当前位置:   article > 正文

C语言实现二叉树(链式)_写出用 c 语言定义一个二叉树的二叉链表结点结构的算法。

写出用 c 语言定义一个二叉树的二叉链表结点结构的算法。

        一颗二叉树是一个节点的有限集合,是由一个根节点和两个子树构成;每个子树又有两个子树。这两个子树分为左子树和右子树,且顺序不能颠倒。如图,像一个倒着的树一样:


它有两种存储方式,一种是顺序存储,一种是链式存储。

顺序存储:

        对于一棵完全二叉树所有结点按照层序自顶向下,同一层自左向右顺序存入一个顺序表中,如果该节点为空,则存入一个特殊的字符代表NULL。例如: 

这就是二叉树的顺序存储。

优点:存储完全二叉树,简单省空间
缺点:存储一般二叉树尤其单支树,存储空间利用不高

链式存储:

        二叉树的链式存储结构是用结构体定义结点,每个结点有两个指针,一个指向它的左子树,一个指向右子树。如图:


下面实现二叉树链式结构的基本操作:

定义结点:

  1. typedef char DataType;
  2. typedef struct TreeNode
  3. {
  4. DataType elem;
  5. struct TreeNode* rchild;
  6. struct TreeNode* lchild;
  7. }TreeNode;

实现二叉树的初始化:

  1. void InitTree(TreeNode** root)
  2. {
  3. assert(root);
  4. if(*root == NULL)
  5. return;
  6. *root = NULL;
  7. return;
  8. }

实现二叉树的先序遍历:

算法:(递归版本

    若二叉树为空,算法结束;否则

        a 访问根节点

        b 先序遍历根节点的左子树

        c 先序遍历根节点的右子树


  1. void PreOrder(TreeNode* root)
  2. {
  3. if(root == NULL)
  4. return;
  5. printf("%c ", root->elem);
  6. PreOrder(root->lchild);
  7. PreOrder(root->rchild);
  8. return;
  9. }

实现非递归版本的先序遍历:

1.若根节点为空(空树,不需要遍历),直接返回;

2.否则,将根节点入栈;

3.判断栈是否为空,不为空进入循环;

4.取栈顶结点并访问该节点,同时将该节点出栈;

5.若该节点的右子树不为空,将右孩子结点入栈;

6.若该节点的左子树不为空,将左孩子节点入栈;

7.直到栈为空,跳出循环,完成了先序遍历。

  1. void PreOrderByLoop(TreeNode* root)
  2. {
  3. if(root == NULL)
  4. return;
  5. SeqStack s;
  6. InitSeqStack(&s);
  7. PushSeqStack(&s, root);
  8. TreeNode* tmp;
  9. while(IsEmpty(&s) != 1)
  10. {
  11. TopSeqStack(&s, &tmp);
  12. printf("%c ", tmp->elem);
  13. PopSeqStack(&s);
  14. if(tmp->rchild != NULL)
  15. PushSeqStack(&s, tmp->rchild);
  16. if(tmp->lchild != NULL)
  17. PushSeqStack(&s, tmp->lchild);
  18. }
  19. return;
  20. }

实现二叉树的中序遍历:


递归版本:

    若二叉树为空,直接返回;否则

1.遍历二叉树的左子树

2.访问根节点

3.遍历二叉树的右子树

  1. void InOrder(TreeNode* root)
  2. {
  3. if(root == NULL)
  4. return;
  5. InOrder(root->lchild);
  6. printf("%c ", root->elem);
  7. InOrder(root->rchild);
  8. return;
  9. }

非递归版本:

1.若树为空,直接返回;否则令tmp=root,进入循环(跳出条件为栈为空 或 tmp==NULL)

2.循环的将tmp节点的所有左子树入栈

3.取栈顶结点为tmp,访问该节点并出栈

4.令tmp=tmp的右孩子,进入下一次循环

  1. void InOrderByLoop(TreeNode* root)
  2. {
  3. if(root == NULL)
  4. return;
  5. SeqStack s;
  6. InitSeqStack(&s);
  7. TreeNode* tmp = root;
  8. while(IsEmpty(&s) != 1 || tmp != NULL)
  9. {
  10. while(tmp != NULL)
  11. {
  12. PushSeqStack(&s, tmp);
  13. tmp = tmp->lchild;
  14. }
  15. TopSeqStack(&s, &tmp);
  16. printf("%c ", tmp->elem);
  17. tmp = tmp->rchild;
  18. PopSeqStack(&s);
  19. }

实现二叉树的后续遍历:


递归版本:

若树为空,直接返回;否则

1.遍历根节点的左子树;

2.遍历根节点的右子树;

3.访问根节点。

  1. void PostOrder(TreeNode* root)
  2. {
  3. if(root == NULL)
  4. return;
  5. PostOrder(root->lchild);
  6. PostOrder(root->rchild);
  7. printf("%c ", root->elem);
  8. return;
  9. }

非递归版本:

1.若树为空,直接返回;否则令tmp= root,进入循环(条件为栈非空或tmp!=NULL)

2.循环的将所有左子树入栈;

3.去栈顶结点,若该节点没有右子树或者右子树已经访问过了,则访问该节点并出栈;

4.否则,令tmp为该节点的右子树,进入下一层循环。

  1. void PostOrderByLoop(TreeNode* root)
  2. {
  3. if(root == NULL)
  4. return;
  5. TreeNode* tmp = root;
  6. TreeNode* pre = NULL;
  7. TreeNode* top;
  8. SeqStack s;
  9. InitSeqStack(&s);
  10. while(IsEmpty(&s) != 1 || tmp != NULL)
  11. {
  12. while(tmp != NULL)
  13. {
  14. PushSeqStack(&s, tmp);
  15. tmp = tmp->lchild;
  16. }
  17. TopSeqStack(&s, &top);
  18. if(top->rchild == NULL || top->rchild == pre)
  19. {
  20. printf("%c ", top->elem);
  21. pre = top;
  22. PopSeqStack(&s);
  23. }
  24. else
  25. tmp = top->rchild;
  26. }
  27. return;
  28. }

实现二叉树的层序遍历:


1.若树为空,直接返回;

2.否则将根节点入队列;

3.取队首结点,访问该节点;

4.若该节点的左子树不为空,将左子树入队列;若右子树不为空,将右子树入队列;

5.循环的进行3和4,直到队列为空。

  1. void LevelOrder(TreeNode* root)
  2. {
  3. if(root == NULL)
  4. return;
  5. SeqQueue q;
  6. InitSeqQueue(&q);
  7. PushSeqQueue(&q, root);
  8. TreeNode* tmp;
  9. while(SizeSeqQueue(&q) != 0)
  10. {
  11. FrontSeqQueue(&q, &tmp);
  12. printf("%c ", tmp->elem);
  13. if(tmp->lchild != NULL)
  14. PushSeqQueue(&q, tmp->lchild);
  15. if(tmp->rchild != NULL)
  16. PushSeqQueue(&q, tmp->rchild);
  17. PopSeqQueue(&q);
  18. }
  19. return;
  20. }
二叉树前序遍历规则应用:二叉树的创建/拷贝
二叉树的创建:

        现有一个带有特殊字符的二叉树先序遍历结果,其中特殊字符是代表空节点,如何建立这样的二叉树?

        答:利用递归版本的先序遍历方法,构建还原该二叉树。

  1. TreeNode* _CreateTree(DataType array[], size_t size, DataType null_node, size_t* index)
  2. {
  3. assert(index);
  4. if(*index >= size)
  5. return NULL;
  6. if(array[*index] == null_node)
  7. {
  8. ++*index;
  9. return NULL;
  10. }
  11. TreeNode* new_node = CreateNode(array[(*index)++]);
  12. new_node->lchild = _CreateTree(array, size, null_node, index);
  13. new_node->rchild = _CreateTree(array, size, null_node, index);
  14. return new_node;
  15. }
  16. TreeNode* CreateTree(DataType array[], size_t size, DataType null_node)
  17. {
  18. assert(array);
  19. size_t index = 0;
  20. return _CreateTree(array, size, null_node, &index);
  21. }

二叉树的拷贝:

类似的:

  1. TreeNode* TreeClone(TreeNode* root)
  2. {
  3. if(root == NULL)
  4. return NULL;
  5. TreeNode* new_node = CreateNode(root->elem);
  6. new_node->lchild = TreeClone(root->lchild);
  7. new_node->rchild = TreeClone(root->rchild);
  8. return new_node;
  9. }
二叉树后序遍历规则应用:二叉树的销毁
  1. void DestroyNode(TreeNode* node)
  2. {
  3. free(node);
  4. return;
  5. }
  6. void TreeDestroy(TreeNode** root)
  7. {
  8. assert(root);
  9. if(*root ==NULL)
  10. return;
  11. TreeDestroy(&((*root)->lchild));
  12. TreeDestroy(&((*root)->rchild));
  13. DestroyNode(*root);
  14. *root = NULL;
  15. return;
  16. }

求二叉树的高度 :

二叉树的高度为左子树和右子树高度较大的那一个!

  1. size_t TreeHeight(TreeNode* root)
  2. {
  3. if(root == NULL)
  4. return 0;
  5. size_t lheight = TreeHeight(root->lchild) + 1;
  6. size_t rheight = TreeHeight(root->rchild) + 1;
  7. return rheight > lheight ? rheight : lheight;
  8. }
求二叉树叶子结点的个数

叶子结点:没有左右孩子的结点;

二叉树叶子结点的个数 = 左子树叶子结点的个数 + 右子树叶子结点的个数。

  1. size_t TreeLeafSize(TreeNode* root)
  2. {
  3. if(root == NULL)
  4. return 0;
  5. if(root->lchild == NULL && root->rchild == NULL)
  6. return 1;
  7. return TreeLeafSize(root->lchild) + TreeLeafSize(root->rchild);
  8. }
求二叉树第K层结点的个数

  1. size_t TreeKLevelSize(TreeNode* root, int K)
  2. {
  3. if(root == NULL)
  4. return 0;
  5. if(K == 1)
  6. return 1;
  7. return TreeKLevelSize(root->lchild, K-1) + TreeKLevelSize(root->rchild, K-1);
  8. }

求二叉树的镜像 

解决方法:递归的交换二叉树的左右子树。

  1. void TreeMirror(TreeNode* root)
  2. {
  3. if(root == NULL)
  4. return;
  5. TreeNode* tmp = root->lchild;
  6. root->lchild = root->rchild;
  7. root->rchild = tmp;
  8. TreeMirror(root->lchild);
  9. TreeMirror(root->rchild);
  10. return;
  11. }

解决方法(二):(非递归)

遍历该二叉树,同时交换每个结点的左右子树。

以下是用层序遍历实现的:

  1. void TreeMirrorByLoop(TreeNode* root)
  2. {
  3. if(root == NULL)
  4. return;
  5. SeqQueue q;
  6. InitSeqQueue(&q);
  7. PushSeqQueue(&q, root);
  8. TreeNode* tmp;
  9. while(SizeSeqQueue(&q) > 0)
  10. {
  11. FrontSeqQueue(&q, &tmp);
  12. TreeNode* tp = tmp->lchild;
  13. tmp->lchild = tmp->rchild;
  14. tmp->rchild = tp;
  15. if(tmp->lchild != NULL)
  16. PushSeqQueue(&q, tmp->lchild);
  17. if(tmp->rchild != NULL)
  18. PushSeqQueue(&q, tmp->rchild);
  19. PopSeqQueue(&q);
  20. }
  21. return;
  22. }

判断一棵二叉树是否为完全二叉树(层序遍历变形)

问题分析:

        若为完全二叉树,层序遍历每个结点,左右子树都存在,直到遍历到一个转折结点,若只有左子树或没有子树,那么接下来层序遍历的结点都没有子树。

问题解决:

1.将根节点入队列,并且置flag=0(代表不是完全二叉树);

2.进入循环(循环条件为队列非空);

3.取队首结点,并出队列

4.若flag==0

  若该节点左右孩子都存在,分别入队列;

  若该节点只有左孩子节点,入队列,并置flag=1;

  若该节点只有右孩子结点,返回0(不是完全二叉树);

5.若flag==1

   若该节点左右孩子都不存在,什么都不做;

   否则,flag=0;

6.直到队列为空,跳出循环,返回flag。

  1. int IsCompleteTree(TreeNode* root)
  2. {
  3. if(root == NULL)
  4. return 1;
  5. SeqQueue q;
  6. int flag = 0; //表示该树不是完全二叉树
  7. InitSeqQueue(&q);
  8. PushSeqQueue(&q, root);
  9. TreeNode* tmp = root;
  10. while(FrontSeqQueue(&q, &tmp))
  11. {
  12. PopSeqQueue(&q);
  13. if(flag == 0)
  14. {
  15. if(tmp->lchild != NULL && tmp->rchild != NULL)
  16. {
  17. PushSeqQueue(&q, tmp->lchild);
  18. PushSeqQueue(&q, tmp->rchild);
  19. }
  20. else if(tmp->lchild == NULL && tmp->rchild != NULL)
  21. return 0;
  22. else if(tmp->lchild != NULL && tmp->rchild == NULL)
  23. {
  24. PushSeqQueue(&q, tmp->rchild);
  25. flag = 1;
  26. }
  27. else
  28. {
  29. flag = 1;
  30. }
  31. }
  32. else
  33. {
  34. if(tmp->lchild != NULL && tmp->rchild != NULL);
  35. else
  36. flag = 0;
  37. }
  38. }
  39. return flag;
  40. }















声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/233085?site
推荐阅读
相关标签
  

闽ICP备14008679号