演算法第十二記 二叉排序樹總結

2021-09-02 19:19:47 字數 3891 閱讀 8823

今天在看完了《演算法導論》的二叉排序樹和極客時間王爭老師講的二叉排序樹有了不少體會,下面進行總結一下:

#pragma once

struct treenode

int value;

treenode* left_child, *right_child,*parent;

};class binarytree

treenode* search(int val);

void insert(treenode* node);

void remove(treenode* des);

void remove(int val);

treenode* successor(treenode* x);

treenode* predesessor(treenode* x);

void inorder();

void preorder();

void aftorder();

private:

treenode* ret_minimum(treenode* x);

treenode* ret_maxnimum(treenode* x);

void transplant(treenode* u, treenode* v);

private:

treenode* root;

};

#include "binarytree.h"

#include #include using std::stack;

using std::cout;

using std::swap;

treenode* binarytree::search(int val)

return nullptr;

}void binarytree::insert(treenode* node)

return;

} treenode* cur = root;

treenode* pre=nullptr;

while (cur)

if (node->value >= pre->value)

pre->right_child = node;

else

pre->left_child = node;

node->parent = pre;

}void binarytree::remove(treenode * des)

else if (des->right_child == nullptr)

else }

void binarytree::remove(int val)

treenode * binarytree::successor(treenode * x)

else }

return par;

}treenode * binarytree::predesessor(treenode * x)

else

return par; }

}void binarytree::inorder()

if (sta.empty())

break;

cur = sta.top();

cout << cur->value<

sta.pop();

cur = cur->right_child; }}

void binarytree::preorder()

if (sta.empty())

break;

cur = sta.top();

sta.pop(); }}

void binarytree::aftorder()

while (!sta_2.empty()) }

treenode* binarytree::ret_minimum(treenode* x)

return cur;

}treenode* binarytree::ret_maxnimum(treenode* x)

return cur;

}void binarytree::transplant(treenode * u, treenode * v)

實現過程中,最大的體會是在於刪除這步操作上,刪除要考慮三種情況,只有左子樹、只有右子樹、左右子樹都有,前兩種情況比較好操作,我們定義了乙個transplant操作用來替代子樹。所以當只有乙個子樹時,我們只要把當前待刪節點的子樹直接接上去就可以了。麻煩的是左右子樹都有的情況,一般我們會選擇待刪節點的前驅或後繼來代替當前節點,這樣就依然能維持二叉排序樹的性質。這裡我選擇了後繼來替代待刪節點。所以刪除的過程就成了,先找到後繼結點,又由於後繼節點肯定是沒有左孩子的所以我們可以先將後繼結點的值與待刪除節點的值進行交換,然後刪除此時這個後繼節點的位置。

void binarytree::remove(treenode * des)

else if (des->right_child == nullptr)

else

}

swap操作可能需要3次拷貝操作,所以如果拷貝操作開銷比較大的話,我們可以選擇另一種原理一樣但刪除稍顯不同的操作。這種操作只要改變幾次指標的指向就行了。

這種操作就又要分兩種情況1.後繼節點此時就是待刪除節點的右孩子 2.後繼結點在待刪除節點右孩子的左子樹中。如果是情況二的話,我們需要多做幾部操作。

1.首先將後繼結點從樹中脫離出來(使用後繼節點的右子樹代替它的位置)

2.然後將這個後繼結點的右孩子指向待刪除結點的右孩子

3.待刪除節點右孩子的父母指向該後繼結點

4.然後將這個後繼節點代替待刪除節點的位置

5.然後這個後繼節點的左孩子指向待刪除結點的左孩子

6.最後待刪除節點左孩子的父母指向這個後繼節點

}}支援重複資料的二叉查詢樹前面講二叉查詢樹的時候,我們預設樹中節點儲存的都是數字。很多時候,在實際的軟體開發中,我們在二叉查詢樹中儲存的,是乙個包含很多欄位的物件。我們利用物件的某個字段作為鍵值(key)來構建二叉查詢樹。我們把物件中的其他字段叫作衛星資料。

前面我們講的二叉查詢樹的操作,針對的都是不存在鍵值相同的情況。那如果儲存的兩個物件鍵值相同,這種情況該怎麼處理呢?我這裡有兩種解決方法。

第一種方法比較容易。二叉查詢樹中每乙個節點不僅會儲存乙個資料,因此我們通過鍊錶和支援動態擴容的陣列等資料結構,把值相同的資料都儲存在同乙個節點上。

第二種方法比較不好理解,不過更加優雅。

每個節點仍然只儲存乙個資料。在查詢插入位置的過程中,如果碰到乙個節點的值,與要插入資料的值相同,我們就將這個要插入的資料放到這個節點的右子樹,也就是說,把這個新插入的資料當作大於這個節點的值來處理。

當要查詢資料的時候,遇到值相同的節點,我們並不停止查詢操作,而是繼續在右子樹中查詢,直到遇到葉子節點,才停止。這樣就可以把鍵值等於要查詢值的所有節點都找出來。

對於刪除操作,我們也需要先查找到每個要刪除的節點,然後再按前面講的刪除操作的方法,依次刪除。

由於二叉排序樹的查詢效率與樹的高度有關,所以如果樹不平衡的話,最終的查詢效率還是不夠理想,最差的時候就是左斜樹或則右斜樹,這樣二叉排序樹的查詢效率就與鍊錶相差不多了。所以這就引入了平衡二叉樹,來防止效率的降低。

演算法總結 二叉排序樹

演算法總結 二叉排序樹 二叉排序樹是一棵特殊的二叉樹,它是一棵二叉樹但同時滿足如下條件 對於樹上任意乙個結點,其上的數值必大於等於其左子樹上任意結點數值,必小於等於其右子樹上任意結點的數值。我們從二叉樹的插入開始了解其建樹方式,對二叉排序樹插入數字 x 1.若當前樹為空,則 x 為其根結點。2.若當...

排序演算法 二叉排序樹

二叉排序樹的基本思想是將序列中的數讀入乙個二叉樹,在讀入時遵循一定的規則 比如,如果二叉樹的乙個節點有左子節點,那麼左子節點一定比父節點的值小 如果乙個節點有右子節點,那麼右子節點一定比父節點的值大。在二叉排序樹製造完成後,通過採用中序遍歷的方法讀取二叉樹節點的值到序列中,就可以得到乙個公升序序列。...

第十二章 二叉搜尋樹

施工中基本操作包括inorder tree walk minimum successor insert delete等。主要是用c 實現,部分會在日後補上 region 二叉樹基本操作 非遞迴版的中序遍歷 頭結點 public static void inorder tree walk node i...