一.遍歷的分類
二分搜尋樹遍歷分為兩大類,深度優先遍歷和層序遍歷。
深度優先遍歷分為三種:先序遍歷(preorder tree walk)、中序遍歷(inorder tree walk)、後序遍歷(postorder tree walk),分別為:
1、前序遍歷:先訪問當前節點,再依次遞迴訪問左右子樹。
2、中序遍歷:先遞迴訪問左子樹,再訪問自身,再遞迴訪問右子樹。
3、後序遍歷:先遞迴訪問左右子樹,再訪問自身節點。
二. 深度優先遍歷
- 前序遍歷:先訪問當前節點,再依次遞迴訪問左右子樹。
- 中序遍歷:先遞迴訪問左子樹,再訪問自身,再遞迴訪問右子樹。
- 後序遍歷:先遞迴訪問左右子樹,再訪問自身節點。
為了更好理解深度優先遍歷我們使用下圖模型:
1. 前序遍歷:
我們對二分搜尋樹中所有節點都分別標記3個點:
開始遍歷:
前序遍歷是對每一個節點第一次訪問的時候進行遍歷:
28
遍歷:28, 16
遍歷:28, 16, 13
遍歷:28, 16, 13
遍歷:28, 16, 13
遍歷:28, 16, 13, 22
遍歷:28, 16, 13, 22
遍歷:28, 16, 13, 22
遍歷:28, 16, 13, 22
依次類推 ……
最後完成整個前序遍歷:
遍歷:28, 16, 13, 22, 30, 29, 42
**程式碼實現(使用遞迴,c++實現)
在public中定義:
//前序遍歷,傳入節點,列印節點相應資訊
void preOrder() {
return preOrder(root);
}
在private中定義:
//前序遍歷,以node為根節點的二分搜尋樹進行前序遍歷,列印節點相應資訊
void preOrder(Node *node) {
if (node != NULL) {
//不一定用列印,還可以對node->key和node->value進行操作
cout << node->key << endl;
preOrder(node->left);
preOrder(node->right);
}
}
2. 中序遍歷
按照前序遍歷的模型和順序,很容易看出中序遍歷就是在中間點的時候進行遍歷:(過程省略)
遍歷:13, 16, 22, 28, 29, 30, 42
如下圖:(可以看出由中序遍歷可以看出遍歷結果是有序的)
**程式碼實現(使用遞迴,c++實現)
在public中定義:
//中序遍歷,以節點為node的節點為根節點
void inOrder() {
return inOrder(root);
}
在private中定義:
//中序遍歷,以node為根節點的二分搜尋樹進行前序遍歷,列印節點相應資訊
void inOrder(Node *node) {
if (node != NULL) {
inOrder(node->left);
cout << node->key << endl;
inOrder(node->right);
}
}
3. 後序遍歷
一樣的邏輯,後序遍歷就是在第三個點時進行遍歷:(過程省略)
遍歷:13, 22, 16, 29, 42, 30, 28
如下圖:
後序遍歷有個重要的應用:二叉樹的銷燬(從子節點依次向上刪除)
**程式碼實現(使用遞迴,c++實現)
在public中定義:
//後序遍歷,以node為根節點的二分搜尋樹進行前序遍歷,列印節點相應資訊
void postOrder() {
return postOrder(root);
}
在private中定義:
//後序遍歷,以node為根節點的二分搜尋樹進行前序遍歷,列印節點相應資訊
void postOrder(Node *node) {
if (node != NULL) {
postOrder(node->left);
postOrder(node->right);
cout << node->key << endl;
}
}
下面我們來使用後序遍歷將二分搜尋樹銷燬:
//解構函式的實現,其本質是後序遍歷
void distroy(Node *node) {
if (node != NULL) {
distroy(node->left);
distroy(node->right);
delete node;
count--;
}
}
三. 廣度優先遍歷
1.介紹
二分搜尋樹的廣度優先(層序遍歷),即逐層進行遍歷,即將每層的節點存在佇列當中,然後進行出隊(取出節點)和入隊(存入下一層的節點)的操作,以此達到遍歷的目的。
通過引入一個佇列來支撐層序遍歷:
如果根節點為空,無可遍歷;
如果根節點不為空:
先將根節點入隊;
只要佇列不為空:
- 出隊隊首節點,並遍歷;
- 如果隊首節點有左孩子,將左孩子入隊;
- 如果隊首節點有右孩子,將右孩子入隊;
2.具體資料
以下圖為例:
- 我們使用一個佇列——front
將28放入佇列中
出:空
入:28
佇列:28
遍歷情況:空
出:28
入:16, 30
佇列:16, 30
遍歷情況:28
出:16
入:13 ,22
佇列:30, 13, 22
遍歷情況:28, 16
出:30
入:29 ,42
佇列: 13, 22, 29, 42
遍歷情況:28, 16, 30
出:13
入:空
佇列: 22, 29, 42
遍歷情況:28, 16, 30, 13
出:22
入:空
佇列: 29, 42
遍歷情況:28, 16, 30, 13, 22
出:29
入:空
佇列: 42
遍歷情況:28, 16, 30, 13, 22, 29
出:42
入:空
佇列: 空
遍歷情況:28, 16, 30, 13, 22, 29, 42
遍歷完成:
遍歷情況:28, 16, 30, 13, 22, 29, 42
3.程式碼實現(使用遞迴,c++實現)
//層序遍歷
void levelOrder(){
queue<Node*> q; //佇列d
q.push(root); //將root入隊
//佇列不為空的情況
while(!q.empty()){
Node *node = q.front(); //將佇列第一個元素取出
q.pop(); //是刪除棧頂元素
cout<<node->key<<endl;
if(node->left)
q.push(node->left);
if(node->right)
q.push(node->right);
}
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結