1. 程式人生 > >左偏樹leftistTree和斜堆skewHeap的分析和實現

左偏樹leftistTree和斜堆skewHeap的分析和實現

最近學習了很多東西(深入學習作業系統中), 部落格的更新也擱置了一段時間, 主要是學習佔用了大量的時間 (學的越多, 也發現自己不會的越多, 就像蘇格拉底說的"我只知道我一無所知");

今天主要分析一下左偏樹和斜堆, 這兩個資料結構是二叉堆的進化版, 一方面能夠實現與二叉堆相同的功能, 程式碼結構也比較簡單; 另一方面它們的合併操作的時間複雜度為O(logn), 而普通二叉堆實現合併操作的時間複雜度為O(n);

左偏樹的性質:

--本節點的鍵值key小於其左右子節點鍵值key(與二叉堆相同);

--本節點的左子節點的距離大於等於本節點的右子節點(這意味著每個節點中除了要儲存鍵值外, 還需要一個額外的dist儲存距離);

--節點的距離是其右子節點的距離+1(這意味著, 一個節點的dist是從它出發到達最近終端節點的距離);

斜堆的性質:

--本節點的鍵值key小於其左右子節點鍵值key;

--斜堆節點不儲存距離dist值, 取而代之的是在每次合併操作時都做swap處理(節省了儲存空間);

核心操作: 合併操作(插入操作, 取最小操作都是基於合併操作);

左偏樹(堆)merge函式具體實現:

--採用遞迴實現;

--每層遞迴中, 當roota->val > rootb->val時, 交換roota和rootb;

--向下遞迴;

--如左子節點距離小於右子節點距離, 交換左右子節點;

--更新本節點距離值;

--返回本節點指標;

斜堆merge函式具體實現:

--採用遞迴實現(也有非遞迴演算法);

--每層遞迴中, 當roota->val > rootb->val時, 交換roota和rootb;

--向下遞迴;

--交換左右子節點;

--返回本節點指標;

左偏樹模板如下(只有新建/合併/插入/取堆頂元素/銷燬等操作, 沒有加入刪除功能):

typedef int elemType;
struct leftistTreeNode {
	elemType data;
	unsigned int dist;
	leftistTreeNode *lchild, *rchild;
	leftistTreeNode(const elemType &val): data(val), dist(0), lchild(NULL), rchild(NULL) {}
};
template <typename type>
void swapPtr(type &x, type &y) {
	type t = x;
	x = y; y = t;
}

leftistTreeNode *createLeftistTree(const vector<elemType> &vec);
void destroyLeftistTree(leftistTreeNode *&root);
leftistTreeNode *mergeLeftistTree(leftistTreeNode *&roota, leftistTreeNode *&rootb);
void insertLeftistTreeNode(leftistTreeNode *&root, const elemType &dt);
leftistTreeNode *extractMinNode(leftistTreeNode *&root);

leftistTreeNode *createLeftistTree(const vector<elemType> &vec) {
	leftistTreeNode *root = NULL;
	for (int i = 0; i != vec.size(); ++i)
		insertLeftistTreeNode(root, vec[i]);
	return root;
}
void destroyLeftistTree(leftistTreeNode *&root) {
	leftistTreeNode *left = root->lchild, *right = root->rchild;
	delete(root); root = NULL;
	if (left) destroyLeftistTree(left);
	if (right) destroyLeftistTree(right);
}
leftistTreeNode *mergeLeftistTree(leftistTreeNode *&roota, leftistTreeNode *&rootb) {//核心部分
	if (!roota || !rootb)
		return roota ? roota : rootb;
	if (roota->data > rootb->data)
		swapPtr<leftistTreeNode*>(roota, rootb);//注意: 此處交換的是指標值
	roota->rchild = mergeLeftistTree(roota->rchild, rootb);
	if (!roota->lchild || roota->lchild->dist < roota->rchild->dist)
		swapPtr<leftistTreeNode*>(roota->lchild, roota->rchild);
	if (!roota->rchild)
		roota->dist = 0;
	else
		roota->dist = roota->rchild->dist + 1;
	return roota;
}
void insertLeftistTreeNode(leftistTreeNode *&root, const elemType &dt) {
	leftistTreeNode *cur = new leftistTreeNode(dt);
	root = mergeLeftistTree(root, cur);
}
leftistTreeNode *extractMinNode(leftistTreeNode *&root) {
	leftistTreeNode *min = root;
	root = mergeLeftistTree(root->lchild, root->rchild);
	return min;
}

斜堆模板如下(只有新建/合併/插入/取堆頂元素/銷燬等操作, 沒有加入刪除功能):
typedef int elemType;
struct skewHeapNode {
	elemType data;
	skewHeapNode *lchild, *rchild;
	skewHeapNode(const elemType &val): data(val), lchild(NULL), rchild(NULL) {}
};

template <typename type>
void swapPtr(type &x, type &y) {
	type t = x;
	x = y; y = t;
}

skewHeapNode *createskewHeap(const vector<elemType> &vec);
void destroyskewHeap(skewHeapNode *&root);
skewHeapNode *mergeskewHeap(skewHeapNode *&roota, skewHeapNode *&rootb);
void insertskewHeapNode(skewHeapNode *&root, const elemType &dt);
skewHeapNode *extractMinNode(skewHeapNode *&root);

skewHeapNode *createskewHeap(const vector<elemType> &vec) {
	skewHeapNode *root = NULL;
	for (int i = 0; i != vec.size(); ++i)
		insertskewHeapNode(root, vec[i]);
	return root;
}
void destroyskewHeap(skewHeapNode *&root) {
	skewHeapNode *left = root->lchild, *right = root->rchild;
	delete(root); root = NULL;
	if (left) destroyskewHeap(left);
	if (right) destroyskewHeap(right);
}
skewHeapNode *mergeskewHeap(skewHeapNode *&roota, skewHeapNode *&rootb) {//此處與左偏堆不同, 不判斷左右子節點距離
	if (!roota || !rootb)
		return roota ? roota : rootb;
	if (roota->data > rootb->data)
		swapPtr<skewHeapNode*>(roota, rootb);
	roota->rchild = mergeskewHeap(roota->rchild, rootb);
	swapPtr(roota->lchild, rootb->rchild);
	return roota;
}
void insertskewHeapNode(skewHeapNode *&root, const elemType &dt) {
	skewHeapNode *cur = new skewHeapNode(dt);
	root = mergeskewHeap(root, cur);
}
skewHeapNode *extractMinNode(skewHeapNode *&root) {
	skewHeapNode *min = root;
	root = mergeskewHeap(root->lchild, root->rchild);
	return min;
}

最近應該會多發一些學習總結性的內容, 鞏固一下知識, 有空把我的學習筆記也發上來供大家參考;

如果演算法或分析有問題, 請指正, 謝謝