大根堆: 根节点value不小于子节点的value,满足这条性质的二叉树即为大根堆。
小根堆:根节点value不大于子节点的value,满足这条性质的二叉树即为小根堆。
从大根堆的定义可知:在大根堆里要得到最大值只需o(1)的时间。所以很明显,大根堆可以求最大值和维护前k小的数。注意是前k小的数,不是前k大的数,因为当前要插入到堆里的数可以直接和堆里最大值考虑,如果比堆里最大的都还要小,那就那这个值放到堆里,这样就维护了前k小的数。
如果k很大的话,要划分为很多个堆。小根堆和大根堆相反。
堆的操作主要有:
bool isEmpty(int *a); // 判断堆是否为空
bool isFull(int *a); //判断堆是否为满
int top(int *a);// 返回堆顶元素
void pop(int *a);//删除堆顶元素
pop是删除堆顶元素,直接把最后面那个元素的值赋给堆顶,同时元素个数减一,然后是调整堆。
void push(int *a,int);//插入元素
push之前要判断空间是否为满,直接把value放到堆最后,然后是调整堆。
代码:
View Code
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 7 #define maxSize 200008<<2 8 int heap[maxSize]; 9 10 bool isEmpty(int *a); 11 bool isFull(int *a); 12 int top(int *a); 13 void pop(int *a); 14 void push(int *a, int); 15 16 template <typename T> 17 void Swap( T& a, T& b) 18 { 19 T tmp = a; a = b; b = tmp; 20 } 21 22 // 判空 23 bool isEmpty(int *a){ 24 return a[0]<=0? true: false; 25 } 26 // 27 bool isFull(int *a){ 28 return a[0]+1>=maxSize? true: false; 29 } 30 31 int top(int *a){ 32 if(isEmpty(a) ) { 33 puts("since for the heap is empty, the operation is illegel!"); 34 exit(0); 35 } 36 return heap[1]; 37 }; 38 39 // 调整堆,自上往下 40 void adjust( int *a ) { 41 int i = 1; 42 while( i <= a[0] ){ 43 if((i<<1|1) <= a[0] ) // 存在左右子树。 44 { 45 if(a[i<<1] > a[i] && a[i<<1]>a[i<<1|1]){ 46 Swap(a[i<<1], a[i]); i <<= 1; 47 }else if(a[i<<1|1] > a[i]) { 48 Swap(a[i<<1|1], a[i]); 49 i = i<<1|1; 50 }else break; 51 52 }else if( (i<<1) <= a[0] ) { // 只存在左子树 53 if(a[i<<1] > a[i]){ 54 Swap(a[i<<1], a[i]); i <<= 1; 55 }else break; 56 57 }else break; 58 } 59 } 60 61 void pop(int *a){ 62 if(isEmpty(a) ) { 63 fprintf(stderr, "the heap is empty!"); 64 exit(0); 65 } 66 a[1] = a[a[0]-- ]; 67 adjust(a); 68 } 69 70 void outPut(int *a){ 71 puts("***********************************\n"); 72 if(isEmpty(a) ) puts("the heap is empty!"); 73 else 74 { 75 for ( int i=1; i<=a[0]; ++i) 76 printf("%d %d\n", i, a[i]); 77 } 78 puts("***********************************\n"); 79 } 80 81 void push(int *a, int value){ 82 if(isFull(a) ) { 83 fprintf(stderr, "the heap is full!\n"); 84 return ; 85 } 86 a[++a[0] ] = value; 87 int i = a[0]; // 调整堆,自下而上 88 while(i > 1 && a[i] > a[i/2]) { 89 Swap(a[i], a[i/2]); i >>= 1; 90 } 91 }; 92 93 int main() 94 { 95 heap[0] = 0; // 记录元素个数; 96 printf("push five intgers: "); 97 for ( int i=0, tmp; i<5; ++i ) { 98 scanf ("%d", &tmp); 99 push(heap, tmp); // 插入元素 100 } 101 outPut(heap); // 输出堆 102 103 int maxx = top(heap); // 取出堆的最大值 104 printf("the maxx in current tree is %d \n", maxx); 105 106 // 删除堆顶(最大值) 107 printf("delete tha top node.\n"); 108 pop(heap); 109 outPut(heap); 110 111 printf("输入一个元素进行插入操作:"); 112 int tmp; scanf("%d", &tmp); 113 push(heap, tmp); 114 outPut(heap); 115 116 printf("clear the heap.\n"); 117 while(!isEmpty(heap) ) pop(heap); 118 printf("the size of the heap is %d\n", heap[0]); 119 120 system("pause"); 121 };
堆排序: 向大根堆中插入和删除元素的时间都是0(logn),根据这两个操作的时间,可以知道堆排序的时间复杂度为n*log(n). 堆排序思路: 在待排序的元素中建立大根堆,每次都把最大的取出来,这样就完成了排序。未完,待续。。。。