堆的建立,插入,刪除,排序
阿新 • • 發佈:2018-12-21
堆是一種完全二叉樹,有最小堆和最大堆之分,最小堆是指根節點的值一定小於左子樹和右子樹所有元素的值,最大堆則相反(當你從小到大排序時, 可以選擇最小堆反之,則選擇最大堆) 1.如何建立一個最小堆呢:由於堆是一個完全二叉樹,所以滿足以下關係(我們將元素的順序從0開始排,第i個節點稱之為Ki, 那麼元素就有K0, K1, K2.....),Ki的父節點一定是K(i-1)/2, Ki的左孩子節點一定是Ki*2+1, 右孩子節點一定是Ki*2+2。因此我們可以不用向普通二叉樹那樣,用指標來訪問其左孩子節點和右孩子節點(本次程式中是以指標來訪問的,雖然有點多此一舉,就當鍛鍊一下自己使用指標的能力吧)。然而最重要的問題是,假如我們一開始面臨的是一個堆,我們又如何將其變成一個最小堆呢,那就需要我們進行向上調整(後面會具體講) 2.如何在一個最小堆中插入一個元素呢: 為了不破壞堆已有的結構,在堆尾部插入一個元素後,會破壞堆的結構,如何進行調整呢?可以採用向上調整 3.如何刪除一個元素呢:堆就像是一個佇列,在尾部插入,在頭部刪除,再刪除掉整個樹的根節點後,會破壞堆的結構,為了有效利用堆已有的結構,將堆尾部的元素移到根節點位置,然後進行向下調整(後面會講向下調整) 4.向下調整:將尾部節點移到根節點位置,若該節點數值小於左孩子節點和有孩子節點數值,就無需調整,否則就需將數值最小的孩子節點與根節點互換元素值,然後對數值發生改變的孩子節點進行同樣的調整。(堆的優異性就體現在這裡,對於數值沒有發生改變的孩子節點就無需進行調整,這很可能一下子跳過了一大堆節點,所以二叉樹的時間複雜性與數的高度有關) 5.向上調整:在尾部插入一個元素後,將該元素與其父節點比,若父節點的值大於該孩子節點,則進行互換元素值,對於堆來說,假如有n個節點,則有n / 2個節點是有孩子節點的,則K0至Kn/2都需要進行調整,注意是從Kn/2至K0的順序來依此調整的,從樹的結構來看就是先上的,同時當改變孩子節點元素值是,若該孩子節點同時也有孩子時要進行向下調整,由於堆無非是根,左孩子和右孩子,可以通過遞迴來實現,所以程式碼不是太複雜 關於調整的總結:我們可以發現向上調整和向下調整大致思路是一樣的,都是比較根節點與其孩子節點數值的大小以保證最小堆(或最大堆)的要求,所不同的是向上調整與向上調整的調整方向是相反的,向上調整是在尾部插入元素要進行的調整,向下調整是在刪除根節點並將尾部節點補為根節點後要進行的調整 6.堆的一個應用就是進行排序:由於根節點的元素值是整個樹的最小的,我們可以建立一個堆後,刪除該根節點,將餘下的節點進行向下調整,得到新的堆,重新進行上述步驟。就可以得到從小到大排列的結果了(從大到小隻需建立最大堆即可)。
#include <stdio.h> #include <stdlib.h> #define SIZE 20 typedef int ElemType; typedef struct treenode { ElemType data; struct treenode * left; struct treenode * right; }Node, *pNode; void show(pNode * tree) { if (tree == NULL) return ; int i; for (i = 0; tree[i] != NULL; i++) printf("%-3d", tree[i]->data); printf("\n"); } void getlength(pNode * tree) { if (tree == NULL) printf("get length failure\n");; int i; for (i = 0; tree[i] != NULL; i++) ; printf("tree has %d nodes\n", i); } pNode * CreateTree(ElemType *e, int length) { if (e == NULL || length <= 0 || length > SIZE) return ; pNode *str = (pNode *)malloc(sizeof(pNode) * SIZE); int i, j; for ( i = 0; i < length; i++) { str[i] = (pNode)malloc(sizeof(Node) * 1); if (str[i] == NULL) { for (j = 0; j < i; j++) { free(str[j]); } free(str); printf("堆建立失敗\n"); return NULL; } else str[i]->data = e[i]; } for (i = 0; i < length; i++) { if (2 * i + 1 < length) str[i]->left = str[2 * i + 1]; else str[i]->left = NULL; if (2 * i + 2 < length) str[i]->right = str[2 * i + 2]; else str[i]->right = NULL; } return str; } void ExchangeData(ElemType *a, ElemType * b) { if (a == NULL || b == NULL) return; printf("exchange %d and %d\n", *a, *b); ElemType temp; temp = *a; *a = *b; *b = temp; } void SiftUp(pNode root) { if (root == NULL || (root->left == NULL && root->right == NULL)) return; ElemType e; int c; if (root->left == NULL) { c = 0; e = root->right->data; } else if(root->right == NULL) { c = 1; e = root->left->data; } else { c = root->left->data > root->right->data? 0 : 1; e = root->left->data > root->right->data? root->right->data : root->left->data; } if (root->data > e) { if (c == 0) { ExchangeData(&(root->data), &(root->right->data)); SiftUp(root->right); } else if (c == 1) { ExchangeData(&(root->data), &(root->left->data)); SiftUp(root->left); } } } void SiftDown(pNode root) { if (root == NULL || (root->left == NULL && root->right == NULL)) return; ElemType e; int c; if (root->left == NULL) { c = 0; e = root->right->data; } else if(root->right == NULL) { c = 1; e = root->left->data; } else { c = root->left->data > root->right->data ? 0 : 1; e = root->left->data > root->right->data? root->right->data : root->left->data; } if (root->data > e) { if (c == 0) { ExchangeData(&(root->data), &(root->right->data)); SiftDown(root->right); } else if (c == 1) { ExchangeData(&(root->data), &(root->left->data)); SiftDown(root->left); } } } void Delete(pNode * tree) { if (tree == NULL || tree[0] == NULL) return; int i; for (i = 0; tree[i] != NULL; i++) ; i--; if (i == 0) { free(tree[0]); return; } tree[0]->data = tree[i]->data; free(tree[i]); tree[i] = NULL; if (i % 2 == 1) tree[(i - 1) / 2]->left = NULL; else tree[(i - 1) / 2]->right = NULL; SiftDown(tree[0]); } void Insert(pNode *tree, ElemType e) { if (tree == NULL) { printf("insert failure\n"); return ; } int i, j; for ( i = 0; tree[i] != NULL; i++); if (i > SIZE) { printf("insert failure\n"); return; } printf("i = %d\n", i); tree[i] = (pNode)malloc(sizeof(Node) * 1); if (tree[i] == NULL) { printf("insert failure\n"); return; } tree[i]->data = e; tree[i]->left = NULL; tree[i]->right = NULL; if (i % 2 == 1) tree[(i - 1) / 2]->left = tree[i]; else tree[(i - 1) / 2]->right = tree[i]; for (j = (i + 1) / 2 - 1; j >= 0; j--) SiftUp(tree[j]); } int main() { ElemType res[SIZE]; int i; ElemType e; ElemType a[SIZE] = {2, 5, 6, 23, 45, 55, 67, 32, 56, 11, 1}; /* printf("please input 10 numbers\n"); for (i = 0; i < 10; i++) scanf("%d", a + i); */ pNode * tree = CreateTree(a, 10); if (tree == NULL) { printf("create tree failure\n"); exit(1); } for (i = 10 / 2 - 1; i >= 0; i--) SiftUp(tree[i]); show(tree); for(i = 0; i < 5; i++) { printf("please input the num which you want to insert\n"); scanf("%d", &e); Insert(tree, e); show(tree); } int main() { ElemType res[SIZE]; int i; ElemType e; ElemType a[SIZE] = {2, 5, 6, 23, 45, 55, 67, 32, 56, 11, 1}; /* printf("please input 10 numbers\n"); for (i = 0; i < 10; i++) scanf("%d", a + i); */ pNode * tree = CreateTree(a, 10); if (tree == NULL) { printf("create tree failure\n"); exit(1); } for (i = 10 / 2 - 1; i >= 0; i--) SiftUp(tree[i]); show(tree); for(i = 0; i < 5; i++) { printf("please input the num which you want to insert\n"); scanf("%d", &e); Insert(tree, e); show(tree); }