本文将介绍三种排序算法--插入排序,希尔排序,堆排序。本文所有例子都是使用升序
一.插入排序
算法思想
维护一个有序数组,将要插入的数据与有序数组自最后一个元素直到合适位置的数一一比较。
eg: 有序数组:1,3,5,6,7 现在待插入数据为2,那么他将会和7,6,5,3,依次作比较,当带插入数据小于有序数组最后的元素大小,则将该元素后移,直到待插入元素找到合适位置为止。
代码实现
void InsertSort(int* a, int size) { assert(a); for (int i = 0; i < size - 1; ++i) { int end = i; //标识有序数组的最后一位 int tmp = a[end + 1]; while (end >= 0 && tmp < a[end]) { a[end + 1] = a[end]; //待插入数据比有序数组的最后一个数小,将有序数组最后一位向后移位 --end; } a[end + 1] = tmp; } }
总结
1.插入排序可以认为是间距为1的插入算法,说这个是为了待会儿更好的理解希尔排序。
2.插入排序的时间复杂度为O(n^2);
3.插入排序的空间复杂度为O(1);
4.具有稳定性
排序算法的稳定性是指,经过排序算法排序的相同元素的相对位置不会发生改变。
二.希尔排序
算法思想
希尔排序可以认为是插入排序的增强版,因为,他加入了一个预排的过程,即在实现间距为1的插入算法之前,他已经预先将间距为gap(gap一直减减直到>0)的数组排列过了。所以,当进行gap = 1的插入排序之前使得待排序数组已经高度接近有序,使得这次进行的gap = 1的排序的时间复杂度,可以小于O(N^2)(gap = 1的插入排序,最好情况的时间复杂度为O(1),前面的预排过程正是出于这个目的)。
代码实现
//希尔排序 void ShellSort(int* a,size_t size) { assert(a); int gap = size / 2; while (gap > 0) { for (int i = 0; i < size - gap; ++i) { int end = i; int tmp = a[end + gap]; while (end >= 0 && tmp < a[end]) { a[end + gap] = a[end]; end -= gap; } a[end + gap] = tmp; } --gap; } }
总结
1.希尔排序预排的思想和插入排序的思想是一致的,只是,他把原数组分成不同的区间。
2.希尔排序的时间复杂度为O(N^2),空间复杂度为O(1);
3,具有不稳定性
三.堆排序
算法思想
void AdjustDown(int* a, size_t size, int parent) { assert(a); int child = parent * 2 + 1; while (child<size) { if (child+1<size && a[child] < a[child + 1]) ++child; if (a[parent] < a[child]) { swap(a[parent], a[child]); parent = child; child = parent * 2 + 1; } else { break; } } } void HeapSort(int* a,size_t size) { assert(a); //建堆 for (int i = (size - 2) / 2; i >= 0; --i) //从第一个非叶子节点开始调 { AdjustDown(a, size, i); } for (size_t i = 0; i < size; ++i) { swap(a[0], a[size - 1 - i]); AdjustDown(a, size - i - 1, 0); } }
总结
1.时间复杂度为O(N*lgN),空间复杂度为O(1);
2.具有不稳定性
以上就是本人在学习过程中的一些经验总结。当然,本人能力有限,难免会有纰漏,希望大家可以指正。