//這裡的堆指的都是二叉堆,為了優先佇列產生(優先佇列,使一些特殊的結點在出隊的時候要優先出來。出隊入隊操作變成了insert和delete)
//堆是乙個完全二叉樹,除了最後一層,其餘層都是滿的。這樣的話儲存用乙個陣列就可以,任乙個元素位置在i,其左兒子位置是2*i,右兒子位置是2*i+1,父結點是i/2向下取整
//完全二叉樹的高度是logn的下界,所以涉及到完全二叉樹的操作,是跟這個高度相關的,就是o(logn),比如下面的上濾和下濾
//buildheap是o(n),它的界就是堆兩個結點之間的線的條數,這個可以通過計算堆中所有結點的高度和來得到,這個和是o(n)
//d堆,二叉堆是2堆,這樣就理解d堆是什麼了。書上說實踐中4堆可以勝過二叉堆......
//二叉堆和bst(二叉搜尋樹)的區別,二叉搜尋樹的左結點《父結點《右結點,堆是父結點小於孩子結點,孩子結點的順序沒有比。大於同理。
template class binaryheap
bool isempty() const;
const comparable & findmin() const;
void insert(const comparable & x) //insert相當於入隊操作
array[hole] = x;
} void deletemin() //deletemin相當於出隊操作,操作可以迅速執行依賴於堆序性質,最小的在根上,這個規律遞迴到子堆
void deletemin(comparable & minitem) //和上面的區別,就是把出隊的元素存到minitem裡了
void makeempty();
private:
int currentsize;
vectorarray;
void buildheap() //這個堆(現在還不是堆)先是亂排的,然後從下往上一直下濾,這個堆就是有序的了 }
void percolatedown(int hole) //下濾,上面呼叫的函式
if (array[child] < tmp)
else
break;
} array[hole] = tmp;
}};//左式堆:1.左兒子的零路徑長至少與右路徑的零路徑長一樣大;2.任一結點的零路徑長比它的諸兒子結點的零路徑長的最小值多1。merge用到了這兩個性質
//n個結點的左式樹有一條右路經最多含有log(n+1)的下界個結點。對左式堆操作的一般思路是,將所有的工作放到右路徑上進行,保證樹深短。
//從樹開始,這裡面的類定義都有乙個技巧,就是用公有的函式呼叫私有的函式
templateclass leftistheap
void deletemin()
void deletemin(comparable & minitem)
void makeempty();
void merge(leftistheap & rhs) //合併,左式堆的最主要的演算法。遞迴的將具有大的根值的堆和具有小的根值的堆的右子堆合併。所以執行合併的時間與右路徑的長的和成正比,合併兩個左式堆的時間界o(logn)
root = merge(root, rhs.root);
rhs.root = null;
} const leftistheap & operator=(const liftistheap & rhs);
private:
struct leftistnode
};leftistnode * root;
leftistnode * merge(leftistnode *h1, leftistnode *h2)
leftistnode * merge1(leftistnode *h1, leftistnode *h2);
else
h1->npl = h1->right->npl + 1;
} return h1;
} void swapchildren(leftistnode *t);
void reclainmemory(leftistnode *t);
leftistnode * clone(leftistnode *t) const;
};//二項佇列,是乙個二項樹的森林,n個結點,用幾棵二項樹組成
templateclass binomialqueue
int minindex = findminindex(); //找到最小的是哪棵樹的樹根,返回座標
minitem = thetrees[minindex]->element;
binomialnode *oldroot = thetrees[minindex];
binomialnode *deletedtree = oldroot->leftchild;
delete oldroot;
binomialqueue deletedqueue; //把找到的那棵樹的根刪除之後,剩下的變成乙個新的森林
deletedqueue.thetrees.resize(minindex + 1); //為什麼我覺得resize(minindex)也可以......
deletedqueue.currentsize = (1 << minindex) - 1; //就是2^minindex-1,就是那棵樹去掉根結點之後的結點數
for (int j = minindex - 1; j >= 0; j--) //這個就是造森林的過程,**沒問題.......二項佇列的特點,每一棵樹的子樹,都是層數從0往上排的.......只是整個森林不一定每棵樹都有
thetrees[minindex] = null;
currentsize -= deletedqueue.currentsize + 1;
merge(deletedqueue);
} void makeempty();
void merge(binomialqueue & rhs)
binomialnode * carry = null; //合併二項佇列的過程,有兩個森林,然後按照從小往大排每棵樹,把兩個森林對應的位置相加(combinetrees就是幹這個的)。
//這個carry相當於,乙個進製,比如高度為2的兩個樹合併之後,高度變成了3,carry就要存這個,之前的兩棵樹2的位置清空;
//然後carry,兩棵樹有8種情況,逐個分析。這裡combine,也只合併兩個高度相同的tree。
for (int i = 0, j = 1; j <= currentsize; i++; j *= 2) //這裡的i就是thetrees的標號,j是用來控制這個標號的。i對應這個位置的樹的高度,每棵樹有2^i個結點,所以如果總共有n個結點,樹最大的編號就是logn的下界
for (int k = 0; k < rhs.thetrees.size(); k++)
rhs.thetrees[k] = null;
rhs.currentsize = 0;
} }const binomialqueue & operator=(const binomialqueue & rhs);
private:
struct binomialnode
};enum(default_trees = 1);
//乙個二項佇列的森林,包括一共有多少個結點,還有森林每棵樹根結點的vector(vector的座標是這棵樹的高度,這棵樹的結點數是2^i,i是座標。比如只有乙個結點的就是0,如果沒有這棵樹,就是null)
int currentsize; //總的結點數
vectorthetrees; //an array of tree roots
int findminindex() const
}return minindex;
} int capcity() const;
binomialnode* combinetrees(binomialnode *t1, binomialnode *t2) //這個是把兩個大小一樣的tree合併 t1和t2是兩棵樹的root
void makeempty(binomialnode * & t);
binomialnode * clone(binomialnode *t) const;
};
左式二叉堆
定義 零路徑長npl x 定義為從x到乙個沒有兩個兒子的節點的最短路徑長。npl x min 1 定義npl null 1,那麼這個公式滿足只有乙個子節點的節點 左式堆的性質 1 結構性質 對於堆中的任一節點,左兒子的零路徑長至少與右兒子的零路徑長一樣大 2 堆序性質 和二叉樹的相同,節點的值大於等...
二叉堆 Heap 的學習
定義 在一棵完全二叉樹中,滿足a parent i a i 小根堆為例 性質1 parent i i 2 left i i 2 right i i 2 1 性質2 高度為 h的堆,元素對多 個,最少 個 性質3 含 n個元素的堆的高度為floor lg n 性質 4 當用陣列表示儲存了 n個元素的堆...
二叉堆的實現
include include define max heap size 101 class binaryminheap void insert intvalue void removemin intgetmin void displayheaparray private int heaparray...