【数据结构X.3】先序遍历序列第k节点值,删去以x为根的子树,最近的公共祖先节点,非空二叉树的宽度,求解后序序列,叶子节点按从左到右的顺序连成一个单链表,递归非递归

32 篇文章 0 订阅
16 篇文章 1 订阅

二叉树算法习题:

1.设计算法,求解先序遍历序列第k(1<=k<=n)个节点的值

int getKNodeVal(BiTree tr, int k)

2.对于树中每个元素为x的节点,删去以它为根的子树,释放相应的空间

BiTree DeleteValX(BiTree tr, char x)

3. p和q分别为指向二叉树中的任意两个节点的值,其中数值不会重复,找到离p和q最近的公共祖先节点

BiNode *FindAncestor(BiTree tr, char p, char q)

4.求非空二叉树b的宽度:具有节点数目最多的那一层的节点个数

int GetTreeWidth(BiTree tr)

5.假设一颗满二叉树,所有节点都不同,已知先序序列是pre,设计算法求解后序序列post

void GetPostLine(int pre[], int h1, int t1, int post[], int h2, int t2)

6.1.非递归,设计算法将二叉树的叶子节点按从左到右的顺序连成一个单链表,表头指针为head,二叉树按照二叉链表方式存储,链接时,用叶节点的右指针域来存放单链表指针

BiTree TransToLinkList(BiTree tr)

7.第6题的递归算法:只有这样从下向上的计算,才能保证头指针是head,而且能正常访问子节点

BiNode *InOrder(BiTree tr)

函数调用:

BiTree_use.cpp
  int A[9] = {'1', '2', '3', '4', '5', '6', '7', '8'};
    int B[9] = {'4', '3', '2', '5', '1', '7', '6', '8'};
    BiTree tr2 = BuildTreeBeforeAndIn(A, B, 0, 7, 0, 7);
    int k = 5;
    std::cout << "先序遍历序列中第" << k << "个值为:" << char(getKNodeVal(tr2, k)) << std::endl;
    //char ch = '2';
    //tr2 = DeleteValX(tr2, ch);
    //VisitTreeAfter(tr2);
    char ch1 = '5';
    char ch2 = '4';
    std::cout << char(ch1) << "和" << char(ch2) << "的公共节点是" << char(FindAncestor(tr2, ch1, ch2)->data) << std::endl;
    std::cout << "树的最大宽度是:" << GetTreeWidth(tr2) << std::endl;
    int C[7]={0,1,3,4,2,5,6};
    int D[7]={0};  
    GetPostLine(C,0,6,D,0,6); //设计算法求解满二叉树的后序序列post
    for(int i=0;i<7;i++){
        std::cout<<D[i]<<" ";
    }
    std::cout << std::endl;
    BiNode* link= InOrder(tr2);
    BiNode*iter=link;
    while(iter){
        std::cout<<char(iter->data)<<" " ;
        iter=iter->rchild;
    }
    
BiTree.h

/***
 * 二叉树各个值不同,先序和中序遍历序列分别存于数组A[1..n],B[1....n]中,
 * 算法建立该二叉树链表
 */
BiTree BuildTreeBeforeAndIn(int A[], int B[], int h1, int t1, int h2, int t2)
{
    BiNode *root = (BiNode *)malloc(sizeof(BiNode));
    root->data = A[h1]; //找到根节点
    //std::cout << root->data << " ";
    int i;
    for (i = h2; B[i] != A[h1]; i++)
        ;
    int llen = i - h2; //以根为中间节点,划分左右
    int rlen = t2 - i;
    //std::cout << llen << " " << rlen << " " << std::endl;
    if (llen != 0)
        root->lchild = BuildTreeBeforeAndIn(A, B, h1 + 1, h1 + llen, h2, h2 + llen - 1);
    else
        root->lchild = NULL;
    if (rlen != 0)
        root->rchild = BuildTreeBeforeAndIn(A, B, h1 + llen + 1, t1, h2 + llen + 1, t2);
    else
        root->rchild = NULL;
    return root;
}

/**
 * 设计算法,求解先序遍历序列仲第k(1<=k<=n)个节点的值
 */
int getKNodeVal(BiTree tr, int k)
{
    std::stack<BiNode *> s;
    BiNode *p = tr;
    int i = 0;
    while (!s.empty() || p)
    {
        if (p)
        {
            i += 1;
            if (i == k)
                return p->data;
            s.push(p);
            p = p->lchild;
        }
        else
        {
            p = s.top();
            s.pop();
            p = p->rchild;
        }
    }
    return -1;
}

/**
 * 对于树中每个元素为x的节点,删去以它为根的子树,释放相应的空间
 */
BiTree DeleteValX(BiTree tr, char x)
{
    if (tr->data == x)
        return NULL;
    std::stack<BiNode *> s; //后序遍历的时候,栈顶的元素是这个节点的根节点
    BiNode *p = tr, *r = NULL;
    while (p || !s.empty())
    {
        if (p)
        {
            s.push(p);
            p = p->lchild;
        }
        else
        {
            p = s.top();
            if (p->rchild && p->rchild != r) //有右子节点且右子节点没有被访问过
            {
                p = p->rchild;
                s.push(p);
                p = p->lchild;
            }
            else
            {
                p = s.top();
                s.pop();
                std::cout << "正在访问节点" << char(p->data) << std::endl;
                if (p->data == x)
                {
                    std::cout << "正在删除节点" << x << std::endl;
                    BiNode *tmp = s.top();
                    if (tmp)
                    {
                        if (tmp->rchild->data == p->data)
                        {
                            std::cout << "正在删除右边的节点" << tmp->rchild << std::endl;
                            tmp->rchild = NULL;
                        }
                        else if (tmp->lchild->data == p->data)
                        {
                            std::cout << "正在删除左边的节点" << tmp->lchild << std::endl;
                            tmp->lchild = NULL;
                        }
                    }
                }
                r = p;
                p = NULL;
            }
        }
    }
    return tr;
}

/***
 * p和q分别为指向二叉树中的任意两个节点的值,其中数值不会重复
 * 找到离p和q最近的公共祖先节点
 */
BiNode *FindAncestor(BiTree tr, char p, char q)
{
    BiNode *tmp = tr, *r = NULL;
    std::stack<BiNode *> s;
    bool findp = false;
    bool findq = false;
    while (!s.empty() || tmp)
    {
        if (tmp)
        {
            s.push(tmp);
            tmp = tmp->lchild;
        }
        else
        {
            tmp = s.top();
            if (tmp->rchild && tmp->rchild != r)
            {
                tmp = tmp->rchild;
                s.push(tmp);
                tmp = tmp->lchild;
            }
            else
            {
                tmp = s.top();
                s.pop();
                if (tmp->data == p)
                {
                    findp = true;
                }
                if (tmp->data == q)
                {
                    findq = true;
                }

                if (findp && findq)
                    return s.top();
                r = tmp;
                tmp = NULL;
            }
        }
    }
    return NULL;
}

/**
 * 求非空二叉树b的宽度:具有节点数目最多的那一层的节点个数
 */
int GetTreeWidth(BiTree tr)
{
    //思路:层次遍历
    std::queue<BiNode *> q;
    BiNode *p = tr, *mark = tr;
    int width = 0;
    int maxWidth = 0;
    q.push(p);
    while (!q.empty())
    {
        width += 1;
        p = q.front();
        q.pop();
        if (p)
        {
            if (p->lchild)
                q.push(p->lchild);
            if (p->rchild)
                q.push(p->rchild);
        }

        if (p->data == mark->data)
        {
            //std::cout << "当前层宽度是:" << width << std::endl;
            maxWidth = std::max(width, maxWidth);
            mark = q.back();
            width = 0;
        }
    }
    return maxWidth;
}

/**
 * 假设一颗满二叉树,所有节点都不同,已知先序序列是pre,设计算法求解后序序列post
 */
void GetPostLine(int pre[], int h1, int t1, int post[], int h2, int t2)
{
    //满二叉树,所以层上是满的
    int half;
    if (t1 >= h1)
    {
        post[t2] = pre[h1];
        half = (t1 - h1) / 2;
        GetPostLine(pre, h1 + 1, h1 + half, post, h2, h2 + half - 1);
        GetPostLine(pre, h1 + 1 + half, t1, post, h2 + half, t2 - 1);
    }
}

/**
 * 1.非递归
 * 设计算法将二叉树的叶子节点按从左到右的顺序连成一个单链表,表头指针为head
 * 二叉树按照二叉链表方式存储,链接时,用叶节点的右指针域来存放单链表指针
 */
BiTree TransToLinkList(BiTree tr)
{
    //需要判断是否是叶节点
    BiNode *head = (BiNode *)malloc(sizeof(BiNode));
    head->data = tr->data;
    BiNode *p = tr, *next = head;

    std::stack<BiNode *> s;
    while (p || !s.empty())
    {
        if (p)
        {
            if (!p->lchild && !p->rchild) //都为空,是叶子节点
            {
                std::cout << "找到了叶子节点: " << char(p->data) << std::endl;
                next->rchild = p;
                next = next->rchild;
            }
            s.push(p);
            p = p->lchild;
        }
        else
        {
            p = s.top();
            s.pop();
            p = p->rchild;
        }
    }
    next->rchild = NULL;
    tr= head->rchild;
    return tr;
}

/**
 * 2.递归算法:
 * 设计算法将二叉树的叶子节点按从左到右的顺序连成一个单链表,表头指针为head
 * 二叉树按照二叉链表方式存储,链接时,用叶节点的右指针域来存放单链表指针
 * 
 * 只有这样从下向上的计算,才能保证头指针是head,而且能正常访问子节点
 */
BiNode *head, *pre = NULL;
BiNode *InOrder(BiTree tr)
{
    if (tr)
    {
        InOrder(tr->lchild);
        if (tr->lchild == NULL && tr->rchild == NULL)
        {
            if (pre == NULL)
            {
                head = tr;
                pre = tr;
            } //处理第一个叶节点
            else
            {
                pre->rchild = tr;
                pre = tr;
            }
        }
        InOrder(tr->rchild);
        pre->rchild = NULL; //设置链表尾部
    }
    return head;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现这个功能,可以采用二叉搜索树的特性,即左子树中所有节点小于根节点,右子树中所有节点大于根节点。因此,在先序遍历序列中,根节点必定是序列的第一个元素。 具体的实现步骤如下: 1. 定义一个二叉树的结构体,包含键和左右子节点指针。 2. 定义一个函数,输入先序遍历序列序列长度,返回根节点。 3. 从先序遍历序列中取出第一个元素作为根节点。 4. 遍历序列,将小于根节点的元素放入左子树序列,大于根节点的元素放入右子树序列。 5. 递归创建左右子树,并将左右子树的根节点分别挂在根节点的左右子节点上。 6. 采用递归的方式遍历二叉树,查找节点U和V的位置。 7. 如果当前节点为NULL或者等于U或V,则返回当前节点。 8. 如果U和V分别在当前节点的左右子树中,则当前节点最近公共祖先。 9. 如果U和V在当前节点的同一子树中,则继续向下递归。 10. 最终返回最近公共祖先节点的键即可。 下面是实现代码的示例: ```c #include <stdio.h> #include <stdlib.h> typedef struct Node { int key; struct Node* left; struct Node* right; } Node; Node* create_bst(int* preorder, int len) { if (len == 0) { return NULL; } Node* root = (Node*) malloc(sizeof(Node)); root->key = preorder[0]; int i; for (i = 1; i < len; i++) { if (preorder[i] > root->key) { break; } } root->left = create_bst(preorder + 1, i - 1); root->right = create_bst(preorder + i, len - i); return root; } Node* find_lca(Node* root, int u, int v) { if (root == NULL || root->key == u || root->key == v) { return root; } if (u < root->key && v < root->key) { return find_lca(root->left, u, v); } else if (u > root->key && v > root->key) { return find_lca(root->right, u, v); } else { return root; } } int main() { int preorder[] = {6, 2, 1, 4, 3, 5, 9, 7, 10}; int len = sizeof(preorder) / sizeof(preorder[0]); Node* root = create_bst(preorder, len); int u = 3, v = 5; Node* lca = find_lca(root, u, v); printf("LCA of %d and %d is %d\n", u, v, lca->key); u = 4, v = 9; lca = find_lca(root, u, v); printf("LCA of %d and %d is %d\n", u, v, lca->key); u = 4, v = 5; lca = find_lca(root, u, v); printf("LCA of %d and %d is %d\n", u, v, lca->key); return 0; } ``` 输出结果如下: ``` LCA of 3 and 5 is 4 LCA of 4 and 9 is 6 LCA of 4 and 5 is 4 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值