数据结构进阶实训九

Data structure advanced training course notes and algorithm exercises

Source Code: https://github.com/MysticalGuest/DataStructure/tree/master/AdvancedJuniorTraining


题目1

建二叉树二叉链表存储
  - 扩展的先序序列(之前采用的方法)
  此次要求:已知两个遍历序列建二叉树(先/中,后/中)
  - 其先、中序遍历序列分别存放在两个数组pre[]和inorder[]中。
  - 其中、后序遍历序列分别存放在两个数组inorder[]和post中。

1.1 算法设计思想

两种建树的思想相同,都是分治的思想;
通过前序遍历,第一个元素就是树的根节点;
然后在重建左子树,找到左子树的根节点,重建右子树,找到右子树的根节点,递归下去;
中序+后续遍历重建树也是如此;
后续序列的最后一个元素就是树的根节点。

1.2 源代码

#include<stdio.h>
#include<Windows.h>

typedef char ElemType;
typedef struct Node{
  ElemType elem;
  struct Node *LChild;
  struct Node *RChild;
}BiTNode, *BiTree;

// 前序+中序重建二叉树
void ReBuildByPreAndInOrder(char *prelist, char *inlist, int len, BiTree *bt){
  if(!prelist || !inlist || len<=0 )    //空树 
    return;
  int i;
  
  // 找到根结点在中序遍历中的位置 
  for(i = 0; i < len; i++){
    if(inlist[i] == prelist[0])     
      break;           
  } 
  
  if(i>=len)
    return;
  
  // 初始化根结点 
  *bt = (BiTNode*)malloc(sizeof(BiTNode));
  if(!bt) // 申请失败
    return;
  (*bt)->LChild = (*bt)->RChild = NULL;
  (*bt)->elem = prelist[0];
  
  // 重建左子树
  ReBuildByPreAndInOrder(prelist+1, inlist, i, &(*bt)->LChild); 
  // 重建右子树 
  ReBuildByPreAndInOrder(prelist+i+1, inlist+i+1, len-i-1, &(*bt)->RChild);
}

// 中序+后序重建二叉树
void ReBuildByInAndPostOrder(char *inlist,char *postlist, int len, BiTree *bt){
  if(!inlist || !postlist || len<=0 )   //空树 
    return;
  int i;
  
  // 找到根结点在中序遍历中的位置 
  for(i = 0; i < len; i++){
    if(inlist[i] == postlist[len-1])      
      break;           
  } 
  
  if(i>=len)
    return;
  
  // 初始化根结点 
  *bt = (BiTNode*)malloc(sizeof(BiTNode));
  if(!bt)
    return;
  (*bt)->LChild = (*bt)->RChild = NULL;
  (*bt)->elem = postlist[len-1];
  
  //重建左子树 
  ReBuildByInAndPostOrder(inlist, postlist, i, &(*bt)->LChild);         
  //重建右子树 
  ReBuildByInAndPostOrder(inlist+i+1, postlist+i, len-i-1, &(*bt)->RChild);
}

void PrintTree(BiTree bt,int nLayer){
  int i;
  if(bt==NULL)
    return;
  PrintTree(bt->RChild,nLayer+1);
  for(i=0;i<nLayer;i++)
    printf(" ");
  printf("%c\n", bt->elem);
  PrintTree(bt->LChild,nLayer+1);
}

void main(){
  char pre[7]={'A', 'B', 'D', 'E', 'C', 'F', 'G'},
    inorder1[7] = {'D', 'B', 'E', 'A', 'F', 'C', 'G'},
    inorder2[9] = {'G', 'D', 'H', 'B', 'A', 'E', 'C', 'I', 'F'},
    post[9] = {'G', 'H', 'D', 'B', 'E', 'I', 'F', 'C', 'A'};
  int i=0;

  /* 前序+中序重建二叉树 */
  printf("Give the preorder and midorder traversal of a binary tree: \nPreorder = ");
  for(i=0; i<7; i++){
    printf("%c  ", pre[i]);
  }
  printf("\nMidorder = ");
  for(i=0; i<7; i++){
    printf("%c  ", inorder1[i]);
  }

  BiTree T1=NULL;
  ReBuildByPreAndInOrder(pre, inorder1, 7, &T1);
  printf("\nThe binary tree constructed by two traversal sequences is: \n");
  PrintTree(T1, 1);
  /* 前序+中序重建二叉树 */

  /* 中序+后序重建二叉树 */
  printf("Give the midorder and postorder traversal of a binary tree: \nMidorder = ");
  for(i=0; i<9; i++){
    printf("%c  ", inorder2[i]);
  }
  printf("\nPostorder = ");
  for(i=0; i<9; i++){
    printf("%c  ", post[i]);
  }

  BiTree T2=NULL;
  ReBuildByInAndPostOrder(inorder2, post, 9, &T2);
  printf("\nThe binary tree constructed by two traversal sequences is: \n");
  PrintTree(T2, 1);
  /* 中序+后序重建二叉树 */

  system("pause");
}

1.3 运行情况截图

DS



题目2

求二叉树中值为x的节点所在的层号。
二叉树bt采用二叉链表存储;
设计一个算法level(bt,x)求二叉树中值为x的节点所在的层号

2.1 算法设计思想

在求二叉树深度算法的基础上改进算法;
在含有目标节点的子树上查找,到达目标节点即结束递归

2.2 源代码

// 算法1
int layer(BiTree bt, char x){
  int cot = 0;
  if(bt==NULL)
    return cot;
  else if(bt->elem==x){
    cot = 1;
    return cot;
  }
  else{
    // printf("layer(bt->LChild, x): %d\n", layer(bt->LChild, x));
    if(layer(bt->LChild, x)){
      cot = layer(bt->LChild, x)+1;
      return cot;
    }
    // printf("layer(bt->RChild, x): %d\n", layer(bt->RChild, x));
    if(layer(bt->RChild, x)){
      cot = layer(bt->RChild, x)+1;
      return cot;
    }
  }
  return cot;
}

// 算法2
int find_node_level(BiTree bt, char x, int h){
  if (bt == NULL)
    return 0;
  else if (bt->elem == x)
    return h;
  else{
    int l = find_node_level(bt->LChild, x, h+1);
    if (l != 0)
      return l;
    else
      return find_node_level(bt->RChild, x, h+1);
  }
}

// 算法3
void level_in_x(BiTree BT,char x,int level){
  if (BT == NULL){
    return ;
  }
  if(BT->elem == x){
    printf("x in %d",level);
  }
  level++;
  printf("1:%d----\n", level);
  level_in_x(BT->LChild,x,level);
  printf("2:%d----\n", level);
  level_in_x(BT->RChild,x,level);
  printf("3:%d----\n", level);
  level--;
}

2.3 运行情况截图

DS



题目3

求二叉树的宽度。
利用二叉树层次遍历求二叉树的宽度;
二叉树的宽度即二叉树同层结点数的最大值

3.1 算法设计思想

我利用一个足够大的全局数组来记录遍历过程中的二叉树宽度;
利用一个变量max来记录最大宽度,即为所求;
求宽度的函数依然采用的是先序遍历递归的思想,加一个形参k,对应width数组下标,记录当前深度,来传给子层信息;
如果当前深度k的节点不为空,那么width[k]++,来记录宽度;
max为宽度最大值

3.2 源代码

#define size 100

int width[size];
int max=0;

void MaxWidth(BiTree T,int k){
  if(T==NULL)
    return;
  width[k]++;
  if(max<width[k])
    max=width[k];
  MaxWidth(T->LChild, k+1);
  MaxWidth(T->RChild, k+1);
}

3.3 运行情况截图

DS



题目4

二叉树bt采用二叉链表存储,设计算法实现采用括号表示法输出该二叉树。
            A
          /   \
        B     C
        /     / \
      D     E   F
        \
        G                        A(B(D(,G)),C(E,F))

4.1 算法设计思想

把题目中的括号表示法A(B(D(,G)),C(E,F)),去掉括号变为:
ABDGCEF
这种写法不是我们熟悉的先序遍历吗!
所以我就在二叉树先序遍历算法的基础上改进算法;

a.在节点的左右子树不为空时输出“(”;
b.当节点右子树不为空时输出“,”;
c.在节点的左右子树不为空时输出“)”

4.2 源代码

void Brackets(BiTree T){
  if (T==NULL)
    return;
  printf("%c", T->elem);
  if(T->LChild!=NULL||T->RChild!=NULL)
    printf("( ");
  Brackets(T->LChild);
  if(T->RChild!=NULL)
    printf(", ", T->elem);
  Brackets(T->RChild);
  if(T->LChild!=NULL||T->RChild!=NULL)
    printf(" )");
}

4.3 运行情况截图

DS



题目5

求二叉树的路径长度。
二叉树二叉链表存储
二叉树的路径长度即:二叉树中所有结点的路径长度之和。
(结点的路径长度即:从根到结点的分支数)

5.1 算法设计思想

路径长度即为分支数之和;
根据二叉树的性质;
每个节点的头部都有一个分支,除了根节点;
所以分支数之和就是二叉树节点数-1;
那么采用递归的方法求得节点数,就可以求得路劲长度了

5.2 源代码

int Node(BiTree T){
  if (T==NULL)
    return 0;
  else{
    return 1 + Node(T->LChild) + Node(T->RChild);
  }
}

printf("The path length of this binary tree is: %d\n", Node(T)-1);

5.3 运行情况截图

DS


更多精彩

等多精彩,访问我的个人博客吧!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值