目录
二叉搜索树是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根节点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉搜索树。
二叉搜索树作为一种经典的数据结构,它既有链表的快速插入与删除操作的特点,又有数组快速查找的优势;所以应用十分广泛,例如在文件系统和数据库系统一般会采用这种数据结构进行高效率的排序与检索操作。
1.定义树的结构体:
typedef struct TreeNode* TNP;
struct TreeNode {
int data;
TNP left;
TNP right;
};
2.插入操作:
GetNode函数是给指定元素创建一个新结点,便于插入树中。
Insert函数当树为空, 创建根节点;如果根节点元素比指定元素大,递归操作到左子树进行插入,如果根节点元素比指定元素小,递归操作到右子树进行插入。
TNP GetNode(int x) {
TNP s = (TNP)malloc(sizeof(TNP));
s->data = x;
s->left = s->right = NULL;
return s;
}
TNP Insert(TNP root, int x) {
if (root == NULL) {
root = GetNode(x);
}
else if (root->data >= x) {
root->left = Insert(root->left, x);
}
else {
root->right = Insert(root->right, x);
}
return root;
}
3.查询指定元素是否在树内:
如果为空树,直接返回false;如果根节点元素比指定元素大,递归操作到左子树进行查询;
如果根节点元素比指定元素小,递归操作到右子树进行查询。
bool Serch(TNP root,int data){
if(root==NULL)return false;
else if(root->data==data)return true;
else if(root->data>=data)return Serch(root->left,data);
else return Serch(root->right,data);
}
4.搜索树中最值:
如果是空树,直接提示搜索失败;
Serch_Min函数:找到根节点左子树的最小叶结点并返回;
Serch_Max函数:找到根节点右子树的最大叶结点并返回;
int Serch_Min(TNP root){
if(root==NULL){
cout<<"The tree is empty"<<endl;
return -1;
}else{
TNP temp=root;
while(temp->left!=NULL)temp=temp->left;
return temp->data;
}
}
int Serch_Max(TNP root){
if(root==NULL){
cout<<"The tree is empty"<<endl;
return -1;
}else{
TNP temp=root;
while(temp->right!=NULL)temp=temp->right;
return temp->data;
}
}
5.计算树的高度&深度:
PS:
深度是指从根节点到该节点的最长简单路径边的条数;
高度是指从最下方的叶节点到该节点的最长简单路径边的条数;
int FindHeight(TNP root) {
if (root == NULL)return -1;
return max(FindHeight(root->left), FindHeight(root->right)) + 1;
}
int Deep(TNP root,int num)
{
if(root){
num++;
return max(Deep(root->left,num),Deep(root->right,num));
}
else return num;
}
6.层序遍历:广度优先(借助队列实现)
开一个队列,将根节点入队,进入循环:对队头结点进行操作后出队,并将左右子树的根节点入队。
//层序遍历 breadth-first;by queue
void LevelOrderTraversal(TNP root) {
if (root == NULL)return;
queue<TNP>q;
q.push(root);
while (!q.empty()) {
TNP temp = q.front();
cout << temp->data << " ";
if (temp->left)q.push(temp->left);
if (temp->right)q.push(temp->right);
q.pop();
}
cout << endl;
}
图示:
7.前中后序遍历:深度优先(借助递归实现)
图示:
前序:先访问根节点,再访问左子树,最后访问右子树(所谓前中后即访问根节点的时序)
中序:
先访问左子树,再访问根节点,最后访问右子树;
后序:
先访问左子树,再访问右子树,最后访问根节点;
代码实现:
//前中后序遍历 depth-first;
//前序遍历:
void PreOrderTraversal(TNP root) {
if (root == NULL)return;
cout << root->data << " ";
PreOrderTraversal(root->left);
PreOrderTraversal(root->right);
}
//中序遍历:
void InOrderTraversal(TNP root) {
if (root == NULL)return;
InOrderTraversal(root->left);
cout << root->data << " ";
InOrderTraversal(root->right);
}
//后序遍历
void PostOrderTraversal(TNP root) {
if (root == NULL)return;
PostOrderTraversal(root->left);
PostOrderTraversal(root->right);
cout << root->data << " ";
}
8.判断一棵树是否为二叉搜索树:
思路:判断结点是否在指定范围内;
根节点范围:(INT_MIN,INT_MAX);
左子树范围:(INT_MIN,根节点);右子树范围:(根节点,INT_MAX);
如此递归,如果所有结点满足条件则为二叉搜索树。
//判断是否为二叉搜索树
bool IsBST(TNP root, int maxrange, int minrange) {
if (root == NULL)return true;
if (root->data<maxrange && root->data>minrange
&& IsBST(root->left, root->data, minrange)
&& IsBST(root->right, maxrange, root->data))
return true;
else return false;
}
9.删除一个结点:
Find_Min函数:找到root树的最小叶节点;
分三种情况:
case 1:要删除的结点为叶节点:直接释放该结点;
case 2:要删除的结点只有一个子树:令要删除的结点的父结点与该节结点的子树根结点建立链接,释放该结点;
case 3:要删除的结点有两个子树:找到该结点右子树的最大叶结点,替换该结点,然后简化为case 2的情况。
//删除一个节点
//case1:叶节点
//case2:只有一个子树
//case3:有俩子树(找右子树的最大值,然后替换欲删除的结点,然后退回case2进行处理)
TNP Find_Min(TNP root) {
if (root == NULL)return root;
TNP temp = root;
while (temp->left != NULL)temp = temp->left;
return temp;
}
TNP Delete(TNP root, int data) {
if (root == NULL)return root;
else if (root->data > data)root->left = Delete(root->left, data);
else if (root->data < data)root->right = Delete(root->right, data);
else {
//case1:
if (root->left == NULL && root->right == NULL) {
delete root;
root = NULL;
}
//case2:
else if (root->left == NULL) {
TNP temp = root;
root = root->right;
delete temp;
}
else if (root->right == NULL) {
TNP temp = root;
root = root->left;
delete temp;
}
//case3:
else {
TNP temp = Find_Min(root);
root->data = temp->data;
root->right = Delete(root->right, temp->data);
}
}
return root;
}
10.搜索一个结点的中序后继结点:
Find函数:找到指定元素所在结点。
Search_InSuccessor函数:如果为空树,返回NULL;
case 1:该结点有右子树:搜索该结点右子树的最小叶结点,返回;
case 2:该结点无右子树:搜索该结点最近的且没被访问过的父结点,返回。
TNP Find(TNP root, int data) {
if (root == NULL)return root;
else if (root->data == data)return root;
else if (root->data > data)return Find(root->left, data);
else return Find(root->right, data);
}
TNP Search_InSuccessor(TNP root, int data) {
TNP temp = Find(root, data);
if (temp == NULL)return root;
if (temp->right != NULL)return Find_Min(temp->right);
else {
TNP successor = NULL, ancestor = root;
while (temp != ancestor) {
if (temp->data < ancestor->data) {
successor = ancestor;
ancestor = ancestor->left;
}
else {
ancestor = ancestor->right;
}
}
return successor;
}
}