一:直接插入排序
直接插入排序(Insertion Sort)的基本思想是:每次将一个待排序的记录,按其关键字大小插入到前面已经排好序的子序列中的适当位置,直到全部记录插入完成为止。
概念很简单,直接看代码:
#include<iostream> #include<algorithm> using namespace std; void InsertSort(int _arry[]); int main() { int arry[10] = { 2,0,6,9,7,4,1,3,5,4 }; InsertSort(arry); for each (auto & x in arry) { cout << x << " "; } cout << endl; return 0; } void InsertSort(int _arry[])//升序 { int temp; for (int i = 1; i < 10; i++) { if (_arry[i] < _arry[i - 1]) { temp = _arry[i]; int j; for (j = i - 1; j >= 0 && temp < _arry[j]; j--) _arry[j + 1] = _arry[j]; _arry[j + 1] = temp; } } }
快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod)。快速排序可以说是很重要,在笔试也经常拿来判断一个程序员的基础编码水平。关于快速排序的理解,可以参考这篇文章,讲解的很易懂,http://developer.51cto.com/art/201403/430986.htm
下面附上我的代码:
#include<iostream> #include<algorithm> using namespace std; int arry[10]; void QuickSort(int left, int right); int main() { for each (auto x in arry) cin >> x; QuickSort(0, 9);//快排 for each(auto & x in arry) cout << x << " "; cout << endl; return 0; } void QuickSort(int left, int right) { if (!(left<right)) return; int i = left; int j = right; int base = arry[i]; while (i < j) { while (i < j&&arry[j] >= base)//先做右边的 j--; while (i < j&&arry[i] <= base)//然后做左边的,注意顺序 i++; if (i < j) { int temp = arry[i]; arry[i] = arry[j]; arry[j] = temp; } } arry[left] = arry[i]; arry[i] = base; QuickSort(left, i - 1); QuickSort(i + 1, right); }
堆排序的内容有点多,写这篇博客的目的也不是教学初学者,只是做个笔记。其实这四个排序,要写出来是不难的,这四个排序的概念在数据结构课本上都有概念上的讲解,无论是否初次涉及这个算法,我觉得认真看的话,都是可以理解的。当然,如果你是一个好学的孩子,已经提前学到这个算法,而又苦于找不到好的概念讲解和完整的代码参考,我就提供几个链接来弥补这篇博客上的算法概念分析的不足, http://bubkoo.com/2014/01/14/sort-algorithm/heap-sort/,http://www.cnblogs.com/dolphin0520/archive/2011/10/06/2199741.html
#include<iostream> #include<utility> using namespace std; int arry[] = { 2,3,9,5,1,7,6,4,0,8 }; /* 已知arry[s....m]的值除arr[s]之外均满足堆的定义,本函数调整arry[s],使arr[s...m]成一个大顶堆 */ void HeapAdjust(int s, int m) { int rc = arry[s]; for (int i = s * 2; i <= m; i*=2) { if (i < m&&arry[i] < arry[i + 1]) i++; if (rc >= arry[i]) break; arry[s] = arry[i]; s = i; } arry[s] = rc; } /* 升序排序 */ void HeapSort(int & len) { for (int i = len / 2; i >= 0; i--) HeapAdjust(i, len - 1); for (int i = len - 1; i > 0; i--) { swap(arry[0], arry[i]);//将大值依次放在后面 HeapAdjust(0, i - 1); } } int main() { int len = sizeof(arry) / sizeof(int); HeapSort(len); for each(auto x in arry) cout << x << " ";//0 1 2 3 4 5 6 7 8 9 cout << endl; return 0; }
首先考虑下如何将将两个有序数列合并。这个非常简单,只要比较两个数列的第一个数,谁小就先取谁,取了后就在对应数列中删除这个数。然后再进行比较,如果有数列为空,那直接将另一个数列的数据依次取出即可。
而归并排序就是递归的去做上面的事情。
直接看代码。
#include<iostream> #include<algorithm> using namespace std; /* 把有序的arry[start...mid]和有序的arry[mid+1...end]合并 */ void Merge(int* arry, int* assit, int start, int mid, int end) { int i, j; int k = start; for (i = start, j = mid + 1; i <= mid&&j <= end; ) assit[k++] = (arry[i] > arry[j]) ? arry[j++] : arry[i++]; //将剩余的数依次放入assit中 while (i <= mid) assit[k++] = arry[i++]; while (j <= end) assit[k++] = arry[j++]; for (i = start; i <= end; i++) arry[i] = assit[i]; } /* 升序--对arry[start....end]进行归并排序 */ void MergeSort(int* arry, int* assit, int start, int end) { if (start < end) { int mid = (start + end) >> 1; MergeSort(arry, assit, start, mid); MergeSort(arry, assit, mid + 1, end); Merge(arry, assit, start, mid, end); } } int main() { int* arry; int* assit;//辅助 arry = new int[10]{ 2,3,9,5,1,7,6,4,0,8 }; assit = new int[10]; MergeSort(arry, assit, 0, 9); for_each(arry, arry + 10, [](int x) {cout << x << " "; }); cout << endl; delete[]arry; delete[]assit; return 0; }
五:四种排序的分析
下面从算法的稳定性和效率两方面来讲:
1.稳定性
什么叫稳定?百度百科解释为:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,ri=rj,且ri在rj之前,而在排序后的序列中,ri仍在rj之前,则称这种排序算法是稳定的;否则称为不稳定的。
那么在上述算法中,哪个是稳定的?哪个是不稳定的?
直接插入排序-->稳定
快速排序-->不稳定
堆排序-->不稳定
归并排序-->稳定
2.效率
排序方法 | 平均时间 | 最坏情况 | 辅助存储 |
直接插入 | O(n*n) | O(n*n) | O(1) |
快速排序 | O(n*logn) | O(n*n) | O(logn) |
堆排序 | O(n*logn) | O(n*logn) | O(1) |
归并排序 | O(n*logn) | O(n*logn) | O(n) |