二叉树:广义表搭建二叉树

使用广义表搭建二叉树(及层序遍历)

问题概要

二叉树是非常常见的数据结构,那么,如何从无到有构建一棵二叉树呢?比较主流的方法就是输入一个广义表,例如A(B(D),C),这种形式。那么,如何把这种字符串转变为对应的,用指针相连的二叉树,这个问题很常见,故记录如下。(这里假定树的节点内容均为大写英文字符。)

算法思路

首先,为了建立树,必须建一个根节点。
为了在这棵树上运动,建立一个指针,指向当前操作的节点,命名为curr,初始时指向根节点。
下面开始逐字符读入广义表。
当读入的字符为大写英文字符时,显然,此时对当前节点进行赋值操作;
当读入的字符为左括号时,应当建立当前节点的左孩子,同时,为统一赋值操作,应当把当前的curr指针指向新建的左孩子;
当读入的字符为逗号时,应当建立当前节点的兄弟节点(右兄弟)。也就是说,先把当前的curr指针指向它的父亲,然后对于这个父亲,建立右孩子,在把curr指针指向这个右孩子;
当读入的字符为右括号时,说明右孩子已经操作完毕(可能赋值,也可能没有赋值),令curr指针指向其父即可;
当读入的字符为/n时,结束输入,二叉树建立完毕。

代码

#include
#include
#include

struct treenode {
 struct treenode* parent ;
 struct treenode* lchild ;
 struct treenode* rchild ;
 char data;
};

int main()
{
 struct treenode* root = (struct treenode*)malloc(sizeof(struct treenode));
 struct treenode* curr = root;
 int node_num = 0;
 while (1)
 {
  char tmp;
  scanf_s("%c", &tmp);
  if (tmp != '\n')
  {
     if (tmp == '(')
   {
    curr->lchild = (struct treenode*)malloc(sizeof(struct treenode));
    curr->lchild->parent = curr;
    curr = curr->lchild;
    curr->lchild = NULL;
    curr->rchild = NULL;
    curr->data = 'a';
   }
      else if (tmp == ',')
   {
    curr = curr->parent;
    curr->rchild = (struct treenode*)malloc(sizeof(struct treenode));
    curr->rchild->parent = curr;
    curr = curr->rchild;
    curr->lchild = NULL;
    curr->rchild = NULL;
    curr->data = 'a';
   }
      else if (tmp == ')')
   {
    curr = curr->parent;
   }
   else
   {
    curr->data = tmp;
    node_num++;
   }
  }
  else
   break;
 }
 struct treenode** q = (struct treenode**)calloc(node_num + 5, sizeof(struct treenode*));
 int head = 0;
 int tail = 1;
 q[0] = root;
 while (head<tail)
 {
  struct treenode* now = q[head];
  head++;
  if (now->data != 'a')
  {
   printf_s("%c", now->data);
   printf_s(" ");
  }
  if (now->lchild)
  {
   q[tail] = now->lchild;
   tail++;
  }
  if (now->rchild)
  {
   q[tail] = now->rchild;
   tail++;
  }
 }
}

层序遍历

二叉树的层序遍历很容易实现,首先,在数据结构上,你应当选择一个队列。然后,根节点入队,当队列不为空时,循环:一个节点t出队,访问t的data,t的左孩子入队,t的右孩子出队。
这里我用动态数组加上队头变量与队尾变量实现了一个乞丐版的队列,当然是很浪费空间的,可以基于链表维护一个更加精巧的队列。

malloc

这里需要注意一点,就是malloc的使用要加小心。从本质上来说,malloc只是为你分配了你所要求的空间,但这个空间里具体有什么,也就是说,这个新建的指针所指向的内容的初始化,需要你自己来操作。比如代码:

struct treenode* root = (struct treenode*)malloc(sizeof(struct treenode));

这个代码执行完之后,root->parent的值是什么?什么都不是!它甚至不是NULL。如果未经初始化就加以访问,就会报错,一般是0xcdcdcdcd或者0xcccccccc。

你可能感兴趣的:(数据结构,数据结构,二叉树,c语言,malloc,广义表)