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

二叉树算法习题:

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值