关键词搜索

源码搜索 ×
×

【数据结构】二叉树--链式结构

发布2022-04-17浏览801次

详情内容

普通二叉树增删查改没有价值,单纯为了存储数据,不如使用线性表。

学习普通二叉树是为更好的控制它的结构,为后续学习更加复杂的搜索二叉树打基础。

平衡二叉树:AVL树,红黑树。

二叉树的概念:

1.空树

2.非空:根节点,根结点的左子树,根结点的右子树组成。

二叉树的概念:

1.空树

2.非空:根节点,根结点的左子树,根结点的右子树组成。

根据概念可知:二叉树定义是递归的,因此后续基本操作按照递归进行。

二叉树的遍历

前序,中序,后续遍历

模拟遍历

1.前序遍历(先根遍历):根 左子树 右子树 

                          1  2  3  4  5  6

2.中序遍历(中根遍历):左子树,根结点 ,右子树

                                 3  2  1  5  4  6

3.后序遍历(后根遍历):左子树,右子树,根

                         3  2  5  6  4  1

层序遍历:1  2  4  3  5  6

模拟实现二叉树遍历

构建链式结构

  1. typedef int BTDataType;
  2. typedef struct BinaryTreeNode
  3. {
  4. struct BinaryTreeNode* left;//左树节点
  5. struct BinaryTreeNode* right;//右数节点
  6. BTDataType data;//节点值
  7. }BTNode;
  8. BTNode* BinaryTreeFind(BTNode* root, BTDataType x);
  9. BTNode* BuyBTNode(BTDataType x)
  10. {
  11. //malloc节点
  12. BTNode* tmp = (BTNode*)malloc(sizeof(BTNode));
  13. if (tmp == NULL)
  14. {
  15. printf("malloc failed!\n");
  16. exit(-1);
  17. }
  18. BTNode* node = tmp;
  19. node->left = node->right = NULL;
  20. node->data = x;
  21. return node;
  22. }
  23. //手动创建链式二叉树
  24. BTNode* CreatBinaryTree()
  25. {
  26. BTNode* node1 = BuyBTNode(1);
  27. BTNode* node2 = BuyBTNode(2);
  28. BTNode* node3 = BuyBTNode(3);
  29. BTNode* node4 = BuyBTNode(4);
  30. BTNode* node5 = BuyBTNode(5);
  31. BTNode* node6 = BuyBTNode(6);
  32. node1->left = node2;
  33. node1->right = node4;
  34. node2->left = node3;
  35. node4->left = node5;
  36. node4->right = node6;
  37. return node1;
  38. }

1.前序遍历

基本思路:根 - 左数- 右数

  1. void PrevOrder(BTNode* tree)
  2. {
  3. if (tree == NULL)
  4. {
  5. printf("NULL ");
  6. return;
  7. }
  8. printf("%d ", tree->data);
  9. PrevOrder(tree->left);
  10. PrevOrder(tree->right);
  11. }

 

 

2.中序遍历

左子树 - 根结点  - 右子树

  1. //中序遍历
  2. void InOrder(BTNode* tree)
  3. {
  4. if (tree == NULL)
  5. {
  6. printf("NULL ");
  7. return;
  8. }
  9. InOrder(tree->left);
  10. printf("%d ", tree->data);
  11. InOrder(tree->right);
  12. }

 

 

3.后序遍历

左子树- 右子树- 根

  1. //后序遍历
  2. void NextOrder(BTNode* tree)
  3. {
  4. if (tree == NULL)
  5. {
  6. printf("NULL ");
  7. return;
  8. }
  9. NextOrder(tree->left);
  10. NextOrder(tree->right);
  11. printf("%d ", tree->data);
  12. }

 

4.求节点个数

a.遍历+计数

第一种:

  1. 1.遍历+计数
  2. void BTSize(BTNode* tree, int* pCount)
  3. {
  4. if (tree == NULL)
  5. return;
  6. (*pCount)++;
  7. BTSize(tree->left,pCount);
  8. BTSize(tree->right, pCount);
  9. }

第二种:

定义一个全局遍历的计数器或者static定义一个静态局部变量。

  1. int count = 0;
  2. int BTSize(BTNode* tree)
  3. {
  4. //static int count = 0;
  5. if (tree == NULL)
  6. return count;
  7. count++;
  8. BTSize(tree->left);
  9. BTSize(tree->right);
  10. return count;
  11. }

但这有一个致命的错误,多次调用返回的节点个数会错误。

原因:全局变量和静态局部变量都没办法没初始化为0。

b.分治:

分治思想:将复杂的问题分成规模更小的子问题,子问题再分为更小的子问题,……

方法:计算完左子树的节点个数再加上右节点的个数。

思想:递归

  1. //分治
  2. /*把复杂的问题,分成更小规模的子问题,子问题再分为更小的子问题……*/
  3. //左子树算完再算右数再加上根节点
  4. int BTSize(BTNode* tree)
  5. {
  6. if (tree == NULL)
  7. return 0;
  8. return BTSize(tree->left) + BTSize(tree->right) + 1;
  9. }

5.求叶子节点的个数

分治:计算完左树再计算完右树。

代码:

  1. //求叶子结点的个数
  2. //分治
  3. int BTreeLeafSize(BTNode* tree)
  4. {
  5. if (tree == NULL)
  6. return 0;
  7. if (tree->left == NULL && tree->right == NULL)
  8. return 1;
  9. return BTreeLeafSize(tree->left) + BTreeLeafSize(tree->right);
  10. }

6.求第k层节点的个数

思路:将第k-1层的作为父亲节点,递推。

  1. //第k层节点的个数
  2. int BTreeLevelSize(BTNode* tree,int k)
  3. {
  4. assert(k >= 1);
  5. if (tree == NULL)
  6. return 0;
  7. if (k == 1)
  8. return 1;
  9. //找到k-1层作为父亲节点,计算即可
  10. return BTreeLevelSize(tree->left,k-1) + BTreeLevelSize(tree->right,k-1);
  11. }

7.问树高几何?

分治:计算左子树高度和右子树高度作比较,大的那个+1

  1. //求树高几何?
  2. int BTreeDepth(BTNode* tree)
  3. {
  4. //分治,左数算出高来,右数算出高来,比较取其大者
  5. if (tree == NULL)
  6. return 0;
  7. return BTreeDepth(tree->left) > BTreeDepth(tree->right) ? BTreeDepth(tree->left) + 1 : BTreeDepth(tree->right) + 1;
  8. }

8.二叉树查找值为x的节点

  1. 思路:1)考虑分治思想,先递归左树,再递归右树。
  2. 2)找到就返回对应节点地址,炸藕到就返回NULL
  3. 3)判断返回的是为NULL 还是 对应的节点。
  1. //二叉树查找为x的节点
  2. BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
  3. {
  4. if (root == NULL)
  5. return NULL;
  6. //前序遍历
  7. if (root->data == x)
  8. return root;
  9. //先遍历左树
  10. BTNode* ret1 = BinaryTreeFind(root->left,x);
  11. if (ret1)
  12. return ret1;
  13. //遍历右树
  14. BTNode* ret2 = BinaryTreeFind(root->right, x);
  15. if (ret2)
  16. return ret2;
  17. return NULL;
  18. }

9.层序遍历

思路:根据层序遍历的特性,可以使用队列解决。

当取出上一层的数据的时候,将上一层对应的left 和 right 入队列。

注意:C由于没有库,要取出我们之前自己实现的队列的文件,添加在该项目的相应位置。

记得在Queue.h上加入

入队列的时候,入的是二叉树的一整个结构体,不单单是data

代码:

  1. //层序遍历
  2. /*根据层序遍历的特性,考虑将数据入队列,可以根据队列的性质,实现层序遍历
  3. 当取出上一层数据的时候,将leftright 节点依次入队列*/
  4. void LevelOrder(BTNode* tree)
  5. {
  6. //创建队列
  7. Queue q;
  8. QueueInit(&q);
  9. //树不为空,入队列
  10. if (tree)
  11. {
  12. QueuePush(&q,tree);
  13. }
  14. //将数据入队列。
  15. while (!QueueEmpty(&q))
  16. {
  17. BTNode* front = QueueFront(&q);
  18. QueuePop(&q);
  19. printf("%d ", front->data);
  20. //如果左子树不为空,入队列
  21. if (front->left)
  22. QueuePush(&q, front->left);
  23. //如果右树不为空,入队列
  24. if (front->right)
  25. QueuePush(&q, front->right);
  26. }
  27. printf("\n");
  28. //销毁队列
  29. QueueDestory(&q);
  30. }

 

10.判断二叉树是否为完全二叉树

思路:判断还是以队列为基础,层序遍历为辅。

入队列时,NULL也入队列,当出队列的时候遇到NULL时,开始将剩下的队列数据除队列,当剩下的数据中只有NULL时,则说明其是完全二叉树,否则就不是。

画图:

这棵树就不是完全二叉树。

代码:

  1. //判断二叉树是否为完全二叉树
  2. /*以队列为基础,层序遍历为辅助,当遇到NULL时,将剩下的数据都出队列,当剩下的数据中只有NULL
  3. 则说明是完全二叉树,否则就不是文强案二叉树*/
  4. bool BTreeComplete(BTNode* root)
  5. {
  6. Queue q;
  7. QueueInit(&q);
  8. //若不为空,入队列
  9. if (root)
  10. QueuePush(&q, root);
  11. while (!QueueEmpty(&q))
  12. {
  13. BTNode* front = QueueFront(&q);
  14. QueuePop(&q);
  15. //为空时跳出
  16. if (front == NULL)
  17. break;
  18. //入队列
  19. QueuePush(&q, front->left);
  20. QueuePush(&q, front->right);
  21. }
  22. while (!QueueEmpty(&q))
  23. {
  24. BTNode* front = QueueFront(&q);
  25. QueuePop(&q);
  26. if (front)
  27. return false;
  28. }
  29. return true;
  30. }

11.销毁树

思路:递归分治,销毁左子树 - 右子树 - 根

  1. void BTreeDestroy(BTNode* root)
  2. {
  3. if (root == NULL)
  4. return;
  5. BTreeDestroy(root->left);
  6. BTreeDestroy(root->right);
  7. free(root);
  8. }

如有错误,还请大佬们指出~

相关技术文章

点击QQ咨询
开通会员
返回顶部
×
微信扫码支付
微信扫码支付
确定支付下载
请使用微信描二维码支付
×

提示信息

×

选择支付方式

  • 微信支付
  • 支付宝付款
确定支付下载