堆的建立,插入,刪除,排序

2021-09-01 00:10:03 字數 3334 閱讀 3563

堆是一種完全二叉樹,有最小堆和最大堆之分,最小堆是指根節點的值一定小於左子樹和右子樹所有元素的值,最大堆則相反(當你從小到大排序時, 可以選擇最小堆反之,則選擇最大堆)

1.如何建立乙個最小堆呢:由於堆是乙個完全二叉樹,所以滿足以下關係(我們將元素的順序從0開始排,第i個節點稱之為ki, 那麼元素就有k0, k1, k2…),ki的父節點一定是k(i-1)/2, ki的左孩子節點一定是ki2+1, 右孩子節點一定是ki2+2。因此我們可以不用向普通二叉樹那樣,用指標來訪問其左孩子節點和右孩子節點(本次程式中是以指標來訪問的,雖然有點多此一舉,就當鍛鍊一下自己使用指標的能力吧)。然而最重要的問題是,假如我們一開始面臨的是乙個堆,我們又如何將其變成乙個最小堆呢,那就需要我們進行向上調整(後面會具體講)

2.如何在乙個最小堆中插入乙個元素呢: 為了不破壞堆已有的結構,在堆尾部插入乙個元素後,會破壞堆的結構,如何進行調整呢?可以採用向上調整

3.如何刪除乙個元素呢:堆就像是乙個佇列,在尾部插入,在頭部刪除,再刪除掉整個樹的根節點後,會破壞堆的結構,為了有效利用堆已有的結構,將堆尾部的元素移到根節點位置,然後進行向下調整(後面會講向下調整)

4.向下調整:將尾部節點移到根節點位置,若該節點數值小於左孩子節點和有孩子節點數值,就無需調整,否則就需將數值最小的孩子節點與根節點互換元素值,然後對數值發生改變的孩子節點進行同樣的調整。(堆的優異性就體現在這裡,對於數值沒有發生改變的孩子節點就無需進行調整,這很可能一下子跳過了一大堆節點,所以二叉樹的時間複雜性與數的高度有關)

5.向上調整:在尾部插入乙個元素後,將該元素與其父節點比,若父節點的值大於該孩子節點,則進行互換元素值,對於堆來說,假如有n個節點,則有n / 2個節點是有孩子節點的,則k0至kn/2都需要進行調整,注意是從kn/2至k0的順序來依此調整的,從樹的結構來看就是先上的,同時當改變孩子節點元素值是,若該孩子節點同時也有孩子時要進行向下調整,由於堆無非是根,左孩子和右孩子,可以通過遞迴來實現,所以**不是太複雜

關於調整的總結:我們可以發現向上調整和向下調整大致思路是一樣的,都是比較根節點與其孩子節點數值的大小以保證最小堆(或最大堆)的要求,所不同的是向上調整與向上調整的調整方向是相反的,向上調整是在尾部插入元素要進行的調整,向下調整是在刪除根節點並將尾部節點補為根節點後要進行的調整

6.堆的乙個應用就是進行排序:由於根節點的元素值是整個樹的最小的,我們可以建立乙個堆後,刪除該根節點,將餘下的節點進行向下調整,得到新的堆,重新進行上述步驟。就可以得到從小到大排列的結果了(從大到小只需建立最大堆即可)。

看到網上經典的堆排序**,只有不到一百行,不得不反思一下自己的程式為何這麼冗長:

(1).堆本可以對映到乙個一維陣列,無需像普通二叉樹那樣採用指標來訪問根節點,本程式既用指標又用陣列(用陣列是完全二叉樹滿足的關係(1中所說)對程式設計很有用)

(2).向上調整和向下調整其本質差不多,可以合併,這裡寫成兩個介面是為了插入,刪除時呼叫方便,如果只是排序,則可不必這麼寫

(3).加了一些測試**時用到的藉口(誰讓自己菜呢,寫程式總有bug),如show(),getlength()等;

(4).不得不感嘆經典就是經典,程式設計方面還得加油啊

#include #include #define size 20

typedef int elemtype;

typedef struct treenode

node, *pnode;

void show(pnode * tree)

void getlength(pnode * tree)

pnode * createtree(elemtype *e, int length)

free(str);

printf("堆建立失敗\n");

return null;

}else

str[i]->data = e[i];

}for (i = 0; i < length; i++)

return str;

}void exchangedata(elemtype *a, elemtype * b)

void siftup(pnode root)

else if(root->right == null)

else

if (root->data > e)

else if (c == 1)

}} void siftdown(pnode root)

else if(root->right == null)

else

if (root->data > e)

else if (c == 1)

}} void delete(pnode * tree)

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)

int i, j;

for ( i = 0; tree[i] != null; i++);

if (i > size)

printf("i = %d\n", i);

tree[i] = (pnode)malloc(sizeof(node) * 1);

if (tree[i] == null)

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()

;/* printf("please input 10 numbers\n");

for (i = 0; i < 10; i++)

scanf("%d", a + i);

*/ pnode * tree = createtree(a, 10);

if (tree == null)

for (i = 10 / 2 - 1; i >= 0; i--)

siftup(tree[i]);

show(tree);

for(i = 0; i < 5; i++)

堆建立 插入 刪除和排序

ifndef heap h define heap h include include include include include define maxsize 10 typedef int datatype typedef struct heap heap,pheap 堆的初始化 void h...

堆的建立,插入,刪除

堆的概念 如果有乙個關鍵碼的集合k 把它的所有元素按完全二叉樹的順序儲存方式儲存在乙個一維陣列中,並滿足 ki k2 i 1 且ki k2 i 2 i 0,1,2 則稱這個堆為最小堆 或者最大堆 其實這麼多乾乾的概念還是很不好理解的 先來說一下什麼是完全二叉樹 如果一顆具有n個結點的二叉樹的結構與滿...

堆的建立 刪除 插入

我們知道在c語言中也有乙個名字叫做堆,那麼在資料結構中的堆和c語言中的堆一樣嗎?答案是 no c語言中的堆 其實是因為有一堆東西在此放著,所以起名為堆 資料結構的堆 如果有乙個關鍵碼的集合k 把它的所有元素按完全二叉樹的順序儲存方式儲存在乙個一維陣列中,並滿足 ki k2 i 1 且 ki k2 i...