直接插入排序是一种简单的插入排序法,其基本思想是:
把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列 。
实际中我们玩扑克牌时,就用了插入排序的思想:
就是,第一次摸牌我们把它放在第一张,第二次就和第一张比较,比它大就放在他的后面,否则就放在他的前面,摸第三张的时候先和后面大的一张牌开始比较,依次向前。
总结来说就是:
当插入第i(i>=1)个元素时,前面的array[0],array[1],…,array[i-1]已经排好序,此时用array[i]的排序码与array[i-1],array[i-2],…的排序码顺序进行比较,找到插入位置即将array[i]插入,原来位置上的元素顺序后移
直接插入排序的特性总结:
下面我们对直接插入排序进行代码的实现
插入排序很简单
我们将第二个元素开始向后遍历,i=1,令end=i-1,并且保存a[i]的值
当a[end]大于此前i下标的元素的值时,将其调整,将end位置的值移动到end后面一个位置,同时end–,如果是小于的,那就直接跳出循环,就代表了前面的所有值都是升序的
void insertsort(int* a, int n)
{
for (int i = 1; i < n; i++)
{
int end = i - 1;
int temp = a[i];
while (end >= 0)
{
if (a[end] > temp)
{
a[end + 1] = a[end];
end--;
}
else
{
break;
}
}
a[end + 1] = temp;
}
}
希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有记录分成个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。
下面为代码实现:
我们开始令gap为n的三分之一+1,加一是因为gap不能等于0,一般情况下gap是数组长度的三分之一是比较合适的
后面的逻辑就和插入排序差不多了
后面的for循环时各个分组的数字同时进行排序
void shellsort(int* a, int n)
{
int gap = n;
while (gap > 1)
{
gap = gap / 3 + 1;
for (int i = 0; i < n - gap; i++)
{
int end = i;
int temp = a[end + gap];
while (end >= 0)
{
if (a[end] > a[temp])
{
a[end + gap] = a[end];
end -= gap;
}
else
{
break;
}
}
a[end + gap] = temp;
}
}
}
希尔排序的特性总结:
选择排序的思想就是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。
代码实现:
第一次找出最大值最小值的下标,然后放在首尾
交换值,然后begin和end分别被前进和后退
void SelectSort(int* a, int n)
{
assert(a);
int begin = 0, end = n - 1;
while (begin < end)
{
int min = begin, max = begin;
for (int i = begin; i <= end; i++)
{
if (a[i] >= a[max])
max = i;
if (a[i] < a[min])
min = i;
}
Swap(&a[begin], &a[min]);
//如果最大的位置在begin位置
//说明min是和最大的交换位置
//这个时候max的位置就发生了变换
//max变到了min的位置
//所以要更新max的位置
if (begin == max)
max = min;
Swap(&a[end], &a[max]);
++begin;
--end;
}
快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:
任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止
总结下来就是:
我们将小于中间位置的值的放在左边,大于的放在右边,然后再对左边进行一样的划分,右边也是,用递归实现即可
在实现快排前我们先定义一个找中间下标的函数:
也就是常说的三数取中,有利于更好更快得完成快排
int getmidindex(int* a, int left, int right)
{
int midi = (left + right) / 2;
if (a[left] < a[midi])
{
if (a[midi] < a[right])
{
return midi;
}
else if (a[left] < a[right])
{
return right;
}
else
return left;
}
else//a[left] >=a[midi]
{
if (a[midi] > a[right])
{
return midi;
}
else if (a[left] > a[right])
{
return right;
}
else
return left;
}
}
快速排序一共有三种方法:
int partsort1(int* a, int left, int right)
{
int midi = getmidindex(a, left, right);
swap(&a[left], &a[midi]);
int keyi = left;
while (left < right)
{
while (left < right && a[right] >= a[keyi])
{
right--;
}
while (left < right && a[left] <= a[keyi])
{
left++;
}
swap(&a[left], &a[right]);
}
swap(&a[keyi], &a[left]);
return left;
}
void quicksort(int* a, int begin, int end)
{
if (begin >= end)
return;
int midi = partsort1(a, begin, end);
quicksort(a, begin, midi - 1);
quicksort(a, midi + 1, end);
}
代码实现如下:
int partsort2(int* a, int left, int right)
{
int midi = getmidindex(a, left, right);
swap(&a[left], &a[midi]);
int hole = left;
int key = a[left];
while (left < right)
{
while (left < right && a[right] >= key)
{
right--;
}
a[hole] = a[right];
hole = right;
while (left < right && a[left] <= key)
{
left++;
}
a[hole] = a[left];
hole = left;
}
a[hole] = key;
return hole;
}
void quicksort(int* a, int begin, int end)
{
if (begin >= end)
return;
int midi = partsort1(a, begin, end);
quicksort(a, begin, midi - 1);
quicksort(a, midi + 1, end);
}
代码实现:
int partsort3(int* a, int left, int right)
{
int midi = getmidindex(a, left, right);
swap(&a[left], &a[midi]);
int prev = left;
int cur = left + 1;
int keyi = left;
while (cur <= right)
{
if (a[keyi] > a[cur] && ++prev != cur)
{
swap(&a[prev] ,&a[cur]);
}
cur++;
}
swap(&a[prev] ,&a[keyi]);
keyi = prev;
return keyi;
}
void quicksort(int* a, int begin, int end)
{
if (begin >= end)
return;
int midi = partsort1(a, begin, end);
quicksort(a, begin, midi - 1);
quicksort(a, midi + 1, end);
}
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide andConquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
他的大概步骤如下:
归并排序的递归很简单:
就是将区间逐一划分
并且得开辟一块新的空间,最后将temp直接全部memcpy到目标空间a中
void _mergesort(int* a, int begin, int end, int* temp)
{
if (begin >= end)
return;
int midi = (begin + end) / 2;
_mergesort(a,begin, midi,temp);
_mergesort(a,midi + 1, end,temp);
int begin1 = begin;
int begin2 = midi + 1;
int end1 = midi;
int end2 = end;
int i = begin;
while (begin1 <= end1 && begin2 <= end2)
{
if (a[begin1] < a[begin2])
{
temp[i++] = a[begin1++];
}
else
{
temp[i++] = a[begin2++];
}
}
while (begin1 <= end1)
{
temp[i++] = a[begin1++];
}
while (begin2 <= end2)
{
temp[i++] = a[begin2++];
}
memcpy(a + begin, temp + begin, sizeof(int) * (end - begin + 1));
}
void mergesort(int* a, int n)
{
int* temp = (int*)malloc(sizeof(int)*n);
_mergesort(a, 0, n-1, temp);
free(temp);
}
非递归就有点难了:
void mergesortnonr(int* a, int n)
{
int* temp =(int*)malloc(sizeof(int) * n);
if (temp == NULL)
{
perror("malloc");
}
int gap = 1;
while (gap < n)
{
int j = 0;
for (int i = 0; i < n; i += 2*gap)
{
int begin1 = i;
int begin2 = i + gap;
int end1 = i + gap-1;
int end2 = i + 2 * gap - 1;
if (end1 >= n || begin2 >= n)
{
break;
}
if (end2 >= n)
{
end2 = n - 1;//修正
}
while (begin1 <= end1 && begin2 <= end2)
{
if (a[begin1] <= a[begin2])
{
temp[j++] = a[begin1++];
}
else
{
temp[j++] = a[begin2++];
}
}
while (begin1 <= end1)
{
temp[j++] = a[begin1++];
}
while (begin2 <= end2)
{
temp[j++] = a[begin2++];
}
//每归并完一组就拷贝一组
memcpy(a + i, temp + i, sizeof(int) * (end2 - i + 1));
}
gap *= 2;
}
free(temp);
}
归并排序的特性总结:
思想:计数排序又称为鸽巢原理,是对哈希直接定址法的变形应用。 操作步骤:
void countsort(int* a, int n)
{
int i = 0;
int j = 0;
int max = a[0];
int min = a[0];
for (i = 0; i < n; i++)
{
if (a[i] > max)
{
max = a[i];
}
if (a[i] < min)
{
min = a[i];
}
}
int range = max - min + 1;
int* count = (int*)malloc(sizeof(int) * n);
memset(count, 0, sizeof(int) * range);
for (i = 0; i < n; i++)
{
count[a[i] - min]++;
}
int k = 0;
for (j = 0; j < range; j++)
{
while (count[j]--)
{
a[k++] = j + min;
}
}
}
计数排序的特性总结: