堆排序-HeapSort
1. 堆排序与快速排序,归并排序一样都是时间复杂度为O(N*logN)的几种常见排序方法。学习堆排序前,先讲解下什么是数据结构中的二叉堆。
二叉堆的定义
二叉堆是完全二叉树或者是近似完全二叉树。
二叉堆满足二个特性:
1)父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。
2)每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。
当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆。当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆
堆分为大顶堆和小顶堆,其中下图(1)中是大顶堆,(2)为小顶堆
2. 堆排序的思想
利用大顶堆(小顶堆)堆顶记录的是最大关键字(最小关键字)这一特性,使得每次从无序中选择最大记录(最小记录)变得简单。
其基本思想为(大顶堆):
1)将初始待排序关键字序列(R1,R2....Rn)构建成大顶堆,此堆为初始的无序区;
2)将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,......Rn-1)和新的有序区(Rn),且满足R[1,2...n-1]<=R[n];
3)由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,......Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2....Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。
下面举例说明(大顶堆):
给定一个整形数组a[]={16,7,3,20,17,8},对其进行堆排序。
1)首先根据该数组元素构建一个完全二叉树,得到
20和16交换后导致16不满足堆的性质,因此需重新调整
这样就得到了初始堆。
此时3位于堆顶不满堆的性质,则需调整继续调整
其实就是每次把堆顶元素和最后没交换过的子节点元素交换,然后将此子节点之前的二叉树重新排序,变成大顶堆。
如果按递增排序,需要用到大顶堆,每次把堆顶(无序堆最大值)放到有序堆前面,重新得到无序区大顶堆;
如果按递减排序,需要用到小顶堆,每次把堆顶(无序堆最小值)放到有序堆前面,重新得到无序区小顶堆;
程序如下(包含递增和递减):
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.IO; 6 7 namespace conHeapSort 8 { 9 class HeapSort 10 { 11 private static Boolean Asce = true;//heap sorted by ascending order 12 private static Boolean Desc = false;//heap sorted by descending order 13 static void Main(string[] args) 14 { 15 List<int> input = new List<int>(); 16 HeapSort exap = new HeapSort(); 17 String str; 18 19 input.Add(0);//start from index one 20 str = Console.ReadLine(); 21 while(str != "exit"){ 22 input.Add(Int32.Parse(str)); 23 str = Console.ReadLine(); 24 } 25 26 exap.SortHeap(input, Desc); 27 for (int i = 1; i < input.Count; i++ ) 28 { 29 Console.WriteLine(input[i].ToString()); 30 } 31 } 32 void SortHeap(List<int> data, Boolean order) 33 { 34 BuildHeap(data, order); 35 36 if (order) 37 { 38 for (int i = data.Count - 1; i >= 1; i--) 39 { 40 Swap(data, 1, i); //exchange between index 1 and index i 41 MaxHeap(data, 1, i - 1); //get max heap 42 } 43 } 44 else 45 { 46 for (int i = data.Count - 1; i >= 1; i--) 47 { 48 Swap(data, 1, i);//exchange between index 1 and index i 49 MinHeap(data, 1, i - 1); //get min heap 50 } 51 } 52 } 53 void BuildHeap(List<int> data, Boolean order) 54 { 55 if (order) //make maximal heap 56 { 57 for (int i = data.Count / 2; i >= 1; i--) 58 { 59 MaxHeap(data, i, data.Count - 1); //initialize 60 } 61 } 62 else //make minimal heap 63 { 64 for (int i = data.Count / 2; i >= 1; i--) 65 { 66 MinHeap(data, i, data.Count - 1);//initialize 67 } 68 } 69 } 70 //get max heap 71 void MaxHeap(List<int> data, int i, int size) 72 { 73 int lchild = 2 * i; 74 int rchild = lchild + 1; 75 int max = i; 76 if (i <= size / 2) 77 { 78 if (lchild <= size && data[lchild] > data[max]) 79 { 80 max = lchild; 81 } 82 if (rchild <= size && data[rchild] > data[max]) 83 { 84 max = rchild; 85 } 86 if (max != i) 87 { 88 Swap(data, i, max); //exchange child and parent node 89 MaxHeap(data, max, size); //continue to adjust 90 } 91 } 92 } 93 //get min heap 94 void MinHeap(List<int> data, int i, int size) 95 { 96 int lchild = 2 * i; 97 int rchild = lchild + 1; 98 int min = i; 99 if (i <= size / 2) 100 { 101 if (lchild <= size && data[lchild] < data[min]) 102 { 103 min = lchild; 104 } 105 if (rchild <= size && data[rchild] < data[min]) 106 { 107 min = rchild; 108 } 109 if (min != i) 110 { 111 Swap(data, i, min);//exchange child and parent node 112 MinHeap(data, min, size); 113 } 114 } 115 } 116 //exchange index1 and index2 in data 117 void Swap(List<int> data, int index1, int index2) 118 { 119 int temp = data[index2]; 120 data[index2] = data[index1]; 121 data[index1] = temp; 122 } 123 } 124 }