当前位置:   article > 正文

数据结构——二叉树(OJ练习)

数据结构——二叉树(OJ练习)

大家好,本期是二叉树的最后一期,这一期我们来看看二叉树的编程题

单值二叉树

. - 力扣(LeetCode)

首先我们的思路是:遍历二叉树,把每个节点去比较一次,按照要求返回

我们来看代码

  1. bool isUnivalTree(struct TreeNode* root) {
  2. if(root==NULL){
  3. return true;
  4. }
  5. if(root->left&&root->left->val!=root->val){
  6. return false;
  7. }
  8. if(root->right&&root->right->val!=root->val){
  9. return false;
  10. }
  11. return isUnivalTree(root->left) && isUnivalTree(root->right);
  12. }

检查两颗树是否相同

. - 力扣(LeetCode)

这里我们的思路是:同时遍历两给树,遇到空树或者不相等时返回。

  1. bool isSameTree(struct TreeNode* p, struct TreeNode* q) {
  2. if(p==NULL&&q==NULL){
  3. return true;
  4. }
  5. if(p==NULL||q==NULL){
  6. return false;
  7. }
  8. if(p->val!=q->val){
  9. return false;
  10. }
  11. return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);
  12. }

对称二叉树

. - 力扣(LeetCode)

我们仔细观察该对称二叉树,我们发现互相对称的节点它们的左子树与右子树分别相等,这就是突破口,我们可以重新创建一个函数,将参数分成两个一左一右两个节点,然后向下比较,这个过程与上一题类似。

我们来看代码

  1. bool _isSymmetric(struct TreeNode* pl,struct TreeNode* pr){
  2. if(pl==NULL&&pr==NULL){
  3. return true;
  4. }
  5. if(pl==NULL||pr==NULL){
  6. return false;
  7. }
  8. if(pl->val!=pr->val){
  9. return false;
  10. }
  11. return _isSymmetric(pl->left,pr->right)&&_isSymmetric(pl->right,pr->left);
  12. }
  13. bool isSymmetric(struct TreeNode* root) {
  14. return _isSymmetric(root->left,root->right);
  15. }

另一颗树的子树

. - 力扣(LeetCode)

这题我们的思路是找出root所有的子树跟subroot比较,这里的比较函数我们前面已经写过了,如果相同就返回true,如果没找到就返回false

代码如下

  1. //比较函数
  2. bool pdxt(struct TreeNode*p,struct TreeNode*q){
  3. if(p==NULL&&q==NULL){
  4. return true;
  5. }
  6. if(p==NULL||q==NULL){
  7. return false;
  8. }
  9. if(p->val!=q->val){
  10. return false;
  11. }
  12. return pdxt(p->left,q->left)&&pdxt(p->right,q->right);
  13. }
  14. bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot){
  15. if(root==NULL){
  16. return false;
  17. }
  18. if(pdxt(root,subRoot)){
  19. return true;
  20. }
  21. return isSubtree( root->left, subRoot)||isSubtree( root->right, subRoot);
  22. }

二叉树的前序遍历

. - 力扣(LeetCode)

这一题可跟我们前一期的前序遍历有所不同,我们仔细观察一下他给我们的参数是一个二叉树的根和一个int*的指针,这个指针是输出型指针,也就是说这个指针是出题人用来获取二叉树节点个数的,而这个函数的返回类型是int*,它要我们返回一个存储二叉树数据的数组,所以我们这里最好动态开辟内存来存储,

所以我们的思路是用两个子函数来辅助完成,一个函数来计算二叉树的节点数一个函数用来遍历二叉树,最后由原函数返回。

  1. int evertreenode(struct TreeNode* root){
  2. return root==NULL?0: evertreenode(root->left)+evertreenode(root->right)+1;
  3. }
  4. void qianxu(struct TreeNode*root,int*a,int*i){
  5. if(root==NULL){
  6. return;
  7. }
  8. a[(*i)++]=root->val;
  9. qianxu(root->left,a,i);
  10. qianxu(root->right,a,i);
  11. }
  12. int* preorderTraversal(struct TreeNode* root, int* returnSize) {
  13. *returnSize=evertreenode(root);
  14. int*a=(int*)malloc(sizeof(int)*(*returnSize));
  15. int i=0;
  16. qianxu(root,a,&i);
  17. return a;
  18. }

二叉树的构建与销毁

二叉树的销毁

我们的思路是遍历二叉树,把节点一个一个销毁,那么这里我们选什么方式遍历?

答案是后序,因为前序是先销毁根,如果根销毁了就找不到,只能先把左右子树先存储起来再销毁。(这里三种遍历顺序都可以,只是后序更好)。

  1. void treeDestory(BTnode* node1) {
  2. if (node1 == NULL) {
  3. return;
  4. }
  5. treeDestory(node1->lest);
  6. treeDestory(node1->right);
  7. free(node1);
  8. }

判断二叉树是否是完全二叉树

这一题我们就要用到我们上一期学习的层序遍历来实现了,主要思路是,用层序遍历如果遇到NULL后还可以遇到不为空的节点就不是完全二叉树。

说到层序遍历我们就会想到队列,下面是队列的源码大家可以直接使用

Queue.h

  1. # include<stdio.h>
  2. # include<assert.h>
  3. # include<stdlib.h>
  4. # include<string.h>
  5. # include<errno.h>
  6. # include<stdbool.h>
  7. typedef struct Qhead Qhead;
  8. typedef struct Queue Queue;
  9. typedef struct Binarytreenode BTnode;
  10. //二叉树
  11. struct Binarytreenode {
  12. int size;//保存的数据
  13. BTnode* lest;//左子树
  14. BTnode* right;//右子树
  15. };
  16. //链表结构
  17. struct Qhead {
  18. BTnode* size;
  19. struct Qhead* next;
  20. };
  21. //队列结构
  22. struct Queue {
  23. Qhead* top;//队头
  24. Qhead* end;//队尾
  25. int SZ;
  26. };
  27. //初始化
  28. void Queueinit(Queue* head);
  29. //队尾输入数据
  30. void Queuepush(Queue* head, BTnode* n);
  31. //判断队列是否为空
  32. bool QueueEmpty(Queue* haed);
  33. //队头删除数据
  34. void Queuepop(Queue* head);
  35. //获取对头数据
  36. BTnode* Queuefrost(Queue* head);
  37. //获取队列中的有效元素个数
  38. int Queuesize(Queue* head);
  39. //销毁队列
  40. void QueueDestroy(Queue* head);

Queue.c

  1. //初始化
  2. void Queueinit(Queue* head) {
  3. assert(head);
  4. head->end = NULL;
  5. head->top = NULL;
  6. head->SZ = 0;
  7. }
  8. //队尾输入数据
  9. void Queuepush(Queue* head, BTnode* n) {
  10. assert(head);
  11. Qhead* ps = (Qhead*)malloc(sizeof(Qhead));
  12. if (ps == NULL) {
  13. printf("%s", strerror(errno));
  14. return;
  15. }
  16. ps->next = NULL;
  17. ps->size = n;
  18. if (head->top) {
  19. head->end->next = ps;
  20. head->end = head->end->next;
  21. }
  22. else {
  23. head->top = ps;
  24. head->end = ps;
  25. }
  26. head->SZ++;
  27. }
  28. //判断队列是否为空
  29. bool QueueEmpty(Queue* head) {
  30. assert(head);
  31. return head->SZ == 0;
  32. }
  33. //队头删除数据
  34. void Queuepop(Queue* head) {
  35. assert(head);
  36. assert(!QueueEmpty(head));
  37. if (head->top->next == NULL) {
  38. free(head->top);
  39. head->top = NULL;
  40. head->end = NULL;
  41. }
  42. else {
  43. Qhead* cur = head->top->next;
  44. head->top->next = NULL;
  45. free(head->top);
  46. head->top = cur;
  47. }
  48. head->SZ--;
  49. }
  50. //获取队头数据
  51. BTnode* Queuefrost(Queue* head) {
  52. assert(head);
  53. assert(!QueueEmpty(head));
  54. return head->top->size;
  55. }
  56. //获取队列中的有效元素个数
  57. int Queuesize(Queue* head) {
  58. assert(head);
  59. return head->SZ;
  60. }
  61. //销毁队列
  62. void QueueDestroy(Queue* head) {
  63. assert(head);
  64. while (head->top == NULL) {
  65. Qhead* cur = head->top->next;
  66. head->top->next = NULL;
  67. free(head->top);
  68. head->top = cur;
  69. }
  70. head->top = NULL;
  71. head->end = NULL;
  72. head->SZ = 0;
  73. }

下面是判断完全二叉树的代码

  1. //判断树是不是完全二叉树
  2. bool BTcomplete(BTnode* root) {
  3. Queue head;
  4. Queueinit(&head);
  5. if(root)
  6. Queuepush(&head,root);
  7. while (!QueueEmpty(&head)) {
  8. BTnode* frost = Queuefrost(&head);
  9. Queuepop(&head);
  10. if (frost == NULL)
  11. break;
  12. Queuepush(&head, frost->lest);
  13. Queuepush(&head, frost->right);
  14. }
  15. while (!QueueEmpty(&head)) {
  16. BTnode* frost = Queuefrost(&head);
  17. Queuepop(&head);
  18. if (frost != NULL) {
  19. QueueDestroy(&head);
  20. return false;
  21. }
  22. }
  23. QueueDestroy(&head);
  24. return true;
  25. }

我们可以测试一下。

二叉树的创建

二叉树遍历_牛客题霸_牛客网

这道题我们要从一个先序数组中读取数据构建二叉树。

我们的思路是先创建一个二叉树的结构体,然后将他初始化,再从数组中按照前序来读取数据并为它们开辟一个节点来存储,然后把这些节点按前序来插入。遇到‘#’就说明这是空树。

  1. #include <stdio.h>
  2. # include<stdlib.h>
  3. //二叉树的结构
  4. typedef struct treenode BTnode;
  5. struct treenode{
  6. char size;
  7. BTnode*left;
  8. BTnode*right;
  9. };
  10. //初始化
  11. BTnode* treeinit(char add){
  12. BTnode*root=(BTnode*)malloc(sizeof(BTnode));
  13. if(root==NULL){
  14. return NULL;
  15. }
  16. root->left=NULL;
  17. root->right=NULL;
  18. root->size=add;
  19. return root;
  20. }
  21. //在二叉树中插入数据
  22. BTnode* treepush(char*ps,int*i){
  23. if(ps[*i]=='#'){
  24. (*i)++;
  25. return NULL;
  26. }
  27. BTnode*root=treeinit(ps[*i]);
  28. (*i)++;
  29. root->left=treepush(ps,i);
  30. root->right=treepush(ps,i);
  31. return root;
  32. }
  33. //中序输出
  34. void intree(BTnode*root){
  35. if(root==NULL){
  36. return;
  37. }
  38. intree(root->left);
  39. printf("%c ",root->size);
  40. intree(root->right);
  41. }
  42. int main() {
  43. int i=0;
  44. char add[100];
  45. scanf("%s",add);
  46. BTnode* root =treepush(add,&i);
  47. intree(root);
  48. return 0;
  49. }

我们可以从这道题找出二叉树创建的函数

  1. BTnode* treepush(char*ps,int*i){
  2. if(ps[*i]=='#'){
  3. (*i)++;
  4. return NULL;
  5. }
  6. BTnode*root=treeinit(ps[*i]);
  7. (*i)++;
  8. root->left=treepush(ps,i);
  9. root->right=treepush(ps,i);
  10. return root;
  11. }

经过了这几期的学习我们二叉树学习就告一段落了,这并不意味着我们二叉树已经学完了,随着我们的学习我们还会再学习二叉树的。

  以上就是全部内容了,如果有错误或者不足的地方欢迎大家给予建议。 

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

闽ICP备14008679号