再谈二叉树

本文介绍了二叉搜索树的基本概念及其优势,详细讲解了二叉搜索树的时间复杂度,并通过实例说明了查找效率。此外还提供了创建、遍历及查询二叉搜索树的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

由于树结构经常是面试官拷问的知识点,掌握好它是必须的,又看了些资料,再试着记录一点心得。

一般无规律的树没什么意义,太复杂面试时间也有限。所以主要讨论的是二元搜索树(binary search tree)

二元搜索树的优势是查找很快。时间复杂度是O(log2(n)),也常写成O(log(n)).
因为比如

    70
   /  /
  50   90
 / /   / /
40 45 80 120
 
查询40这个节点,需要3次遍历,整个树节点是7。  于是有这个关系
       2x = n (x代表次数, n代表节点树(data size))

       x = log2n 

这种指数级的速度是很快的。2的10次方等于1204, 在这里等效为最多10次就可以从1024个数据中找出需要的节点来。

不过如果二叉树左右分布不均的话,甚至每个节点只有一个右节点,这样就成了链结构,就失去了该优势。

代码:

结构定义:
  1. typedef struct nodeT
  2. {
  3.     struct nodeT *left;
  4.     struct nodeT *right;
  5.     int value;
  6. }node;

初始化二元搜索树

  1. #include <assert.h>
  2. #define NUM 7
  3. int data[NUM] = {70, 50, 90, 40, 45, 80, 120};
  4. /*
  5. input:
  6. data: 新节点data值
  7. return:
  8. 新节点指针
  9. */
  10. PNode newNode(int data)
  11. {
  12.     PNode p = (PNode)malloc(sizeof(Node));
  13.     assert( p != NULL);
  14.     p->data = data;
  15.     p->lChild = NULL;
  16.     p->rChild = NULL;
  17.     return p;
  18. }
  19. /* 
  20. return:
  21.   false:插入重复data值节点
  22.   true: 成功构建
  23. */
  24. bool CreateBTree(PNode &root)
  25. {
  26.     int i;
  27.     root = newNode(data[0]);
  28.     PNode p;
  29.     PNode parent;
  30.     for (i=1; i<NUM; i++)
  31.     {
  32.         p = root;
  33.         while (p != NULL)
  34.         {
  35.             // 保存插入节点的父节点
  36.             parent = p;
  37.             if (data[i] > p->data)
  38.                 p = p->rChild;
  39.             else if (data[i] < p->data)
  40.                 p = p->lChild;
  41.             // 要求节点data值不重复
  42.             else
  43.                 return false;
  44.         }
  45.         if (p == NULL)
  46.         {
  47.             // 新建节点,设置其data值和父节点
  48.             p = newNode(data[i]);
  49.             //p->parent = parent;
  50.             if (p->data < parent->data)
  51.                 parent->lChild = p;
  52.             else
  53.                 parent->rChild = p;
  54.         }
  55.     }
  56.     return true;
  57. }
遍历:

  1. void PreOrderTraversal(PNode root)
  2. {
  3.     if (root == NULL)
  4.         return;
  5.     else
  6.     {
  7.         // printf的位置决定了三种遍历方法
  8.         printf("%d ", root->data);
  9.         PreOrderTraversal(root->lChild);
  10.         PreOrderTraversal(root->rChild);
  11.     }
  12. }

查询节点:
  1. /*
  2. params:
  3.   value: 寻找data值为value的节点
  4. return:
  5.   成功: 返回该节点
  6.   失败: 返回NULL
  7. */
  8. PNode SearchNode(PNode root, int value)
  9. {
  10.     if (root == NULL)
  11.         return NULL;
  12.     
  13.     PNode p = root;
  14.     while (p)
  15.     {
  16.         if (p->data < value)
  17.             p = p->rChild;
  18.         else if (p->data > value)
  19.             p = p->lChild;
  20.         else
  21.             return p;
  22.     }   
  23.     return NULL;
  24. }
增加父节点
  1. PNode newNode(int data)
  2. {
  3.     PNode p = (PNode)malloc(sizeof(Node));
  4.     assert( p != NULL);
  5.     p->data = data;
  6.     p->lChild = NULL;
  7.     p->rChild = NULL;
  8.     p->parent = NULL;   //添加
  9.     return p;
  10. }
  11. /*
  12. 添加父节点
  13. */
  14. void AddParent(PNode root)
  15. {
  16.     PNode p;
  17.     if (root == NULL)
  18.         return;
  19.     p = root;
  20.     if (root->lChild != NULL)
  21.     {
  22.         root->lChild->parent = p;
  23.         AddParent(root->lChild);
  24.     }
  25.     if (root->rChild != NULL)
  26.     {
  27.         root->rChild->parent = p;
  28.         AddParent(root->rChild);
  29.     }
  30. }



           
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值