堆及堆排序
堆是一种特殊的数据结构,它是完全二叉树,可以用一维数组来保存,因为二叉树的性质,所以根据数组下标就可以确定位置,下面代码是关于堆的实现, 删除的过程其实就是将堆的根节点取出的过程, 这时的顺序就是有序的, 如果是最小堆,那么就是从小到大排序,反之,就是从大到小
1 #include <stdio.h> 2 3 int h[101]; 4 int n; 5 //交换函数 6 void swap(int a, int b) 7 { 8 int t = h[a]; 9 h[a] = h[b]; 10 h[b] = t; 11 } 12 //向下调整函数, 调整每个点都满足最小堆的特性 13 void siftDown(int i) 14 { 15 int flag = 0;//用来标记是否需要向下调整 16 int t; 17 while(i * 2 <= n && flag == 0)//如果有孩子并且需要继续调整 18 { 19 if(h[i * 2] < h[i])//左儿子不满足最小堆的关系,交换 20 { 21 t = i * 2; 22 } 23 else 24 t = i; 25 if(i * 2 + 1 <= n)//再比较右儿子 26 { 27 if(h[t] > h[i * 2 + 1]) 28 { 29 t = i * 2 + 1; 30 } 31 } 32 if(t != i)//如果最小的节点不是自己,说明子节点中有比父节点小的 33 { 34 swap(i, t); 35 i = t; 36 } 37 else 38 flag = 1; 39 } 40 } 41 //删除堆的根节点的函数, 42 int deleted() 43 { 44 int t = h[1]; 45 h[1] = h[n];//将最后一个移上来, 继续调整,保持最小堆 46 n--; 47 siftDown(1); 48 return t; 49 } 50 //创建堆 51 void create() 52 { 53 for(int i = n / 2; i >= 1; i--) 54 siftDown(i); 55 } 56 57 int main() 58 { 59 scanf("%d", &n); 60 int num = n; 61 for(int i = 1; i <= n; i++) 62 { 63 scanf("%d", &h[i]); 64 } 65 create(); 66 //从小到大输出 67 for(int i = 1; i <= num; i++) 68 printf("%d ", deleted()); 69 return 0; 70 }
上面是一次性的输入数据,当然也可以添加数据,添加数据的时候,只要把数据添加到最后,然后调整顺序使它满足最小堆就行了
代码很简单
1 //向上调整函数 2 void siftUp(int i) 3 { 4 int flag = 0; 5 while(i != 1 && flag == 0) 6 { 7 if(h[i] < h[i / 2]) 8 swap(i, i / 2); 9 else 10 flag = 1; 11 i = i / 2; 12 } 13 }
下面是堆排序的实现,先构造最小堆,然后再堆排序,基本代码类似,就增加了一个堆排序函数,这个函数是将第一个元素,也就是根节点与最后一个交换,那么最后的这个一定是最小的,然后n(总数)--, 这是在调整第一个的位置,使它满足最小堆,一次调整到只剩一个元素就可以了,堆排序的时间复杂度和快排和归并一样都是nlog(n), 也是比较快的排序,下面是堆排序的代码
1 #include <stdio.h> 2 3 int h[101]; 4 int n; 5 //交换函数 6 void swap(int a, int b) 7 { 8 int t = h[a]; 9 h[a] = h[b]; 10 h[b] = t; 11 } 12 //向下调整函数, 调整每个点都满足最小堆的特性 13 void siftDown(int i) 14 { 15 int flag = 0;//用来标记是否需要向下调整 16 int t; 17 while(i * 2 <= n && flag == 0)//如果有孩子并且需要继续调整 18 { 19 if(h[i * 2] < h[i])//左儿子不满足最小堆的关系,交换 20 { 21 t = i * 2; 22 } 23 else 24 t = i; 25 if(i * 2 + 1 <= n)//再比较右儿子 26 { 27 if(h[t] > h[i * 2 + 1]) 28 { 29 t = i * 2 + 1; 30 } 31 } 32 if(t != i)//如果最小的节点不是自己,说明子节点中有比父节点小的 33 { 34 swap(i, t); 35 i = t; 36 } 37 else 38 flag = 1; 39 } 40 } 41 42 //创建堆 43 void create() 44 { 45 for(int i = n / 2; i >= 1; i--) 46 siftDown(i); 47 } 48 //堆排序 49 void heapSort() 50 { 51 //依次将第一个与最后一个交换,所以最后一个为最小的 52 while(n > 1) 53 { 54 swap(1, n); 55 n--;//总数减少 56 siftDown(1); 57 } 58 } 59 60 int main() 61 { 62 scanf("%d", &n); 63 int num; 64 for(int i = 1; i <= n; i++) 65 { 66 scanf("%d", &h[i]); 67 } 68 num = n; 69 create(); 70 heapSort(); 71 for(int i = 1; i <= num; i++) 72 printf("%d ", h[i]); 73 printf("\n"); 74 return 0; 75 }
附(堆的另一种版本):
#include <cstdio> #include <cstring> #include <cstdio> #include <cstdlib> using namespace std; struct HeapStruct{ int *Element; int Size; int Capacity; }; bool isEmpty(HeapStruct *H)//判断队列是否为空 { return (H->Size == 0); } void Insert(HeapStruct *H, int item)//插入函数,将item这个数插入到数列中 { int i; H->Size++; for (i = H->Size; i > 0; i /= 2) { if (H->Element[i / 2] >= item) break; H->Element[i] = H->Element[i / 2]; } H->Element[i] = item; } int Delete(HeapStruct *H)//删除堆顶元素 { if (isEmpty(H)) { printf("Heap is empty!\n"); return 0; } int child, parent; int tmp = H->Element[1]; int t = H->Element[H->Size--]; for (parent = 1; parent * 2 <= H->Size; parent = child) { child = parent * 2; if (child != H->Size && H->Element[child] < H->Element[child + 1]) child++; if (t >= H->Element[child]) break; H->Element[parent] = H->Element[child]; } H->Element[parent] = t; return tmp; } HeapStruct* Build(HeapStruct *H)//当所有的数据都输入到数组的时候,这时候数组还不是堆,要将他调整成堆 { int i, parent, child, tmp; for (i = H->Size / 2; i > 0; i--) { tmp = H->Element[i]; for (parent = i; parent * 2 <= H->Size; parent = child) { child = parent * 2; if (child != H->Size && H->Element[child] < H->Element[child + 1]) child++; if (tmp >= H->Element[child]) break; H->Element[parent] = H->Element[child]; } H->Element[parent] = tmp; } return H; } HeapStruct* Create(int MaxSize)//初始化创建一个大小为MaxSize的堆 { HeapStruct *H = (HeapStruct*) malloc(sizeof(HeapStruct)); H->Size = 0; H->Element = (int *)malloc(sizeof(int) * (MaxSize + 1)); H->Capacity = MaxSize; return H; } int Top(HeapStruct *H)//获得堆顶元素 { if (isEmpty(H)) { printf("Queue is null\n"); return 0; } return H->Element[1]; } int main() { int MaxSize; int n; printf("Input MaxSize:\n"); scanf("%d", &MaxSize); printf("Input n\n"); scanf("%d", &n); HeapStruct *H = Create(MaxSize); H->Size = n; for (int i = 1; i <= n; i++) scanf("%d", &H->Element[i]); H = Build(H); printf("After build heap:\n"); for (int i = 1; i <= n; i++) printf("%d ", H->Element[i]); puts(""); int t; printf("Input you want insert number:\n"); scanf("%d", &t); Insert(H, t); printf("After inserted:\n"); for (int i = 1; i <= H->Size; i++) printf("%d ", H->Element[i]); puts(""); printf("After delete the first one: "); Delete(H); for (int i = 1; i <= H->Size; i++) printf("%d ", H->Element[i]); puts(""); printf("Top is: %d\n", Top(H)); return 0; }