3、【資料結構】樹形結構之二叉查詢樹
一、樹的介紹
1. 樹的定義
樹是一種資料結構,它是由n(n>=1)個有限節點組成一個具有層次關係的集合。 把它叫做“樹”是因為它看起來像一棵倒掛的樹,也就是說它是根朝上,而葉朝下的。它具有以下的特點: (1) 每個節點有零個或多個子節點; (2) 沒有父節點的節點稱為根節點; (3) 每一個非根節點有且只有一個父節點; (4) 除了根節點外,每個子節點可以分為多個不相交的子樹。
2. 樹的基本術語
若一個結點有子樹,那麼該結點稱為子樹根的"雙親",子樹的根是該結點的"孩子"。有相同雙親的結點互為"兄弟"。一個結點的所有子樹上的任何結點都是該結點的後裔。從根結點到某個結點的路徑上的所有結點都是該結點的祖先。 結點的度
二、二叉樹的介紹
1. 二叉樹的定義
二叉樹是每個節點最多有兩個子樹的樹結構。它有五種基本形態:二叉樹可以是空集;根可以有空的左子樹或右子樹;或者左、右子樹皆為空。
2. 二叉樹的性質
二叉樹有以下幾個性質: 性質1:二叉樹第i層上的結點數目最多為 2{i-1} (i≥1)。 性質2:深度為k的二叉樹至多有2{k}-1個結點(k≥1)。 性質3:包含n個結點的二叉樹的高度至少為log2 (n+1)。 性質4:在任意一棵二叉樹中,若終端結點的個數為n0,度為2的結點數為n2,則n0=n2+1
3. 滿二叉樹,完全二叉樹和二叉查詢樹
3.1 滿二叉樹 定義:高度為h,並且由2{h} –1個結點的二叉樹,被稱為滿二叉樹。 3.2 完全二叉樹 定義:一棵二叉樹中,只有最下面兩層結點的度可以小於2,並且最下一層的葉結點集中在靠左的若干位置上。這樣的二叉樹稱為完全二叉樹。 特點:葉子結點只能出現在最下層和次下層,且最下層的葉子結點集中在樹的左部。顯然,一棵滿二叉樹必定是一棵完全二叉樹,而完全二叉樹未必是滿二叉樹。 3.3 二叉查詢樹 定義:二叉查詢樹, 即二叉查詢樹(Binary Search Tree),又被稱為二叉搜尋樹。設x為二叉查詢樹中的一個結點,x節點包含關鍵字key,節點x的key值記為key[x]。如果y是x的左子樹中的一個結點,則key[y] <= key[x];如果y是x的右子樹的一個結點,則key[y] >= key[x]。 在二叉查詢樹中: (1) 若任意節點的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值; (2) 任意節點的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值; (3) 任意節點的左、右子樹也分別為B樹。 (4) 沒有鍵值相等的節點(no duplicate nodes)。 其具體結構如下圖所示:
三、二叉查詢樹的實現(C++)
BSTree.h
typedef int DataType;
struct BSTNode
{
DataType data;
BSTNode *lchild;
BSTNode *rchild;
BSTNode *parent;
BSTNode(DataType x)
:data(x), lchild(NULL), rchild(NULL), parent(NULL){};
};
class BSTree {
public:
BSTree();//建構函式
~BSTree();//解構函式
//定義外部介面函式
//前序遍歷
void preOrder();
//中序遍歷
void inOrder();
//後序遍歷
void postOrder();
//分層遍歷
void levelOrder();
//查詢鍵值為x的結點
BSTNode *searchNode(DataType x);
//將鍵值為x的結點插入二叉樹
void insertNode(DataType x);
//刪除鍵值為x的結點
void removeNode(DataType x);
//銷燬二叉樹
void destroyBSTree();
//列印二叉樹
void printBSTree();
//查詢鍵值最小的結點
DataType minMem();
//查詢鍵值最大的結點
DataType maxMem();
private://定義內部資料和介面函式
BSTNode *root; // 根結點
// 前序遍歷"二叉樹"
void preOrder(BSTNode *root);
// 中序遍歷"二叉樹"
void inOrder(BSTNode *root);
// 後序遍歷"二叉樹"
void postOrder(BSTNode *root);
//分層遍歷
void levelOrder(BSTNode *root);
//查詢
BSTNode * searchNode(BSTNode *root, DataType key);
//插入
void insertNode(BSTNode * &root, BSTNode *x);
//刪除
BSTNode * removeNode(BSTNode *root, BSTNode *x);
//銷燬
void destroyBSTree(BSTNode *root);
//列印
void printBSTree(BSTNode *root, DataType data, int direction);
//查詢最小結點
BSTNode * minMem(BSTNode *root);
//查詢最大結點
BSTNode * maxMem(BSTNode *root);
//查詢前驅
BSTNode * predecessorode(BSTNode *x);
//查詢後繼
BSTNode * successorNode(BSTNode *x);
};
BSTree.cpp
#include <iostream>
#include <iomanip>
#include <queue>
#include "BSTree.h"
using namespace std;
//建構函式
BSTree::BSTree()
:root(NULL)
{
}
//解構函式
BSTree::~BSTree()
{
destroyBSTree();
}
//銷燬二叉樹 - 內部函式
void BSTree::destroyBSTree(BSTNode *bstnode)
{
if(bstnode == NULL)
return;
if(bstnode->lchild != NULL)
return destroyBSTree(bstnode->lchild);
if(bstnode->rchild != NULL)
return destroyBSTree(bstnode->rchild);
delete bstnode;
bstnode = NULL;
}
//銷燬二叉樹 - 外部函式
void BSTree::destroyBSTree()
{
destroyBSTree(root);
}
//插入新結點 - 內部函式
void BSTree::insertNode(BSTNode * &bstnode, BSTNode *x)
{
BSTNode *y = NULL;
BSTNode *z = bstnode;
//查詢x的插入位置
while(z != NULL)
{
y = z;
if(x->data < z->data)
z = z->lchild;
else
z = z->rchild;
}
x->parent = y;
if(y == NULL)
{
bstnode = x;
}
else if(x->data < y->data)
{
y->lchild = x;
}
else
{
y->rchild = x;
}
}
//插入新結點 - 外部函式
void BSTree::insertNode(DataType x)
{
BSTNode *temp = new BSTNode(x);
insertNode(root, temp);
}
//列印二叉樹 - 內部函式
void BSTree::printBSTree(BSTNode *bstnode, DataType data, int direction)
{
if(bstnode != NULL)
{
if(direction == 0)
cout << setw(2) << bstnode->data << " is root " << endl;
else
cout << setw(2) << bstnode->data << " is " << setw(2) << data
<< "`s" << setw(12)
<< (direction == 1?"right child":"left child") << endl;
printBSTree(bstnode->lchild, bstnode->data, -1);
printBSTree(bstnode->rchild, bstnode->data, 1);
}
}
//列印二叉樹 - 外部函式
void BSTree::printBSTree()
{
if(root == NULL)
cout << "good job" << endl;
if(root != NULL)
printBSTree(root, root->data, 0);
}
//前序遍歷 - 內部函式
void BSTree::preOrder(BSTNode *root)
{
if(root != NULL)
{
cout << root->data << " ";
preOrder(root->lchild);
preOrder(root->rchild);
}
}
//前序遍歷 - 外部函式
void BSTree::preOrder()
{
preOrder(root);
}
//中序遍歷 - 內部函式
void BSTree::inOrder(BSTNode *root)
{
if(root != NULL)
{
inOrder(root->lchild);
cout << root->data << " ";
inOrder(root->rchild);
}
}
//中序遍歷 - 外部函式
void BSTree::inOrder()
{
inOrder(root);
}
//後續遍歷 - 內部函式
void BSTree::postOrder(BSTNode *root)
{
if(root != NULL)
{
postOrder(root->lchild);
postOrder(root->rchild);
cout << root->data << " ";
}
}
//後續遍歷 - 外部函式
void BSTree::postOrder()
{
postOrder(root);
}
//分層遍歷 - 內部函式
void BSTree::levelOrder(BSTNode *root)
{
//這裡使用佇列儲存二叉樹的每個結點
//佇列的特性:先進先出
queue<BSTNode *> q;
BSTNode *p = root;
q.push(p);
while(!q.empty())
{
p = q.front();
cout << p->data << " ";
q.pop();
if(p->lchild != NULL)
{
q.push(p->lchild);
}
if(p->rchild != NULL)
{
q.push(p->rchild);
}
}
cout << endl;
}
//分層遍歷 - 外部函式
void BSTree::levelOrder()
{
levelOrder(root);
}
//查詢鍵值為x的結點 - 內部函式
BSTNode * BSTree::searchNode(BSTNode *root, DataType x)
{
if(root == NULL || root->data == x)
return root;
if(x < root->data)
return searchNode(root->lchild, x);
else
return searchNode(root->rchild, x);
}
//查詢鍵值為x的結點 - 外部函式
BSTNode * BSTree::searchNode(DataType x)
{
searchNode(root, x);
}
//查詢最小結點 - 內部函式
BSTNode * BSTree::minMem(BSTNode *root)
{
if(root == NULL)
return NULL;
while(root->lchild != NULL)
root = root->lchild;
return root;
}
//查詢最小結點 - 內部函式
DataType BSTree::minMem()
{
BSTNode *p = minMem(root);
if(p != NULL)
return p->data;
return (DataType)NULL;
}
//查詢最大結點 - 內部函式
BSTNode * BSTree::maxMem(BSTNode *root)
{
if(root == NULL)
return NULL;
while(root->rchild != NULL)
root = root->rchild;
return root;
}
//查詢最大結點 - 外部函式
DataType BSTree::maxMem()
{
BSTNode *p = maxMem(root);
if(p != NULL)
return p->data;
return (DataType)NULL;
}
//查詢結點x的後繼結點,即查詢二叉樹中資料值大於該結點的最小值
BSTNode * BSTree::successorNode(BSTNode *x)
{
//如果x存在右孩子, 則x的後繼結點為“以其右孩子為根的子樹的最小結點
if(x->rchild != NULL)
return minMem(x->rchild);
//如果x沒有右孩子,則x有以下兩種可能:
//(1)x是”一個左孩子“,則”x的後繼結點“為”它的父結點“
//(2)x是一個右孩子,則查詢x的最低父結點,並且該父節點要有左孩子,
//找到這個最低父節點就是x的後繼結點
BSTNode *y = x->parent;
while((y != NULL) && (x == y->rchild))
{
x = y;
y = y->parent;
}
return y;
}
//查詢結點x的前驅結點,即查詢二叉樹中資料值小於該結點的最大值
BSTNode * BSTree::predecessorode(BSTNode *x)
{
//如果x存在左孩子,則x的前驅結點就是以其左孩子為根的子樹的最大結點
if(x->lchild != NULL)
return maxMem(x->lchild);
//如果x沒有左孩子,則x有以下兩張可能
//(1)x是一個右孩子,則x的前驅結點為它的父節點
//(2)x是一個左孩子,則查詢x的最低父節點,並且該父節點具有右孩子,
//找到這個最低的父節點就是x的前驅結點
BSTNode *y = x->parent;
while((y != NULL) && (x == y->lchild))
{
x = y;
y = y->parent;
}
return y;
}
//刪除鍵值為x的結點,並返回該結點 - 內部函式
BSTNode * BSTree::removeNode(BSTNode *root, BSTNode *x)
{
BSTNode *y = NULL;
BSTNode *z = NULL;
if((x->lchild == NULL) || (x->rchild == NULL))
z = x;
else
z = successorNode(x);
if(z->lchild != NULL)
y = z->lchild;
else
y = z->rchild;
if(y != NULL)
y->parent = z->parent;
if(z->parent == NULL)
root = y;
else if(z == z->parent->lchild)
z->parent->lchild = y;
else
z->parent->rchild = y;
if(z != x)
x->data = z->data;
return z;
}
//刪除鍵值為x的結點,並返回該結點 - 外部函式
void BSTree::removeNode(DataType x)
{
BSTNode *z, *node;
if((z = searchNode(root, x)) != NULL)
if((node = removeNode(root, z)) != NULL)
delete node;
}
main.cpp
#include <iostream>
#include "BSTree.h"
using namespace std;
static int arr[] = {1, 5, 4, 3, 2, 6};
#define SIZE(a) ((sizeof(a))/(sizeof(a[0])))
int main()
{
int len;
BSTree *bstree = new BSTree();
//新增元素
len = SIZE(arr);
for(int i = 0; i < len; i++)
{
//cout << arr[i] << " ";
bstree->insertNode(arr[i]);
}
bstree->levelOrder();
cout << bstree->searchNode(4)->parent->data << endl;
cout << "\n== 前序遍歷: ";
bstree->preOrder();
cout << "\n== 中序遍歷: ";
bstree->inOrder();
cout << "\n== 後序遍歷: ";
bstree->postOrder();
cout << "\n== 層次遍歷: ";
bstree->levelOrder();
cout << endl;
cout << "== 最小值: " << bstree->minMem() << endl;
cout << "== 最大值: " << bstree->maxMem() << endl;
cout << "\n== 刪除節點: " <<