排序算法(2)
5.希尔排序(Shell)
void shellsort1(int num[], const int len) { if (len <= 1) return; int i, j, k, dlen, temp; for (dlen = len / 2; dlen > 0; dlen /= 2) //确定步长 { for (i = 0; i < dlen; i++) { for (j = i + dlen; j < len; j += dlen) { temp = num[j]; k = j - dlen; while (k >= 0 && num[k] > temp) { num[k + dlen] = num[k]; k -= dlen; } num[k + dlen] = temp; } } } } void shellsort2(int num[], const int len) { int i, j, dlen, temp; for (dlen = len / 2; dlen > 0; dlen /= 2) { for ( i = dlen; i < len; i++) //从第二序列开始,前面为有序区 { if (num[i] < num[i - dlen]) { temp = num[i]; j = i - dlen; while (j >= 0 && num[j] > temp) { num[j + dlen] = num[j]; j -= dlen; } num[j + dlen] = temp; } } } }
一行两种写法都可以,但是后者比较便于理解和书写。
希尔排序时间复杂度为O(nlogn),不过无需额外开辟空间,属于不稳定排序。
希尔排序的时间性能优于直接插入排序,原因如下:
(1)当文件初态基本有序时,直接插入排序所需的比较和移动次数较多;
(2)当n值较小时,n和n^2的差别也较小,即直接插入排序的最好时间复杂度O(n)和最坏时间复杂度O(n^2)差别不大。
基于以上两点,在希尔排序开始时增量较大,分组比较多,每组的记录数目较少,故各组内直接插入排序较快。后来增量逐渐缩小,分组数目逐渐较少,各组记录数目逐渐增多,但由于文件基本接近有序状态,所以新的排序过程较快。
6.快速排序(QuickSort)
//快速排序 template<typename T> void SWAP(T& a, T&b) { T temp = a; a = b; b = temp; } int Partition(int data[], int left, int right) { if (data == NULL || left < 0 || (right - left) <= 0) { assert(false); } int pivot = data[left]; //轴心元素 while (left < right) { //末尾元素大于轴心元素数值时,不作处理,尾指针往前递进 while (left < right&&data[right] >= pivot) --right; //找到第一个不满足data[right]>pivot的元素,让其与data[left]交换 SWAP(data[left], data[right]); //当前端的元素小于轴心元素时,不作处理,头指针往后递进 while (left < right&&data[left] <= pivot) ++left; //找到第一个不满足data[left]<pivot的元素,让其与data[right]交换 SWAP(data[left], data[right]); } /*由于前面 while(start<end&&arry[end]>=pivot)和while(start<end&&arry[start]<=pivot)的限定, 保证了最后不会出现low>high的情况,因此最后low=high,该位置就是轴心元素在数组中的置。 */ return left; } void Qsort(int data[], int left, int right) { if (left < right) { //此步保证data[pivot]大于左边的元素小于右边的元素,arry[pivot]被正确安排 int pivot = Partition(data, left, right); Qsort(data, left, pivot - 1); Qsort(data, pivot + 1, right); } } void QuickSort(int data[], const int& length) { if (data == NULL || length <= 1) return; Qsort(data, 0, length - 1); }
很好玩的算法,理解确实要花一点时间。
具体原理解释可以参考:http://blog.csdn.net/morewindows/article/details/6684558,结合里面的图解,学习曲线一下就降下来了。
7.二分查找(随机乱入)
//二分查找 int binary_search(int data[], const int length, const int target) { if (data == NULL || length <= 0) return -1; int left = 0, right = length - 1, mid = 0; while (left <= right) { mid = (left + right) >> 1; if (data[mid] == target) { return mid; } else if (data[mid] < target) { right = mid - 1; } else if (data[mid] > target) { left = mid + 1; } } return -1; }
剑指offer中有一个寻找旋转数组中最小值,二分查找的变形,蛮不错的。