当前位置:   article > 正文

数据结构—— 再探二叉树

数据结构—— 再探二叉树

1. TOP-K问题

TOP-K问题:求数据结合中前K个最大或者最小的数据

比如:专业前10名、世界500强、富豪榜、游戏中前100的活跃玩家等

思路:

1. 用数据集合中前K个数据来建堆:
                                                            a.  前k个最大的数据,则建小堆
                                                            b.  前k个最小的数据,则建大堆

                                          一般推荐建小堆   

2. 用剩余的数据依次与堆顶的数据来比较,如果比堆顶的数据就替换堆顶数据(覆盖位置,向下调整)

将剩余的数据依次与堆顶元素比完之后,堆中剩余的数据就是所求的前K个最小或最大的元素

通俗来讲就是:用前K个数建立一个小堆,然后剩下的数依次遍历和堆顶最小的数据比较,如果比堆顶的数据大,就把大的数赋给堆顶,再向下调整,最后堆里剩下的K个数就是最大的K个 ,因为小堆的堆顶一定是最小的数,只要随便拿个数比他大就交换他俩,大的那个数进入堆后再建小堆,大的数就沉在最下面,所以最后堆里面一定是K个最大的数

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <time.h>
  4. void Swap(HPDataType* p1, HPDataType* p2)
  5. {
  6. HPDataType tmp = *p1;
  7. *p1 = *p2;
  8. *p2 = tmp;
  9. }
  10. void AdjustDown(HPDataType* a, int size, int parent)
  11. {
  12. int child = parent * 2 + 1;
  13. while (child < size) {
  14. if (child + 1 < size && a[child + 1] < a[child]) {
  15. child++;
  16. }
  17. if (a[child] < a[parent]) {
  18. Swap(&a[child], &a[parent]);
  19. parent = child;
  20. child = parent * 2 - 1;
  21. }
  22. else {
  23. break;
  24. }
  25. }
  26. }
  27. void CreateNData()
  28. {
  29. int n = 100000;
  30. srand(time(0));
  31. const char* file = "data.txt";
  32. FILE* fin = fopen(file, "w");
  33. if (fin == NULL)
  34. {
  35. perror("fopen error");
  36. return;
  37. }
  38. for (size_t i = 0; i < n; i++) {
  39. int x = rand() % 10000000;
  40. fprintf(fin, "%d\n", x);
  41. }
  42. fclose(fin);
  43. }
  44. void PrintTopK(int k)
  45. {
  46. const char* file = "data.txt";
  47. FILE* fout = fopen(file, "r");
  48. if (fout == NULL)
  49. {
  50. perror("fopen error");
  51. return;
  52. }
  53. int* kminheap = (int*)malloc(sizeof(int) * k);
  54. if (kminheap == NULL)
  55. {
  56. perror("malloc error");
  57. return;
  58. }
  59. for (int i = 0; i < k; i++)
  60. {
  61. fscanf(fout, "%d", &kminheap[i]);
  62. }
  63. // 建小堆
  64. for (int i = (k - 1 - 1) / 2; i >= 0; i--)
  65. {
  66. AdjustDown(kminheap, k, i);
  67. }
  68. int val = 0;
  69. while (!feof(fout))
  70. {
  71. fscanf(fout, "%d", &val);
  72. if (val > kminheap[0])
  73. {
  74. kminheap[0] = val;
  75. AdjustDown(kminheap, k, 0);
  76. }
  77. }
  78. for (int i = 0; i < k; i++)
  79. {
  80. printf("%d ", kminheap[i]);
  81. }
  82. printf("\n");
  83. fclose(fout);
  84. }
  85. int main()
  86. {
  87. CreateNData();
  88. PrintTopK(5);
  89. return 0;
  90. }


2. 二叉树(BinaryTree)

2.1 介绍

前面我们的完全二叉树和满二叉树是使用数组来存储,如果不是完全二叉树和满二叉树就不适合使用数组存储,更适合链式结构来存储

二叉树是:

                1. 空树

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

                3.二叉树是递归结构

二叉树是整棵树拆分为根和子树,然后拆分过的子树再作为根继续拆分 ,一直这样持续至最后一个没有子树的根


在遍历之前先手搓一个二叉树的基础模板(Creat Binary Tree):

  1. #pragma once
  2. #include<stdio.h>
  3. #include<stdlib.h>
  4. #include<stdbool.h>
  5. #include<assert.h>
  6. #include<stdbool.h>
  7. typedef int BTDataType;
  8. typedef struct BinaryTreeNode
  9. {
  10. BTDataType val;
  11. struct BinaryTreeNode* left;
  12. struct BinaryTreeNode* right;
  13. }BTNode;
  14. BTNode* BuyNode(int x)
  15. {
  16. BTNode* node = (BTNode*)malloc(sizeof(BTNode));
  17. if (node == NULL)
  18. {
  19. perror("malloc fail");
  20. return NULL;
  21. }
  22. node->val = x;
  23. node->left = NULL;
  24. node->right = NULL;
  25. return node;
  26. }
  27. BTNode* CreatBinaryTree()
  28. {
  29. BTNode* node1 = BuyNode(1);
  30. BTNode* node2 = BuyNode(2);
  31. BTNode* node3 = BuyNode(3);
  32. BTNode* node4 = BuyNode(4);
  33. BTNode* node5 = BuyNode(5);
  34. BTNode* node6 = BuyNode(6);
  35. //node1的左和右指向node2和node4
  36. node1->left = node2;
  37. node1->right = node4;
  38. //node1的左指向node3
  39. node2->left = node3;
  40. //node4的左和右指向node5和node6
  41. node4->left = node5;
  42. node4->right = node6;
  43. return node1;
  44. }
  45. int main()
  46. {
  47. //root:根 CreatBinaryTree:创建二叉树
  48. BTNode* root = CreatBinaryTree();
  49. return 0;
  50. }

2.2 二叉树的遍历

前序遍历 (Prer Order)   

访问顺序:(根  左子树 右子树  )任何一棵树的访问,都要符合前序,被拆成根   左子树  右子树

访问顺序为:

 

  1. //前序
  2. void PrerOrder(BTNode* root)
  3. {
  4. //如果根为空
  5. if (root == NULL)
  6. {
  7. printf("N ");
  8. return;
  9. }
  10. else
  11. {
  12. //打印根的数
  13. printf("%d\n", root->val);
  14. //打印完之后访问根的左子树和右子树
  15. PrerOrder(root->left);
  16. PrerOrder(root->right);
  17. }
  18. }

                        代码执行完成之后就进行递归调用,一直到遇到空根结束

  1. int main()
  2. {
  3. //root:根 CreatBinaryTree:创建二叉树
  4. BTNode* root = CreatBinaryTree();
  5. PrerOrder(root);
  6. printf("\n");
  7. return 0;
  8. }


中序遍历(In Order)

访问顺序:(左子树   根  右子树 )任何一棵树的访问,都要符合中序,被拆成左子树   根  右子树

访问顺序为:

  1. //中序
  2. void InOrder(BTNode* root)
  3. {
  4. //如果根为空
  5. if (root == NULL)
  6. {
  7. printf("N ");
  8. return;
  9. }
  10. else
  11. {
  12. //先访问左子树
  13. InOrder(root->left);
  14. //打印根的数
  15. printf("%d\n", root->val);
  16. //打印完之后访问根的右子树
  17. InOrder(root->right);
  18. }
  19. }
  1. int main()
  2. {
  3. //root:根 CreatBinaryTree:创建二叉树
  4. BTNode* root = CreatBinaryTree();
  5. //中序
  6. //InOrder(root);
  7. printf("\n");
  8. return 0;
  9. }


后序遍历(Post Order)

访问顺序:(左子树  右子树   根)任何一棵树的访问,都要符合后序,被拆成左子树  右子树   根

访问顺序为: 

  1. //后序
  2. void PostOrder(BTNode* root)
  3. {
  4. //如果根为空
  5. if (root == NULL)
  6. {
  7. printf("N ");
  8. return;
  9. }
  10. else
  11. {
  12. //先访问左子树和右子树
  13. PostOrder(root->left);
  14. PostOrder(root->right);
  15. //再打印根的数
  16. printf("%d\n", root->val);
  17. }
  18. }

  1. int main()
  2. {
  3. //root:根 CreatBinaryTree:创建二叉树
  4. BTNode* root = CreatBinaryTree();
  5. //前序
  6. //PrerOrder(root);
  7. //中序
  8. //InOrder(root);
  9. //后序
  10. PostOrder(root);
  11. printf("\n");
  12. return 0;
  13. }


求二叉树节点的个数 (Tree Size):

节点个数:

                1.如果为空,则为0

                2.如果不为空,则是左子树 + 右子树 + 1

  1. //求整棵树节点的个数
  2. int TreeSize(BTNode* root)
  3. {
  4. //如果为空则返回0,不为空则返回左子树加右子树加1
  5. return root == NULL ? 0 :TreeSize(root->left) + TreeSize(root->right) + 1;
  6. }
  1. int main()
  2. {
  3. //root:根 CreatBinaryTree:创建二叉树
  4. BTNode* root = CreatBinaryTree();
  5. //前序
  6. //PrerOrder(root);
  7. //中序
  8. //InOrder(root);
  9. //后序
  10. //PostOrder(root);
  11. //printf("\n");
  12. //求整棵树节点的个数
  13. printf("TreeSize:%d\n", TreeSize(root));
  14. return 0;
  15. }


获取叶子节点个数(Tree Leaf Size):

叶子:就是度为0,不包括任何子节点,通俗来讲就是没有孩子的节点

  1. //获取叶子节点个数
  2. int TreeLeafSize(BTNode* root)
  3. {
  4. if (root == NULL)
  5. return 0;
  6. if (root->left == NULL && root->right == NULL)
  7. return 1;
  8. return TreeLeafSize(root->left)
  9. + TreeLeafSize(root->right);
  10. }
  1. int main()
  2. {
  3. //root:根 CreatBinaryTree:创建二叉树
  4. BTNode* root = CreatBinaryTree();
  5. //前序
  6. //PrerOrder(root);
  7. //中序
  8. //InOrder(root);
  9. //后序
  10. //PostOrder(root);
  11. //printf("\n");
  12. //求整棵树节点的个数
  13. //printf("TreeSize:%d\n", TreeSize(root));
  14. //获取叶子节点个数
  15. printf("TreeLeafSize:%d\n", TreeLeafSize(root));
  16. return 0;
  17. }


二叉树的高度 (Tree Height):

                        二叉树的高度是有几层高度就是几

  1. //二叉树的高度
  2. int TreeHeight(BTNode* root)
  3. {
  4. if (root == NULL)
  5. return 0;
  6. //使用两个变量记录下来,避免重复计算
  7. int leftHeight = TreeHeight(root->left);
  8. int rightHeight = TreeHeight(root->right);
  9. return leftHeight > rightHeight ?
  10. leftHeight + 1 : rightHeight + 1;
  11. }
  1. int main()
  2. {
  3. //root:根 CreatBinaryTree:创建二叉树
  4. BTNode* root = CreatBinaryTree();
  5. //前序
  6. //PrerOrder(root);
  7. //中序
  8. //InOrder(root);
  9. //后序
  10. //PostOrder(root);
  11. //printf("\n");
  12. //求整棵树节点的个数
  13. //printf("TreeSize:%d\n", TreeSize(root));
  14. //获取叶子节点个数
  15. //printf("TreeLeafSize:%d\n", TreeLeafSize(root));
  16. //二叉树的高度
  17. printf("TreeHeight:%d\n", TreeHeight(root));
  18. return 0;
  19. }

 二叉树第k层结点个数:

  1. // 二叉树第k层节点个数
  2. int TreeLevelKSize(BTNode* root, int k)
  3. {
  4. if (root == NULL)
  5. return 0;
  6. if (k == 1)
  7. return 1;
  8. // 子问题
  9. return TreeLevelKSize(root->left, k - 1)
  10. + TreeLevelKSize(root->right, k - 1);
  11. }


二叉树查找值为x的结点:

  1. // 二叉树查找值为x的节点
  2. BTNode* TreeFind(BTNode* root, BTDataType x)
  3. {
  4. if (root == NULL)
  5. return NULL;
  6. if (root->val == x)
  7. return root;
  8. BTNode* ret1 = TreeFind(root->left, x);
  9. //如果找到了直接返回数值,没有找到直接返回空
  10. if (ret1)
  11. return ret1;
  12. BTNode* ret2 = TreeFind(root->right, x);
  13. //如果找到了直接返回数值,没有找到直接返回空
  14. if (ret2)
  15. return ret2;
  16. return NULL;
  17. }


                                                            休息一下,马上回来~                                                            

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

闽ICP备14008679号