Data structure advanced training course notes and algorithm exercises 数据结构进阶实训课程笔记和算法练习

Source Code

C语言中文网



题目1

建立树的孩子兄弟表示法存储

1.1 算法设计思想

**孩子兄弟表示法:**任意一棵树,它的节点的第一个孩子如果存在就是唯一的,它的右兄弟存在也是唯一的。因此,我们设置两个指针,分别指向该结点的第一个孩子和此结点的右兄弟

给定一颗树,可以找到唯一的一颗二叉树与之对应,因此,可以用一颗二叉树来表示一颗树的结构。如图:

              A                                                                  A
                                                                              /
​       /      |     \                                                    B
                                                                     /        \
​    B        C       D                                           E          C
                                                                     \            \
  /    \               |                                             F           D
                                                                                  /
E       F             G                                                       G
                                                                              /
​                  /    |    \                                              H
                                                                              \
​                H     I       J                                               I
                                                                                  \
​                                                                                    J

和二叉树建树的方法相同,递归的思想,先建立左子树,左子树建立完(即遇到结束标志字符’#’),退层建立右子树。

所以按照将树转化为二叉树,然后输入先序序列来建这棵树。

1.2 源代码

#define ElemType char

typedef struct CSNode{
  ElemType data;
  struct CSNode *firstchild, *nextsibling;
}CSNode, *CSTree;

// eg. ABE#F##C#DGH#I#J#####
void CreatCSTree(CSTree *t){
  ElemType ch;
  scanf("%c", &ch);
  if(ch=='#') {
    (*t)=NULL;
  }
  else {
    (*t)=(CSTree)malloc(sizeof(CSNode));
    (*t)->data=ch;
    CreatCSTree(&((*t)->firstchild));
    CreatCSTree(&((*t)->nextsibling));
  }
}

1.3 运行情况截图



题目2

在树的孩子兄弟表示法下,求取树T的高度。

2.1 算法设计思想

既然我们可以将树转化为孩子兄弟表示法,这种方法用二叉链表的形式实现,那么我们考虑用求二叉树深度的方法来求树的深度。

区别在于,孩子兄弟表示法中每个节点的右子树是这个节点的兄弟,在原树中并不占深度,所以只需修改算法的求右子树高度的部分即可。

2.2 源代码

// eg. ABE#F##C#DGH#I#J#####

int depth(CSTree t){
if(t){
  int fd = depth(t->firstchild)+1;
  int nd = depth(t->nextsibling);
  return fd>nd? fd:nd;
}
}

2.3 运行情况截图



题目3

树采用孩子兄弟表示法存储。
fch data nsib level
编写算法,将树中所有结点层次值置入每个结点的level域,并要求由根开始逐层输出树中的各条边,边的输出格式为(ki,kj)
        示例
         A           转化为                A
      /  |  \      孩子兄弟表示           /
     B   C   D                        B
    / \  |                          /   \
   E   F G                         E      C
                                    \    /  \
                                     F  G    D

3.1 算法设计思想

要输出树中各边,存在边,即两节点在树中是父子关系

在孩子兄弟表示法中,就是与这个节点的左孩子节点,和左孩子节点的所有右孩子节点有边,

所以一个递归打印当前节点和左孩子构成的边,另一个递归打印当前节点与其左孩子的所有右孩子节点所构成的边。

3.2 源代码

#define ElemType char

typedef struct CSNode{
ElemType data;
struct CSNode *firstchild, *nextsibling;
int level;
}CSNode, *CSTree;

// eg. ABE#F##CG##D###
CSTree T;

int layer(CSTree t, char x){
int cot = 0;
if(t==NULL)
  return cot;
else if(t->data==x){
  cot = 1;
  return cot;
}
else{
  if(layer(t->firstchild, x)){
    cot = layer(t->firstchild, x)+1;
    return cot;
  }
  if(layer(t->nextsibling, x)){
    cot = layer(t->nextsibling, x);
    return cot;
  }
}
return cot;
}

void CreatCSTree(CSTree *t){
ElemType ch;
scanf("%c", &ch);
if(ch=='#') {
  (*t)=NULL;
}
else {
  (*t)=(CSTree)malloc(sizeof(CSNode));
  (*t)->data=ch;
  (*t)->level=layer(T, ch);
  CreatCSTree(&((*t)->firstchild));
  CreatCSTree(&((*t)->nextsibling));
}
}

void borderNextSibling(CSTree t, CSTree nt){
printf("%c%c, ", t->data, nt->data);
if(nt->nextsibling)
  borderNextSibling(t, nt->nextsibling);
}

void border(CSTree t){
if(t){
  if(t->firstchild){
    printf("%c%c, ", t->data, t->firstchild->data);
    if(t->firstchild->nextsibling)
      borderNextSibling(t, t->firstchild->nextsibling);
  }
  border(t->firstchild);
  border(t->nextsibling);
}
}

3.3 运行情况截图



题目4

已知树采用孩子兄弟表示法表示试编写算法按如下的凹入方式打印树。
        示例
         A                     A
      /  |  \                   B
     B   C   D                   E  
    / \  |                       F
   E   F G                      C
                                 G
                                D
利用树的先序遍历完成;
细化访问visit()操作:先打空格,在输出结点;打印输出的空格数目和结点所在的层次号有关。

4.1 算法设计思想

首先不考虑前面的每个元素前面的空格,得到打印序列是ABEFCGD,发现这是孩子兄弟表示法的前序遍历结果,然后利用上面第二题的算法获得每个元素的层号,然后打印空格,就可以实现凹入方式打印这棵树了。

4.2 源代码

CSTree T;  // 全局变量
// eg. ABE#F##CG##D###

int layer(CSTree t, char x){
int cot = 0;
if(t==NULL)
  return cot;
else if(t->data==x){
  cot = 1;
  return cot;
}
else{
  if(layer(t->firstchild, x)){
    cot = layer(t->firstchild, x)+1;
    return cot;
  }
  if(layer(t->nextsibling, x)){
    cot = layer(t->nextsibling, x);
    return cot;
  }
}
return cot;
}

void visit(CSTree t){
int i;
if(t){
  for(i=1; i<layer(T, t->data); i++)
    printf(" ");
  printf("%c\n", t->data);
  visit(t->firstchild);
  visit(t->nextsibling);
}
}

4.3 运行情况截图