七夕今宵看碧霄,牵牛织女渡河桥。今天是七夕节,祝大家节日快乐,我含泪写下了这篇文章,接着上一篇,继续进行排序算法的总结。
4.希尔排序(Shell Sort)
希尔排序(Shell's Sort)是插入排序的一种又称“缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因 D.L.Shell 于 1959 年提出而得名,是第一个突破O(n2)的排序算法
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至 1 时,整个文件恰被分成一组,算法便终止。
4.1 算法描述
先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,具体算法描述:
选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
按增量序列个数k,对序列进行k 趟排序;
每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
在网上发现了一张很有意思的图,可以形象的描述希尔排序的过程:
4.2 动图演示
代码实现:
void shellSort(int a[], int len){int i, j, k, tmp, gap;//gap为步长for (gap = len / 2; gap > 0; gap /= 2)//步长初始化为数组长度的一半,每次遍历后步长减半,{for (i = 0; i < gap; i++)//变量i为每次分组的第一个元素下标{ for (j = i + gap; j < len; j += gap)//对步长为gap的元素进行直插排序,当gap为1时,就是直插排序{ tmp = a[j];//备份a[i]的值k = j - gap;//j初始化为i的前一个元素(与i相差gap长度)while (k >= 0 && a[k] > tmp) {a[k + gap] = a[k];//将在a[i]前且比tmp的值大的元素向后移动一位k -= gap;}a[k + gap] = tmp;}}}}
当要排序的数组长度为10000时,希尔排序和插入排序的效率比较:
5.归并排序(Merge Sort)
归并排序是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
5.1 算法描述
把长度为n的输入序列分成两个长度为n/2的子序列;
对这两个子序列分别采用归并排序;
将两个排序好的子序列合并成一个最终的排序序列。
5.2 动图演示
代码实现:
void merge(int arr[], int low, int mid, int high, int temp[]){int i = low; //左子数组开始位置int j = mid + 1; //右子数组开始位置int t = 0; //临时空间指针while (i <= mid && j <= high){if (arr[i] < arr[j])temp[t++] = arr[i++];elsetemp[t++] = arr[j++];}//将左边剩余元素填充进temp中while (i <= mid)temp[t++] = arr[i++];//将右边子数组剩余部分填充到temp中while (j <= high)temp[t++] = arr[j++];//将融合后的数据拷贝到原来的数据对应的子空间中t = 0;while (low <= high)arr[low++] = temp[t++];}void mergeSort(int arr[], int low, int high, int temp[]){if (low < high) //只有low==high为一个元素的时候不用再细分自分组,融合{int mid = (low + high) / 2;//左子数组融合排序mergeSort(arr, low, mid, temp);//右子数组融合排序mergeSort(arr, mid + 1, high, temp);//已经排序好的子数组有序融合merge(arr, low, mid, high, temp);}}
5.4 算法分析
归并排序是一种稳定的排序方法。和选择排序一样,归并排序的性能不受输入数据的影响,但表现比选择排序好的多,因为始终都是O(nlogn)的时间复杂度。代价是需要额外的内存空间。
6.快速排序(Quick Sort)
快速排序(Quicksort)是对冒泡排序的一种改进。快速排序由C. A. R. Hoare在1960年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
6.1 算法描述
快速排序使用分治法来把一个串(list)分为两个子串(sub-lists)。具体算法描述如下:
从数列中挑出一个元素,称为 “基准”(pivot);
重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
6.2 动图演示
代码实现:
void quickSort(int arr[], int low, int high){ int first = low; int last = high; int key = arr[first]; if(low >= high) return; while(first < last) { while(first < last && arr[last] > key) { last--; } arr[first] = arr[last]; while(first < last && arr[first] < key) { first++; } arr[last] = arr[first]; } arr[first] = key; quickSort(arr, low, first-1); quickSort(arr, first+1, high);}
未完待续,程序员也要过情人节啊。。。