堆分為最小堆和最大堆。最小堆指的是任意一個節點都有小於他的做兒子和右兒子。最大堆指的是任意一個節點大於打的左兒子右兒子。
最大堆的操作(堆得主要操作就是上濾和下濾)
插入:先將一個節點插入到堆得最后的位置然后上濾,如果他的父親小於他,就把他父親的值給他,繼續循環,當退出循環的時候就是要插入的節點:
刪除:刪除堆頂元素,然后把最后一個元素拿上來做下濾;如果他的左右兒子中最大的那個大於他就把左右兒子中最大的那個值給堆頂,然后把左右兒子中最大的那個當做父節點繼續循環,當循環退出的時候就是要插入的節點。
如何把一個堆調成最大堆:
先找到最后一個元素的的父節點然后做下濾,把這個小樹調成最大堆然后依次循環。直至循環退出。
typedef struct HNode *Heap; /* 堆的類型定義 */ struct HNode { ElementType *Data; /* 存儲元素的數組 */ int Size; /* 堆中當前元素個數 */ int Capacity; /* 堆的最大容量 */ }; typedef Heap MaxHeap; /* 最大堆 */ typedef Heap MinHeap; /* 最小堆 */ #define MAXDATA 1000 /* 該值應根據具體情況定義為大於堆中所有可能元素的值 */ MaxHeap CreateHeap( int MaxSize ) { /* 創建容量為MaxSize的空的最大堆 */ MaxHeap H = (MaxHeap)malloc(sizeof(struct HNode)); H->Data = (ElementType *)malloc((MaxSize+1)*sizeof(ElementType)); H->Size = 0; H->Capacity = MaxSize; H->Data[0] = MAXDATA; /* 定義"哨兵"為大於堆中所有可能元素的值*/ return H; } bool IsFull( MaxHeap H ) { return (H->Size == H->Capacity); } bool Insert( MaxHeap H, ElementType X ) { /* 將元素X插入最大堆H,其中H->Data[0]已經定義為哨兵 */ int i; if ( IsFull(H) ) { printf("最大堆已滿"); return false; } i = ++H->Size; /* i指向插入后堆中的最后一個元素的位置 */ for ( ; H->Data[i/2] < X; i/=2 ) H->Data[i] = H->Data[i/2]; /* 上濾X */ H->Data[i] = X; /* 將X插入 */ return true; } #define ERROR -1 /* 錯誤標識應根據具體情況定義為堆中不可能出現的元素值 */ bool IsEmpty( MaxHeap H ) { return (H->Size == 0); } ElementType DeleteMax( MaxHeap H ) { /* 從最大堆H中取出鍵值為最大的元素,並刪除一個結點 */ int Parent, Child; ElementType MaxItem, X; if ( IsEmpty(H) ) { printf("最大堆已為空"); return ERROR; } MaxItem = H->Data[1]; /* 取出根結點存放的最大值 */ /* 用最大堆中最后一個元素從根結點開始向上過濾下層結點 */ X = H->Data[H->Size--]; /* 注意當前堆的規模要減小 */ for( Parent=1; Parent*2<=H->Size; Parent=Child ) { Child = Parent * 2; if( (Child!=H->Size) && (H->Data[Child]<H->Data[Child+1]) ) Child++; /* Child指向左右子結點的較大者 */ if( X >= H->Data[Child] ) break; /* 找到了合適位置 */ else /* 下濾X */ H->Data[Parent] = H->Data[Child]; } H->Data[Parent] = X; return MaxItem; } /*----------- 建造最大堆 -----------*/ void PercDown( MaxHeap H, int p ) { /* 下濾:將H中以H->Data[p]為根的子堆調整為最大堆 */ int Parent, Child; ElementType X; X = H->Data[p]; /* 取出根結點存放的值 */ for( Parent=p; Parent*2<=H->Size; Parent=Child ) { Child = Parent * 2; if( (Child!=H->Size) && (H->Data[Child]<H->Data[Child+1]) ) Child++; /* Child指向左右子結點的較大者 */ if( X >= H->Data[Child] ) break; /* 找到了合適位置 */ else /* 下濾X */ H->Data[Parent] = H->Data[Child]; } H->Data[Parent] = X; } void BuildHeap( MaxHeap H ) { /* 調整H->Data[]中的元素,使滿足最大堆的有序性 */ /* 這里假設所有H->Size個元素已經存在H->Data[]中 */ int i; /* 從最后一個結點的父節點開始,到根結點1 */ for( i = H->Size/2; i>0; i-- ) PercDown( H, i ); }
哈弗曼樹(最優二叉樹):
先把節點按權值大小存入最小堆,然后每次從節點中取出兩個最小值並且合並構造哈夫曼樹。
typedef struct TreeNode*Tree struct Tree{ int weight; Tree left; Tree right; }; //假設有這個堆 Tree BuildTree(Heap H){ Heap H; H=BuildMinHeap(H);//假設有這個方法 //做H->size-1次循環 每次取出權值最小的兩個節點進行合並 for(int i=1;i<H->size;i++){ Tree T = (Tree)malloc(sizeof(Tree)); T->left = delete(H); T->right = delete(H); T->weight=T->left->weight+T->right->weight; Insert(H,T); } return delete(H); }
typedef struct TreeNode*Tree struct Tree{ int weight; Tree left; Tree right; }; //假設有這個堆 Tree BuildTree(Heap H){ Heap H; H=BuildMinHeap(H);//假設有這個方法 //做H->size-1次循環 每次取出權值最小的兩個節點進行合並 for(int i=1;i<H->size;i++){ Tree T = (Tree)malloc(sizeof(Tree)); T->left = delete(H); T->right = delete(H); T->weight=T->left->weight+T->right->weight; Insert(H,T); } return delete(H); }
具體的實現過程

