二叉排序樹

2021-07-23 20:43:32 字數 4139 閱讀 2968

什麼是二叉排序樹:即乙個二叉樹,它的每乙個結點的左孩子的key值比當前結點的key值小,而右孩子結點的key值比當前結點的key值大,這樣的乙個樹就是二叉排序樹,也叫二叉搜尋樹(bst_tree);

一顆排序二叉樹的結點框架大概就是這樣:

template

k>

struct

searchbinarytreenode

};

為什麼是排序樹?

是因為如果你去中序遍歷這棵樹的話,遍歷的結果是有序的(公升序);

下面是一棵二叉排序樹的例子:

實現這棵樹的時候我們一般有 增,刪,查三個操作,為什麼沒有改的操作?

其實可以有的,但是改結點的操作正如定義結點框架時所講的,只能修改無關值value等,不能修改key值標識,二叉排序樹是根據key值構造的樹,如果修改了key值,那麼這棵樹就不確實是否依舊是排序樹了;

實現操作**之前,我會在這裡對實現思路進行一定的說明;

首先,這三個操作都可以用遞迴和非遞迴的方法實現,**中對遞迴和非遞迴都有一定的說明;

第一:增結點操作

即在這顆二叉樹中增加乙個結點,並且保持仍然是排序樹,再次強調:樹中的結點key值都是唯一的,不能重複;(後面不再說明,貫徹全文);所以,唯一需要解決的問題就是結點應該插在哪個位置?

看下圖,如果我要在原圖中插入乙個結點,根據樹的特點,比當前結點小,就往它的左樹走,反之右樹,直到左樹為空,或者右樹為空,就代表找到了可以插入的位置;

第二:查詢操作

查詢操作是最簡單的操作,只要比較需要查詢的key值和二叉樹的結點的key值,如果大於樹中結點的key值就往右子樹繼續找,反之往左子樹繼續找,相等的話就是找到了;如果結點都為null了還沒找到就是沒有;

第三: 刪除結點操作

刪除結點的操作就略微有些麻煩了,因為要保持排序樹的性質,所以刪除的時候需要額外注意,首先需要在樹中找到需要刪除的結點,如果刪除的是葉子結點的話就比較好刪除,只要讓父節點的left或者right指向空就好了(至於是父節點的right,還是父節點的left,遞迴和非遞迴的判別方法不一樣,具體看**),如果不是葉子結點呢,又可以分為三種情況:

第一種:當前結點的左為null,那麼就讓父節點的left或者right指向當前結點的右子樹;

第二種:當前結點的右為null,那麼就讓父節點的left或者right指向當前結點的左子樹;

其實可以看出來,要刪除的是葉子結點的話也可歸為左子樹為null或者右子樹為null的情況,因為葉子結點的左右子樹都為null;

注意:前兩種情況有乙個坑:

//有一種情況是,刪除根節點時,根節點只有乙個子樹,即按照左子樹為null或者右子樹為null的情況處理,此時根節點的parent是null,所以需要單獨處理!

第三種:左右子樹都不為null的情況

這種情況就需要想一下如何在不改變樹性質的情況下,達到刪除的目的,我們可以想想,在刪除乙個無頭指標的指定結點的時候,應該怎麼做?因為是沒有頭指標的,所以我們無法從投遍歷鍊錶,就不知道當前刪除結點的前乙個結點的指標,那麼,解決的辦法就是把當前結點的值和下乙個結點的值進行交換,然後刪除下乙個結點就好了; 我們排序樹這裡的原理也是類似的,我們可以把當前需要刪除的非葉子結點和乙個比較容易刪除的結點的key值進行交換,然後刪除那個比較容易刪除的結點;

那麼,怎麼找到這個比較容易刪除的結點,可以交換key值並且不改變樹的性質?

有兩種方法,我們可以和當前結點左子樹的最右結點的key值交換;或者和當前結點的右子樹的最左結點的key值交換;

為什麼呢?

因為交換之後還要保持當前結點的key值比它的左子樹的key值大,比右子樹的key值小,所以只有以上兩種情況的結點可以滿足要求;

例如下圖:

交換結果如下,依然是二叉排序樹:

然後刪除結點3即可到到目的!

下圖是刪除結點的總分析圖:

}//增 遞迴

bool insertr(node*& root, k key)

else

if(root->_key == key)

return

false;

else

if(root->_key > key)

return insert(root->_right ,key);

}//增 非遞迴

bool insert(const k& key)

node* cur = _root;

node* parent = null;

int flag = -1;

while(cur)

else

if(cur->_key > key)

}cur = new node(key);

if(flag == 1)

parent->_right = cur;

else

if(flag == 0)

parent->_left = cur;

return

true;

}//刪 遞迴

bool remover(const k& key)

//刪 非遞迴

bool remove(const k& key)

else

if(cur->_left == null)

else

}else

if(cur->_right ==null)

else

}delete del;

return

true;

}else

if(cur->_key < key)

else

if(cur->_key > key)

}return

false;

}//查 非遞迴

bool find(const k& key)

return

false;

}//查詢 遞迴

bool findr(const k& key)

//中序遍歷

void inorder()

delete del;

return

true;}}

//查詢 遞迴

bool _findr(node* root, const k& key)

void _inorder(node* root)

private:

node* _root;

};int main()

; searchbinarytreet(arr,10);

t.inorder ();

t.remove (0);

t.remove (1);

t.remove (2);

t.remove (3);

t.remove (4);

t.remove (5);

t.remove (6);

t.remove (7);

t.remove (8);

t.remove (9);

t.inorder ();

system("pause");

return

0;}

二叉排序樹

在複習資料結構,把這個東西總結一下。這種結構是動態查詢表,這種動態是相對靜態查詢 順序查詢,折半查詢,分塊查詢等 來說的。對於各種靜態鍊錶,要達到查詢複雜度為o logn 必須要求有序 而要使插入刪除複雜度為o 1 必須是鍊錶儲存。動態查詢表就可以同時滿足這兩者。動態查詢表的特點是表結構本身在查詢過...

二叉排序樹

name 二叉排序樹相關操作 author unimen date 2011 10 8 13 14 21 刪除結點比較麻煩,總結如下 4大種情況 1 結點p無右孩子 將該點的左孩子變為其在雙親中的同位孩子 1 p為其雙親的左孩子時將其的左孩子變為雙親的左孩子 2 p為其雙親的右孩子時將其的左孩子變為...

二叉排序樹

include include include include struct tree node void insert node struct tree node int void pre order struct tree node void in order struct tree node ...