王道——数据结构——树与二叉树(2)

系列文章目录

其他章节相关文章

王道——数据结构——栈和队列(1)

本章节其他相关文章

王道——数据结构——树与二叉树(1)
王道——数据结构——树与二叉树(3)
王道——数据结构——树与二叉树(4)


文章目录

  • 系列文章目录
    • 其他章节相关文章
    • 本章节其他相关文章
  • 前言
  • 一、5.2节
  • 二、5.3节
    • 后续部分留在下一章


前言

本文为王道数据结构的第五章——树与二叉树的编程题。
运行软件:vscode
使用c++文件编写
本文所使用的树为《王道——数据结构——树与二叉树(1)》中建立的树


一、5.2节

5、已知一棵二叉树按顺序存储结构进行存储,设计一个算法,求编号分别为i和j的两个结点的最近公共祖先结点。
已知顺序结构存储的树的结构,所以父节点为孩子结点下标除2下取整,所以在寻找i和j的两个结点的最近公共祖先结点时,比较i和j,如果i=j:返回i的值,如果i>j:求i的父节点,如果i

// 找编号i和j的最近公共祖先 找序号大的父节点
int test1(TreeNode T[MaxSize], int i, int j){
    if(T[i].isEmpty != true && T[j].isEmpty != true){    
        while(i != j){
            if(i>j)
                i/2;  // 找i的父节点
            else
                j/2;  // 找j的父节点
        }
        return i;
    }
    return -1;

	// 运行代码
	// int i, j;
    // TreeNode T[MaxSize];
    // InitTree(T);
    // buildTree(T, 1);
    // Preorder(T, 1);
    // printf("\n请输入你想查找的两个编号(使用空格分隔):");
    // scanf("%d %d", &i, &j);
    // i= test1(T, i, j);
    // if (i != -1)
    //     printf("编号%d的结点值为%d", i, T[i].value);
    // else
    //     printf("输入编号错误,为空结点");
}

二、5.3节

3、编写后序二叉树的非递归算法。
王道——数据结构——树与二叉树(1)中已经写过,详情请参考
王道——数据结构——树与二叉树(1)

4、试给出二叉树自上而下、自右向左的层次遍历

// 第四题 层次遍历,使用队列实现,先将右孩子压入队中
void test4(){
    BiTree T;
    InitBiTree(T);
    buildTree(T);
    LinkQueue S;
    InitLinkQueue(S);
    EnQueue(S, T);
    BiTNode *x;
    while(S.front != NULL){
        DeQueue(S, x);
        visit(x);
        if(x->rchild != NULL)
            EnQueue(S, x->rchild);
        if(x->lchild != NULL)
            EnQueue(S, x->lchild);
    }
}

5、假设二叉树采用二叉链表存储结构,设计一个非递归算法求二叉树的高度。

// 第五题 使用栈存储树结点,采用深度优先策略,入栈高度加一,出栈高度减一,highest保存当前高度最高值
// 同第三题, 使用栈实现非递归中序遍历
// 好像有bug,还未完善
void test5(){
    BiTree T;
    InitBiTree(T);
    buildTree(T);
    LinkStack S;
    InitLinkStack(S);
    if(T == NULL)
        printf("树高度为0\n");
    else{
        int high = 0, highest = 0;
        BiTNode *p = T;
        while(p || S != NULL){
            if(p){
                Push(S, p);
                p = p->lchild;
                ++high;
                if(high > highest)
                    highest = high;
            }
            else{
                Pop(S, p);
                if(p->rchild == NULL)
                    --high;
                p = p->rchild;
            }
        }
        printf("树高度:%d ", highest);
    }
}


// 第五题——王道书的方法,使用一个指针last指向下一层最左边的元素,如果队首元素等于last,层数加1
// 队尾元素永远是下一层的最后一个元素
// 找树最大宽度
void test5_2(){
    BiTree T;
    InitBiTree(T);
    buildTree(T);
    LinkQueue Q;
    InitLinkQueue(Q);
    if(T == NULL)
        printf("书高度:0");
    else{
        int weigh = 1, weightest = 0;
        BiTNode *p, *last = T;
        EnQueue(Q, T);
        while (Q.front->next != NULL){
            DeQueue(Q, p);
            ++weigh;
            if(p->lchild != NULL)
                EnQueue(Q, p->lchild);
            if(p->rchild != NULL)
                EnQueue(Q, p->rchild);
            if(p == last && Q.front->next != NULL){
                if(weigh > weightest)
                    weightest = weigh;
                weigh = 0;
                last = Q.rear->data;
            }
        }
        printf("树最大宽度:%d ", weightest);
    }
}

6、设一棵二叉树中各结点的值互不相同,其先序遍历和中序遍历分别存于两个一维数组A[1……n]和B[1……n]中,试编写算法建立该算法的二叉树和二叉链表

// 第六题,为了之后测试程序,要建立数组A、B 
#define MaxSize 20

// 数组结构
typedef struct{
    int data[MaxSize];  
    int len;    //记录数组长度
}arr;

// 初始化数组
void Initarr(arr &arry){
    arry.len = 0;
}

// 建立二叉链表
BiTNode *arr_tree(arr arr1, arr arr2){
    if(arr2.len == 1){
        BiTNode *q = (BiTNode *)malloc(sizeof(BiTNode));
        q->data.value = arr2.data[0];
        q->lchild = NULL;
        q->rchild = NULL;
        return q;

    }
    int first;
    for (int i = 0; i<arr1.len; i++){
        for(first = 0; first<arr2.len; first++){
            if(arr1.data[i] == arr2.data[first])
                break;
        }
        if(arr1.data[i] == arr2.data[first])
            break;
    }
    BiTNode *p = (BiTNode *)malloc(sizeof(BiTNode));
    p->data.value = arr2.data[first];
    arr arr3, arr4;
    Initarr(arr3);
    Initarr(arr4);
    for(int i = 0; i<first; i++){
        arr3.data[i] = arr2.data[i];
        ++arr3.len;
    }
    int arr2_now = first;
    for(int i = 0; i<arr2.len-first-1; i++){
        arr4.data[i] = arr2.data[++arr2_now];
        ++arr4.len;
    }
    if(arr3.len!=0)
        p->lchild = arr_tree(arr1, arr3);
    else
        p->lchild = NULL;
    if(arr4.len != 0)
        p->rchild = arr_tree(arr1, arr4);
    else 
        p->rchild = NULL;
    return p;

}

// 运行实现
void test6(){
    arr arr1,arr2;
    Initarr(arr1);
    Initarr(arr2);
    int x, i = 0;
    // 建立A数组
    printf("请输入先序序列顺序(9999退出):");
    scanf("%d", &x);
    while(x != 9999 &&arr1.len < MaxSize){
        arr1.data[i++] = x;
        ++arr1.len;
        printf("输入成功,请继续输入(9999退出):");
        scanf("%d", &x);
    }
    // 建立B数组
    printf("请输入先中序列顺序(9999退出):");
    scanf("%d", &x);
    i = 0;
    while(x != 9999 &&arr2.len < MaxSize){
        arr2.data[i++] = x;
        ++arr2.len;
        printf("输入成功,请继续输入(9999退出):");
        scanf("%d", &x);
    }
    BiTree T;
    T = arr_tree(arr1, arr2);
    printf("后序遍历结果为:");  // 用后序遍历查看树
    PostOrder(T);
}

7、二叉树按二叉链表形式存储,写一个判别给定的二叉树是否是完全二叉树的算法。


// 第七题 判别方法——使用层次遍历,当出现一个结点的孩子为空时,后面的结点都不能有孩子
void test7(){
    BiTree T;
    InitBiTree(T);
    buildTree(T);
    BiTNode *p;
    int arise = 0;  // 标记是否出现孩子为空的结点
    LinkQueue Q;
    InitLinkQueue(Q);
    EnQueue(Q, T);
    while(Q.front->next != NULL){
        DeQueue(Q, p);
        if(arise == 0 && p->lchild != NULL)  // 前面结点均有左右孩子,并且该结点左孩子不为空
            EnQueue(Q, p->lchild);
        else if(arise == 1 && p->lchild != NULL)  // 已经出现孩子为空的结点,该结点仍有左孩子,所以不是完全二叉树
            break;
        else  // 前面结点均有左右孩子,但是该结点左孩子为空, 标记位改为1
            arise = 1 ;
        if(arise == 0 && p->rchild != NULL)
            EnQueue(Q, p->rchild);
        else if(arise ==1 &&p->rchild != NULL)
            break;
        else 
            arise = 1;
    }
    if(Q.front->next != NULL)
        printf("不是完全二叉树");
    else    
        printf("是完全二叉树");
}

8、假设二叉树采用二叉链表存储结构存储,试设计一个算法,计算一棵给定二叉树的双分支结点个数。

// 第八题 采用非递归先序遍历,在访问节点时判断是否有左右孩子,如果有,总数加一
void test8(){
    BiTree T;
    InitBiTree(T);
    buildTree(T);
    LinkStack S;
    InitLinkStack(S);
    BiTNode *p = T;
    int sum = 0;
    while(p || S != NULL){
        if(p){
            Push(S, p);
            if(p->lchild != NULL && p->rchild != NULL)
                ++sum;
            p = p->lchild;
        }
        else{
            Pop(S, p);
            p = p->rchild;
        }
    }
    printf("双分支结点个数为:%d", sum);
}

9、设树B是一棵采用链式结构存储的二叉树,编写一个把树B中所有结点的左右孩子进行交换的函数。

// 第九题 从最上层开始交换左右子树, 使用队列进行层次遍历,出队对结点访问时,交换结点左右孩子顺序,使用中序遍历验证,二者顺序刚好相反
void test9(){
    BiTree T;
    InitBiTree(T);
    buildTree(T);
    InOrder(T);
    LinkQueue Q;
    InitLinkQueue(Q);
    EnQueue(Q, T);
    BiTNode *temp, *p;
    while(Q.front->next != NULL){
        DeQueue(Q, p);
        temp = p->lchild;
        p->lchild = p->rchild;
        p->rchild = temp;
        if(p->lchild != NULL)
            EnQueue(Q, p->lchild);
        if(p->rchild != NULL)
            EnQueue(Q, p->rchild);
    }
    printf("\n");
    InOrder(T);
}

10、假设二叉树采用二叉链表存储结构存储,设计一个算法,求先序遍历序列中第k(k>=1 && k<=二叉树中结点个数)

// 使用先序序列遍历二叉树,对结点访问时计数,当访问到第k个结点时,返回第k个结点的值
void test10(BiTree T, int k, int &sum, int &value){
    ++sum;
    if(sum == k )
        value = T->data.value;
    if(sum != k && T->lchild != NULL)
        test10(T->lchild, k, sum, value);
    if(sum != k && T->rchild != NULL)
        test10(T->rchild, k, sum, value);

    // 运行代码
    // BiTree T;
    // InitBiTree(T);
    // buildTree(T);
    // int x, sum = 0, value;
    // printf("请输入你想查找的结点位序(从1开始):");
    // scanf("%d", &x);
    // test10(T, x, sum, value);
    // if(sum == x)
    //     printf("第%d个结点值为:%d", x, value);
    // else
    //     printf("输入位序无效");
}

后续部分留在下一章

你可能感兴趣的:(数据结构,数据结构,算法,链表)