二叉树中的查找操作(按值查找按位查找)

Posted 薛定谔的猫ovo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉树中的查找操作(按值查找按位查找)相关的知识,希望对你有一定的参考价值。


按值查找

查找元素值为x的结点并删除以其为根的子树

题目描述:
 已知二叉树以二叉链表存储,请编写一个算法:对于树中每个元素值为x的结点,删去以它为根的子树,并释放相应的空间。

算法思想:
 删除以元素值x为根的子树,只要能删除其左右子树,就可以释放值为x的结点,故采用后序的方式实现。
 删除值为x的结点,意味着应将其父结点的左(右)子女指针置空,用层次遍历易于找到某结点的父结点。
 要求删除树中每个元素值为x的结点的子树,故要遍历完二叉树的所有结点。

实现代码:

void DeleteXTree(BNode *bt){ //删除以bt为根的子树
    if(bt != NULL){
        DeleteXTree(bt->lchild);
        DeleteXTree(bt->rchild);
        free(bt);
    }
}

//在二叉树上所有以x为元素值的结点,并删除以其为根的子树
void SearchX(BNode *root, char x){
    queue<BNode *> treenode; //存放二叉树结点指针
    if(root != NULL){
        if(root->data == x){ //若根结点值为x,则删除整棵树
            DeleteXTree(root);
        }
        treenode.push(root); //根结点入队
        while(!treenode.empty()){
            BNode *p = treenode.front();
            treenode.pop(); //队首元素出队
            if(p->lchild != NULL){ //若左子树非空
                if(p->lchild->data == x){
                    DeleteXTree(p->lchild);
                    p->lchild = NULL; //父结点的左子女置空
                }else{
                    treenode.push(p->lchild); //左子树的根结点入队
                }
            }//if
            if(p->rchild != NULL){
                if(p->rchild->data == x){
                    DeleteXTree(p->rchild);
                    p->rchild = NULL;
                }else{
                    treenode.push(p->rchild);
                }
            }//if
        }//while
    }
}

 在这里给出完整代码,建树使用扩展二叉树的遍历序列,为了验证删除结点后的二叉树,在执行完删除操作后,对删除后的二叉树进行层序遍历。

#include<bits/stdc++.h>
using namespace std;

typedef struct BNode{
    char data;
    struct BNode *lchild;
    struct BNode *rchild;
}BNode;

//扩展二叉树的先序遍历序列
void BuildTree_Pre(BNode * & root, char pre[], int & i){
    if(pre[i] == '#'){ //外结点,即空结点
        i++;
        root = NULL;
    }else{
        root = (BNode *)malloc(sizeof(BNode)); //建立根结点
        root->data = pre[i];
        i++;
        BuildTree_Pre(root->lchild, pre, i); //递归建立左子树
        BuildTree_Pre(root->rchild, pre, i); //递归建立右子树
    }
}

void DeleteXTree(BNode *bt){ //删除以bt为根的子树
    if(bt != NULL){
        DeleteXTree(bt->lchild);
        DeleteXTree(bt->rchild);
        free(bt);
    }
}

//在二叉树上所有以x为元素值的结点,并删除以其为根的子树
void SearchX(BNode *root, char x){
    queue<BNode *> treenode; //存放二叉树结点指针
    if(root != NULL){
        if(root->data == x){ //若根结点值为x,则删除整棵树
            DeleteXTree(root);
        }
        treenode.push(root); //根结点入队
        while(!treenode.empty()){
            BNode *p = treenode.front();
            treenode.pop(); //队首元素出队
            if(p->lchild != NULL){ //若左子树非空
                if(p->lchild->data == x){
                    DeleteXTree(p->lchild);
                    p->lchild = NULL; //父结点的左子女置空
                }else{
                    treenode.push(p->lchild); //左子树的根结点入队
                }
            }//if
            if(p->rchild != NULL){
                if(p->rchild->data == x){
                    DeleteXTree(p->rchild);
                    p->rchild = NULL;
                }else{
                    treenode.push(p->rchild);
                }
            }//if
        }//while
    }
}

void LevelOrder(BNode *root){
    queue<BNode *> treenode; //队列存储结点
    if(root != NULL)
        treenode.push(root); //根结点入队
    while(!treenode.empty()){
        BNode *p = treenode.front(); 
        treenode.pop(); //根结点出队
        printf("%c ",p->data); //输出队首元素,即当前访问的结点值
        if(p->lchild != NULL){
            treenode.push(p->lchild);//如果有左子树,则将左子树的根结点入队
        }
        if(p->rchild != NULL){
            treenode.push(p->rchild);//如果有右子树,则将右子树的根结点入队
        }
    }
}

int main(){
    BNode *root;
    char pre[100];
    scanf("%s",pre);
    int i=0;
    BuildTree_Pre(root, pre, i);
    SearchX(root, 'E');
    LevelOrder(root);
    
    return 0;
}

使用的二叉树:

执行结果:



查找值为x的结点并打印其所有祖先

题目描述:
 在二叉树中查找值为x的结点,试编写算法打印值为x的结点的所有祖先,假设值为x的结点不多于一个。

算法思想:
 采用非递归的后序遍历,最后访问根结点,访问到值为x的结点时,栈中所有元素均为该结点的祖先,依次出栈打印即可。关于后序遍历的非递归算法,请参照详解二叉树的遍历问题(前序、后序、中序、层序遍历的递归算法及非递归算法及其详细图示)

实现代码:

void Search(BTree root, char x){
    BNode *p = root;
    BNode *top, *last;
    stack<BNode *> treenode;
    while(p || !treenode.empty()){
        if(p != NULL){ //找到最左边的结点
            treenode.push(p);
            p = p->lchild;
        }else{
            top = treenode.top();
            if(top->data == x){
                printPath(treenode);
                return;
            }else{
                if(top->rchild == NULL || top->rchild == last){ //右子树为空或已经访问过
                    treenode.pop(); 
//                     cout<<top->data<<" ";
                    last = top;
                    p = NULL;
                }else{
                    p = top->rchild;
                    treenode.push(p);
                    p = p->lchild;
                }
            }
        }
    }
}

运行结果:
依旧使用第一个题的二叉树,查找结点G的所有祖先:



按位查找

求先序遍历序列中第k个结点的值

题目描述:
 设二叉树采用二叉链表存储,设计一个算法,利用二叉树的先序遍历求先序遍历序列的第k(1 ≤ k ≤ 二叉树结点个数)个结点。

算法思想:
 在先序遍历算法中加入计数器count,在访问结点的同时统计访问的序号。需要注意的是,算法中不要直接引用全局变量count,而应通过参数表显式传递count,这样能实现算法的复用。

实现代码:

BNode *PreSearchX(BTree root, int k, int &count){
    if(root != NULL){
        if(count == k) return root;
        count++;
        BNode *p = PreSearchX(root->lchild, k, count); //到左子树查找
        if(p!=NULL) return p;
        else return PreSearchX(root->rchild, k, count); //否则到右子树查找
    }else{
        return NULL;
    }
}

运行结果:
依旧使用第一个题的二叉树,查找先序遍历序列中第四个结点值。



求中序遍历序列中第k个结点的值

题目描述:
 设二叉树采用二叉链表存储,设计一个算法,利用二叉树的中序遍历求中序遍历序列的第k(1 ≤ k ≤ 二叉树结点个数)个结点。

算法思想:
 在中序遍历算法中加入计数器count,在访问结点的同时统计访问的序号。需要注意的是,算法中不要直接引用全局变量count,而应通过参数表显式传递count,这样能实现算法的复用。

实现代码:

BNode *InSearchX(BTree root, int k, int &count){
    if(root == NULL) return NULL;
    BNode *p = InSearchX(root->lchild, k, count);
    if(p != NULL)  return p;
    else{
        if(count == k) return root;
        count++;
        return InSearchX(root->rchild, k, count);
    }
}

运行结果:
依旧使用第一个题的二叉树,查找中序遍历序列中第四个结点值。



求后序遍历序列中第k个结点的值

题目描述:
 设二叉树采用二叉链表存储,设计一个算法,利用二叉树的后序遍历求后序遍历序列的第k(1 ≤ k ≤ 二叉树结点个数)个结点。

算法思想:
 在后序遍历算法中加入计数器count,在访问结点的同时统计访问的序号。需要注意的是,算法中不要直接引用全局变量count,而应通过参数表显式传递count,这样能实现算法的复用。

实现代码:

BNode *PostSearchX(BTree root, int k, int &count){
    if(root == NULL) return NULL;
    BNode *p = PostSearchX(root->lchild, k, count);
    if(p != NULL) return p;
    else{
        p = PostSearchX(root->rchild, k, count);
        if(p != NULL) return p;
        if(count == k) return root;
        count++;
        return NULL;
    }
}

运行结果:
依旧使用第一个题的二叉树,查找后序遍历序列中第四个结点值。


完整可运行代码可在我的资源中免费下载。
持续更新中。。。如有错误,欢迎指正。

以上是关于二叉树中的查找操作(按值查找按位查找)的主要内容,如果未能解决你的问题,请参考以下文章

二叉查找树中元素的删除操作

C++二叉树的实现

二叉树(下)

在二叉树中查找给定节点的祖先

使用C在搜索二叉树中查找最长路径

二叉树查找