基本思想:把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列 。
实际中我们玩扑克牌时,就用了插入排序的思想:
当插入第i(i>=1)个元素时,前面的array[0],array[1],…,array[i-1]已经排好序,此时用array[i]的排序码与array[i-1],array[i-2],…的排序码顺序进行比较,找到插入位置即将array[i]插入,原来位置上的元素顺序后移
代码如下:
// 插入排序
void InsertSort(int* a, int n)
{
for (int i = 0;i < n-1;i++)
{
int end = i;
int tmp = a[end + 1];
while (end >= 0)
{
if (tmp < a[end])
{
a[end + 1] = a[end];
--end;
}
else
{
break;
}
}
a[end + 1] = tmp;
}
}
直接插入排序的特性总结:
希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有记录分成个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,取,重复上述分组和排序的工作。当到达=1时,所有记录在统一组内排好序。
代码实现如下:
// 希尔排序
void ShellSort(int* a, int n)
{
int gap = 3;
while (gap > 1)
{
gap = gap / 3 + 1;
for (int i = 0;i < n - gap;i++)
{
int end = i;
int tmp = a[end + gap];
while (end >= 0)
{
if (tmp < a[end])
{
a[end + gap] = a[end];
end -= gap;
}
else
{
break;
}
}
a[end + gap] = tmp;
}
}
}
希尔排序的特性总结:
基本思想:每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。
在元素集合array[i]–array[n-1]中选择关键码最大(小)的数据元素若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中的最后一个(第一个)元素交换在剩余的array[i]–array[n-2](array[i+1]–array[n-1])集合中,重复上述步骤,直到集合剩余1个元素
代码如下:
void SelectSort(int* a, int n)
{
int start = 0;
int end = n - 1;
while (start < end)
{
int max = start;
int min = start;
for (int i = start;i <= end;i++)
{
if (a[max] < a[i])
{
max = i;
}
if (a[min] > a[i])
{
min = i;
}
}
Swap(&a[start], &a[min]);
if (start == max)//防止特殊情况
{
max = min;
}
Swap(&a[end], &a[max]);
start++;
end--;
}
}
堆排序详解(点我)
基本思想:所谓交换,就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置,交换排序的特点是:将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动。
void BubbleSort(int* a, int n)
{
for (int i = 0;i < n-1;i++)
{
int flag = 0;
for (int j = 0;j < n - 1 - i;j++)
{
if (a[j] > a[j + 1])
{
flag = 1;
Swap(&a[j], &a[j + 1]);//交换
}
}
if (!flag)//优化
{
break;
}
}
}
冒泡排序的特性总结:
快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。
PartSort动图如下:
代码如下:
int PartSort1(int* a, int left, int right)
{
int key = left;
while (left < right)
{
while (left < right && a[right] >= a[key])
{
right--;
}
while (left < right && a[left] <= a[key])
{
left++;
}
Swap(&a[left], &a[right]);
}
Swap(&a[left], &a[key]);
return left;
}
//递归
void QuickSort(int* a, int left, int right)
{
if (left >= right)
{
return;
}
int key = PartSort1(a, left, right);
QuickSort(a, left, key - 1);
QuickSort(a, key+1, right);
}
1.空间复杂度 0(lgn)
2.时间复杂度0(n*lgn)
主要通过数据结构栈来模拟实现类似于二叉树的前序遍历
如果有同学对C语言实现栈不熟悉可以点一下链接:C源实现数据结构栈
具体代码如下:
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top; // 栈顶
int capacity; // 容量
}Stack;
// 初始化栈
void StackInit(Stack* ps)
{
STDataType* new = (STDataType*)malloc(sizeof(STDataType) * 4);
if (new == NULL)
{
exit(-1);
}
else
{
ps->a = new;
ps->top = 0;
ps->capacity = 4;
}
}
// 入栈
void StackPush(Stack* ps, STDataType data)
{
assert(ps);
if (ps->top == ps->capacity)
{
STDataType* new = (STDataType*)realloc(ps->a, sizeof(STDataType) * (ps->capacity) * 2);
if (new == NULL)
{
exit(-1);
}
else
{
ps->a = new;
ps->capacity *= 2;
}
}
ps->a[ps->top] = data;
ps->top++;
}
// 出栈
void StackPop(Stack* ps)
{
assert(ps);
if (ps->top > 0)
(ps->top)--;
}
// 获取栈顶元素
STDataType StackTop(Stack* ps)
{
assert(ps);
assert(ps->top > 0);
return ps->a[ps->top - 1];
}
// 获取栈中有效元素个数
int StackSize(Stack* ps)
{
assert(ps);
return ps->top;
}
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* ps)
{
assert(ps);
return ps->top == 0;
}
// 销毁栈
void StackDestroy(Stack* ps)
{
free(ps->a);
free(ps);
}
void StackPrint(Stack* ps)
{
assert(ps);
int n = ps->top;
for (int i = 0;i < n;i++)
{
printf("%d ", ps->a[i]);
}
}
int QuickPart2(int* a, int left, int right)//挖坑法
{
int start = left;
int end = right;
int key = a[left];
int pit = left;
while (start < end)
{
while(start < end && a[end] >= key)
{
end--;
}
//swap(&a[end], &a[pit]);
a[pit] = a[end];
pit = end;
while (start < end && a[start] <= key)
{
start++;
}
//swap(&a[start], &a[pit]);
a[pit] = a[start];
pit = start;
}
a[pit] = key;
return pit;
}
//非递归快速排序
void QuickSortNonR(int* a, int left, int right)
{
if (a == NULL)
{
return;
}
assert(right > 1);
Stack P;
StackInit(&P);
//先向栈里入数据
StackPush(&P, left);
StackPush(&P, right);
while (!StackEmpty(&P))//重复操作直至栈为空
{
int end = StackTop(&P);
StackPop(&P);
int start = StackTop(&P);
StackPop(&P);
int mid = QuickPart2(a, start, end);//使其中一个元素有序
int start1 = start;
int end1 = mid - 1;
int start2 = mid + 1;
int end2 = end;
if (end1 > start1)
{
StackPush(&P, start1);
StackPush(&P, end1);
}
if (start2<end2)
{
StackPush(&P, start2);
StackPush(&P, end2);
}
}
for (int i = 0;i <= right;i++)//打印
{
printf("%d ", a[i]);
}
}
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide andConquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
动图演示如下:
代码如下:
递归版本
void _MergeSort(int* a,int* ret, int left,int right)
{
if (left >= right)
{
return;
}
int start = left;
int end = right;
int indx = start;
int mid = start + (end - start) / 2;
int start1 = start;
int end1 = mid;
int start2 = mid + 1;
int end2 = end;
//递归将其左右区间变有序
_MergeSort(a,ret,start1,end1);
_MergeSort(a,ret,start2,end2);
while (start1 <= end1 && start2 <= end2)
{
if (a[start1] < a[start2])
{
ret[indx++] = a[start1];
start1++;
}
else
{
ret[indx++] = a[start2];
start2++;
}
}
while (start1 <= end1)
{
ret[indx++] = a[start1];
start1++;
}
while (start2 <= end2)
{
ret[indx++] = a[start2];
start2++;
}
//排好的序拷贝到原数组中
memcpy(a+left, ret+left, sizeof(int) * (right - left + 1));
}
// 归并排序递归实现
void MergeSort(int* a, int n)
{
int* tmp = (int*)malloc(sizeof(int) * n);
_MergeSort(a, tmp, 0, n - 1);
}
void MergeSortNonR(int* a, int n)
{
int* ret = (int*)malloc(sizeof(int) * (n));
int gap = 1;
while (gap < n)
{
for (int i = 0;i < n;i += 2*gap)
{
int indx = i;
int start1 = i;
int end1 = i + gap - 1;
int start2 = i + gap;
int end2 = i + gap * 2 - 1;
if (end1 >= n)
{
end1 = n - 1;
}
if (start2 >= n)//保证start2!=end2 防止重复归并
{
start2 = n+1;
end2 = n - 1;
}
if (start2<n && end2 >= n)
{
end2 = n - 1;
}
while (start1 <= end1 && start2 <= end2)
{
if (a[start1] < a[start2])
{
ret[indx++] = a[start1];
start1++;
}
else
{
ret[indx++] = a[start2];
start2++;
}
}
while (start1 <= end1)
{
ret[indx++] = a[start1];
start1++;
}
while (start2 <= end2)
{
ret[indx++] = a[start2];
start2++;
}
}
memcpy(a, ret, sizeof(int) * n);
gap *= 2;
}
以上就是常见排序的总结,如有错误希望指出。