二叉树

一.二叉树的创建
【需要一个前序遍历,并且每个左右孩子都有标志,空用#代替。如:ABD##E#H##CF##G##】

#define  ENDTAG  '#'
typedef char BTDataType;
typedef struct BinaryTreeNode
{
 BTDataType _data;
 struct BinaryTreeNode *_left;
 struct BinaryTreeNode *_right;
}BTNode;

//创建一棵树
    BTNode *BinaryTreeCreate(BTDataType *a)
{
 BTNode *cur;
 static int i = 0;
 if (a[i] == ENDTAG)
 {
  i++;
  return NULL;
 }
 cur = (BTNode *)malloc(sizeof(BTNode));
 cur->_data = a[i];
 i++;
 cur->_left = BinaryTreeCreate(a);
 cur->_right = BinaryTreeCreate(a);
 return cur;
}

二.递归遍历->前中后

//递归遍历
void BinaryTreePrevOrder(BTNode *root)//前序遍历
{
 if (root != NULL)
 {
  printf("%c", root->_data);
  BinaryTreePrevOrder(root->_left);
  BinaryTreePrevOrder(root->_right);
 }
}

void BinaryTreeInOrder(BTNode *root)//中序遍历
{
 if (root != NULL)
 {
  BinaryTreeInOrder(root->_left);
  printf("%c", root->_data);
  BinaryTreeInOrder(root->_right);
 }
}

void BinaryTreePostOrder(BTNode *root)//后序遍历
{
 if (root != NULL)
 {
  BinaryTreePostOrder(root->_left);
  BinaryTreePostOrder(root->_right);
  printf("%c", root->_data);
 }
}

三.非递归遍历<用栈实现>
1.前序遍历:
1)打印当前节点,如果该节点有右子树,就将右子树压栈,然后访问该节点的左子树。
2)如果左子树为空,直接取栈顶,重复1)的操作。
3)栈空且当前节点为空时跳出

void BinaryTreePrevOrderNonR(BTNode *root)//前序遍历(左边打印,右边压栈)
{
 Stack st;
 BTNode *cur = root;
 StackInit(&st,20);
 while (cur || StackEmpty(&st))
 {
  putchar(cur->_data);
  if (cur->_right)
  {
   StackPush(&st, cur->_right);
  }
  if (cur->_left)
  {
   cur = cur->_left;
  }
  else
  {
   cur = StackTop(&st);
   StackPop(&st);
  }
 }
 StackDestory(&st);
}

2.中序遍历
1)先将当前节点及自己的左子树入栈,重复此过程直至没有左子树。
2)将当前节点出栈,然后访问右子树,重复1)的过程,如果右子树为空,取栈顶,重复2)的过程。
3)栈空且当前节点为空,遍历结束,循环跳出。

void BinaryTreeInOrderNonR(BTNode *root)//中序遍历//  一直左压出栈时压右
{
 Stack st;
 BTNode *cur = root;
 StackInit(&st, 20);
 while (cur || StackEmpty(&st))//当cur为空且栈为空时,循环跳出,代表树遍历完毕
 {
  for (; cur; cur = cur->_left)
   //1.把目前的根及其所有的左孩子压栈,直到找不到左孩子为止
   //2.把目前的右孩子作为根,继续将他的左孩子们压栈
  {
   StackPush(&st, cur);
  }
  //if (StackEmpty(&st))
  //{
   cur = StackTop(&st);
   //1.左孩子遍历完毕后,第一个没有左孩子的节点就是中序的第一个输出
   //2.如果右孩子为空<不执行上面的左子树遍历>,此时栈里将会是下一个要访问的节点
   //  如果有右孩子,那么此时栈里将会是以那个右孩子为根的子树中第一个没有左孩子的节点
   putchar(cur->_data);
   //1.由于没有左孩子,所以打印根
   StackPop(&st);
   cur = cur->_right;
   //1.左子树和根遍历结束后,遍历它的右子树
  //}
 }
 StackDestory(&st);
}

3.后序遍历
1)先将当前节点和左子树入栈,直到没有左子树为止,同时,给这几个节点清空“左子树完全访问标记”LN。
2)设置当前节点的LN,访问它的右子树,如果右子树存在,重复1)的过程,如果右子树为空,取出栈顶,如果栈顶元素的LN依然是被设置状态,则继续出栈,直到标记为清空状态,然后重复过程2)
3)栈空且当前节点为空,遍历结束,循环跳出。

void BinaryTreePostOrderNonR(BTNode *root)//后序遍历
{
 BTNode *cur = root;
 Stack st;
 int tag[32] = { 0 };//左孩子遍历标签
 StackInit(&st, 20);
 while (cur || StackEmpty(&st))//当cur为空时,循坏跳出,代表树遍历完毕
 {

  for (; cur; cur = cur->_left)//1.类似中序,将左孩子入栈2.cur为空时,代表上一个节点的右孩子为空,只有这种情况,才可能进入下面的循环
  {
   StackPush(&st, cur);//push操作会导致top+1
   tag[st.top] = 0;
  }
 
 //只要上面的for执行过一次循环(右孩子不为空),这个whil的后半部分条件都不可能满足
  while (StackEmpty(&st) && tag[st.top] == 1)//左孩子还没遍历完成时,不能进入打印
   //所以,这里确保了只有左右子树都遍历完成时,才会进入这个while
  {
   cur = StackTop(&st);
   putchar(cur->_data);//打印根
   StackPop(&st);//pop操作会导致top-1
   cur = NULL;//为了循环正常跳出
  }//父节点打印


  if (StackEmpty(&st))
  {
   tag[st.top] = 1;//进入这里证明左子树遍历完毕,左子树标签1
   cur = StackTop(&st)->_right;//进入右子树继续遍历
  }

 }
 StackDestory(&st);
}

四.层次遍历(用队列)
1)先将根入队
2)队列头出列,将他的左右孩子分别入队
3)重复2)的过程,直到队列为空,循环跳出

void BinaryTreeLevelOrder(BTNode *root)//层序遍历<广度搜索>
{
 Queue pq;
 BTNode *tmp;
 QueueInit(&pq);

 QueuePush(&pq,root);
 
 while (QueueEmpty(&pq))
 {
  tmp = QueueFront(&pq);
  printf("%c", tmp->_data);

  if (tmp->_left)
  {
   QueuePush(&pq, tmp->_left);
  }
  if (tmp->_right)
  {
   QueuePush(&pq, tmp->_right);
  }

  QueuePop(&pq);
 }
 QueueDestory(&pq);
}

五,判断是否是完全二叉树
1)层序遍历
2)如果一个节点有右孩子没有左孩子,那么直接判断不是
3)如果一个节点没有右孩子,设置标签
4)如果设置标签后,任意节点有孩子(非叶子),那么判断不是
5)如果循环正常结束,则判断是

int BinaryTreeComplete(BTNode* root)
{
 Queue pq;
 BTNode *tmp;
 int leafflag = 0;
 QueueInit(&pq);
 QueuePush(&pq, root);
 while (QueueEmpty(&pq))
 {
  tmp = QueueFront(&pq);
  printf("%c", tmp->_data);
  QueuePop(&pq);

  if (leafflag)
  {
   if (tmp->_left || tmp->_right)
   {
    return 0;
   }
   continue;
  }

  if (tmp->_right &&tmp->_left)
  {
   QueuePush(&pq, tmp->_left);
   QueuePush(&pq, tmp->_right);
  }
  else if (tmp->_right&&!tmp->_left)
  {
   return 0;
  }
  else
  {
   leafflag = 1;
   if (tmp->_left)
   {
    QueuePush(&pq, tmp->_left);
   }
  }
 }
 QueueDestory(&pq);
 return 1;
}

六.摧毁树<前序遍历递归摧毁>

void BinaryTreeDestory(BTNode* root)
{
 BTNode *left, *right;
 if (root)
 {
  left = root->_left;
  right = root->_right;
  free(root);
  BinaryTreeDestory(left);
  BinaryTreeDestory(right);
 }
}

附:在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值