排序之选择排序(简单选择排序、堆排序)
选择排序
阐述:
每一趟排序选择出待排集合中最小的值(假设从大到小排序)放置到已排序集合之后,直到待排集合的元素都排完。
复杂度:
遍历待排集合时间复杂度O(N),确定待排集合的首位置时间复杂度O(N),所以选排的时间复杂度是O(N*N)
稳定性:
选排在将最小值置换到已排集合之后时会把相同元素的相对位置打乱,顺便说一下,一般跨度大的置换(非相邻置换)都容易打乱相对位置,所以选排是不稳定的。
效果图:
堆排序:
阐述:
利用堆结构得到最大值(假设是大根堆,大根堆的根元素就是最大值),依次放置在已排集合的首位(假设从小到大排序),直到堆的元素为1。
算法描述:
1.创建堆
2.将当前堆的根元素与当前堆的末尾元素置换
3.重新调整新堆(将上一个堆的末尾元素排除掉),回到第2步,直到堆元素为1.
时间复杂度:
调整堆结构时间复杂度是O(lgN),确定堆的数据长度时间复杂度是O(N)(因为新堆比起旧堆会减少一个元素,也就是待排集合的大小在递减),所以堆排序的时间复杂度是O(N*lgN)。另外创建堆的时间复杂度O(N*lgN),创建堆也是一个耗时的工程。
稳定性:
在堆根和堆尾元素交换是,很可能改变相同元素的相对位置,所以堆排序是不稳定的。
效果图之创建堆:
可以看到,创建堆是从后往前进行的,遍历这些元素时,会查看以该元素为堆根时,是不是满足大根堆的性质,不满足就会调整元素位置。并且调整堆的过程是递归的过程。
效果图之堆排序:
可以看到堆排序的过程就是,堆根与堆尾交换元素,重新调整堆结构,如此往复,直到堆元素个数为1.
代码(c#):
/// <summary> /// 堆排序入口 /// </summary> public static void DoHeapSort_Enterance() { List<int> heap = new List<int>() { 1, 3, 7, 5, 2, 8, 4, 6, 10, 9 }; //创建堆 DoHeapSort_CreateHeap(heap); //LogWrite.LogPlain("堆创建完毕"); //堆排序 for (int i = heap.Count - 1; i > -1; i--) { //交换堆根元素和当前元素的值 Swap(heap, i, 0); //LogWrite.LogPlain(DisplayList(heap, new List<int> { i, 0 }, '[', ']')); //调整堆 //LogWrite.LogPlain(DisplayList(heap, new List<int> { 0, i - 1 }, '<', '>')); DoHeapSort_AjustHeap(0, heap, i - 1); //LogWrite.LogPlain(DisplayList(heap, new List<int> { 0, i - 1 }, '<', '>')); } } /// <summary> /// 调整堆,默认调整为大根堆 /// </summary> /// <param name="indexStartNode">需要调整的的起始索引</param> public static void DoHeapSort_AjustHeap(int indexStartNode, List<int> heap, int indexEndNode) { //显示 //LogWrite.LogPlain(DisplayList(heap, new List<int> { indexStartNode },'<','>')); int indexLeftChild = (indexStartNode + 1) * 2 - 1; //左子节点 int indexMaxChild = indexLeftChild; //记录最大子节点索引 if (indexLeftChild > indexEndNode) return; //查看右子节点 int indexRightChild = (indexStartNode + 1) * 2; if (indexRightChild <= indexEndNode && heap[indexRightChild] > heap[indexLeftChild]) { indexMaxChild = indexRightChild; } //跟父节点交换 if (heap[indexMaxChild] > heap[indexStartNode]) { Swap(heap, indexMaxChild, indexStartNode); //显示 //LogWrite.LogPlain(DisplayList(heap, new List<int> { indexMaxChild, indexStartNode })); //交换之后重新调整堆 DoHeapSort_AjustHeap(indexMaxChild, heap, indexEndNode); } } /// <summary> /// 创建堆(默认是大根堆) /// </summary> /// <returns></returns> public static void DoHeapSort_CreateHeap(List<int> heap) { for (int i = heap.Count - 1; i > -1; i--) { DoHeapSort_AjustHeap(i, heap, heap.Count - 1); } System.Threading.Thread.Sleep(2 * 1000); } /// <summary> /// 交换数组两个元素的值 /// </summary> /// <param name="listNum"></param> /// <param name="indexSource"></param> /// <param name="indexTarget"></param> public static void Swap(List<int> listNum, int index1, int index2) { int swapTemp = listNum[index1]; listNum[index1] = listNum[index2]; listNum[index2] = swapTemp; }