文章目录

  • 前言
  • 1.堆的应用
    • 1.1堆排序
    • 1.2时间复杂度
    • 1.3topk问题
  • 2.二叉树链式结构的实现
    • 2.1二叉树的遍历
    • 2.2部分代码递归图解
      • 前序递归
      • 中序递归
      • 求第k层的结点
      • 二叉树查找值为x的结点
    • 2.3完整代码:

前言

本篇文章主要讲解堆的应用以及链式二叉树的实现与应用
通过这篇文章,大家应该能对堆与二叉树更好的理解


1.堆的应用

1.1堆排序

升序 -- 建大堆
降序 -- 建小堆
如果每次都使用建堆选数,整体的时间复杂度是O(N)
利用堆删除思想来进行排序

//  1、你得先写一个Hp数据结构,反而复杂
//  2、有O(N)空间复杂度//void HeapSort(int* a, int n)//{// HP hp;//    HeapInit(&hp);//    for (int i = 0; i < n; ++i)// {//     HeapPush(&hp, a[i]);//  }////   int i = 0;//   while (!HeapEmpty(&hp))//   {//     a[i++] = HeapTop(&hp);//     HeapPop(&hp);// }// HeapDestroy(&hp);//}
// 升序 -- 建大堆// 降序 -- 建小堆void HeapSort(int* a, int n){ 建堆方式1:O(N*logN)//for (int i = 1; i < n; ++i)//{//    AdjustUp(a, i);//}// 建堆方式2:O(N)for (int i = (n-1-1)/2; i >= 0; --i){AdjustDwon(a, n, i);}// O(N*logN)int end = n - 1;while (end > 0){Swap(&a[0], &a[end]);AdjustDwon(a, end, 0);--end;}
}void TestHeapSort(){// 升序打印 -- 小堆// 降序打印 -- 大堆/*HP hp;HeapInit(&hp);int a[] = { 27, 15, 19, 18, 28, 34, 65, 49, 25, 37 };for (int i = 0; i < sizeof(a) / sizeof(int); ++i){HeapPush(&hp, a[i]);}while (!HeapEmpty(&hp)){printf("%d ", HeapTop(&hp));HeapPop(&hp);}printf("\n");*/int a[] = { 27, 15, 19, 18, 28, 34, 65, 49, 25, 37 };HeapSort(a, sizeof(a) / sizeof(int));}int main(){TestHeapSort();return 0;
}

1.2时间复杂度

向上调整是从最后一排开始调整,但向下调整没算最后一排,而且,最后一排结点数比较多,差不多占了总结点的一半,所以向上调整的时间复杂度就比较大

1.3topk问题

N个数中找出最大或最小的前k个
N是远大于k的

找最大前k个:
排序 O(N*logN)
N个数的大堆,Top/Pop k次 O(N+logN*K)

假设N非常大(100亿),k比较小(100),该如何求解?

  1. 建立k个数的小堆 O(k+(N-k)*logk) 空间效率比较高
  2. 剩下的N-k个一次跟堆顶的数据比较,若比堆顶数据大,就替换堆顶数据进堆 走完以后,堆里面的k个数就是最大的前k个
void PrintTopK(int* a, int n, int k)
{// 1. 建堆--用a中前k个元素建堆int* kMinHeap = (int*)malloc(sizeof(int)*k);assert(kMinHeap);for (int i = 0; i < k; ++i){kMinHeap[i] = a[i];}for (int i = (k - 1 - 1) / 2; i >= 0; --i){AdjustDwon(kMinHeap, k, i);}// 2. 将剩余n-k个元素依次与堆顶元素交换,不满则则替换for (int j = k; j < n; ++j){if (a[j] > kMinHeap[0]){kMinHeap[0] = a[j];AdjustDwon(kMinHeap, k, 0);}}for (int i = 0; i < k; ++i){printf("%d ", kMinHeap[i]);}printf("\n");
}void TestTopk()
{int n = 10000;int* a = (int*)malloc(sizeof(int)*n);srand(time(0));for (int i = 0; i < n; ++i){a[i] = rand() % 1000000;}a[5] = 1000000 + 1;a[1231] = 1000000 + 2;a[531] = 1000000 + 3;a[5121] = 1000000 + 4;a[120] = 1000000 + 5;a[99] = 1000000 + 6;a[0] = 1000000 + 7;a[76] = 1000000 + 8;a[423] = 1000000 + 9;a[3144] = 1000000 + 10;PrintTopK(a, n, 10);
}int main()
{TestTopk();return 0;
}

2.二叉树链式结构的实现

注意:
普通二叉树的增删查改并没有意义

如果只用二叉树存储数据,不如用顺序表和链表,那为什么还要学呢?

  1. 为学习后面更复杂的二叉树打基础(搜索二叉树,红黑树,B树,AVL树……)快速搜索数据,他们的增删查找才有意义
  2. 许多有关二叉树的oj算法题,都是出在普通二叉树上

2.1二叉树的遍历

递归结构遍历:
区别在于:访问根的时机

  1. 前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点的操作发生在遍历其左右子树之前。
    根 左子树 右子树

  2. 中序遍历(Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之中(间)
    左子树 根 右子树

  3. 后序遍历(Postorder Traversal)——访问根结点的操作发生在遍历其左右子树之后。
    左子树 右子树 根

注意:
任何一棵子树都要被分成根,左子树和右子树,只有空树才是不能再被分割的

2.2部分代码递归图解

前序递归

//前序遍历
void PreOrder(BTNode* root)
{if (root == NULL){printf("# ");return;}printf("%d ", root->data);//根PreOrder(root->left);//左子树PreOrder(root->right);//右子树
}

中序递归


//中序
void InOrder(BTNode* root){if (root == NULL){printf("# ");return;}InOrder(root->left);printf("%d ", root->data);InOrder(root->right);
}

求第k层的结点

二叉树查找值为x的结点

假设查找的是5,用前序最方便
注意:递归是层层调用,不是一次就返回过去
如果右边没有找到才会去左边找,如果右边找到是直接返回的

2.3完整代码:

//定义一个链式二叉树
typedef int BTDataType;
typedef struct BinaryTreeNode
{struct BinaryTreeNode* left;struct BinaryTreeNode* right;BTDataType data;}BTNode;//处理空树
BTNode* BuyNode(BTDataType x)
{BTNode* node = (BTNode*)malloc(sizeof(BTNode));assert(node);node->data = x;node->left = NULL;node->right = NULL;return node;
}//手搓一个二叉树
BTNode* CreatBinaryTree()
{BTNode* node1 = BuyNode(1);BTNode* node2 = BuyNode(2);BTNode* node3 = BuyNode(3);BTNode* node4 = BuyNode(4);BTNode* node5 = BuyNode(5);BTNode* node6 = BuyNode(6);node1->left = node2;node1->right = node4;node2->left = node3;node4->left = node5;node4->right = node6;return node1;
}//前序遍历
void PreOrder(BTNode* root)
{if (root == NULL){printf("# ");return;}printf("%d ", root->data);//根PreOrder(root->left);//左子树PreOrder(root->right);//右子树
}//中序
void InOrder(BTNode* root){if (root == NULL){printf("# ");return;}InOrder(root->left);printf("%d ", root->data);InOrder(root->right);
}//后序
void PostOrder(BTNode* root){if (root == NULL){printf("# ");return;}PostOrder(root->left);PostOrder(root->right);printf("%d ", root->data);
}//计数
//定义全局变量
int count = 0;
void TreeSize1(BTNode* root)
{if (root == NULL){return;}++count;TreeSize1(root->left);TreeSize1(root->right);
}//解决不用置空的问题,用分治的思路
int TreeSize2(BTNode* root)
{return root == NULL ? 0 : TreeSize2(root->left) + TreeSize2(root->right) + 1;
}//求叶子结点数量
//分三步走
int TreeLeafSize(BTNode* root)
{if (root == NULL)return 0;if (root->left == NULL && root->right == NULL)return 1;return TreeLeafSize(root->left) + TreeLeafSize(root->right);
}//求第k层结点数
//转换成子问题:求左子树的第k-1层 + 求右子树的第k-1层
int TreeKLevel(BTNode* root, int k)
{assert(k >= 1);if (root == NULL)return 0;if (k == 1)return 1;return TreeKLevel(root->left, k - 1)+ TreeKLevel(root->right, k - 1);
}int main()
{BTNode* root = CreatBinaryTree();PreOrder(root);printf("\n");InOrder(root);printf("\n");PostOrder(root);printf("\n");//每次调用之前要置空,防止叠加count = 0;TreeSize1(root);printf("TreeSize:%d\n", count);count = 0;TreeSize1(root);printf("TreeSize:%d\n", count);printf("TreeSize:%d\n", TreeSize2(root));printf("TreeSize:%d\n", TreeSize2(root));printf("LeafSize:%d\n", TreeLeafSize(root));printf("KLevelSize:%d\n", TreeKLevel(root, 2));printf("KLevelSize:%d\n", TreeKLevel(root, 3));printf("KLevelSize:%d\n", TreeKLevel(root, 4));return 0;
}// 二叉树查找值为x的结点
BTNode* TreeFind(BTNode* root, BTDataType x)
{if (root == NULL)return NULL;if (root->data == x)return root;BTNode* ret1 = TreeFind(root->left, x);if (ret1)return ret1;BTNode* ret2 = TreeFind(root->right, x);if (ret2)return ret2;return NULL;
}// 二叉树查找值为x的结点
BTNode* TreeFind(BTNode* root, BTDataType x)
{if (root == NULL)return NULL;if (root->data == x)return root;BTNode* ret1 = TreeFind(root->left, x);if (ret1)return ret1;BTNode* ret2 = TreeFind(root->right, x);if (ret2)return ret2;return NULL;
}// 求二叉树深度
//求左子树的深度和右子树的深度,在其中大的那个加一就是总的深度
//后序
int TreeDepth(BTNode* root);
{if (root == NULL){return 0;}int leftDepth = TreeDepth(root->left);int rightDepth = TreeDepth(root->right);return leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;
}//二叉树的销毁
//用后序销毁
//先销毁左子树再销毁右子树最后销毁根结点
void TreeDestroy(BTNode* root)
{if(root == NULL){return;}TreeDestroy(root->left);TreeDestroy(root->right);free(root);
}

一目了然——堆与二叉树相关推荐

  1. java sbt二叉树,Treap——堆和二叉树的完美结合,性价比极值的搜索树

    大家好,今天和大家聊一个新的数据结构,叫做Treap. Treap本质上也是一颗BST(平衡二叉搜索树),和我们之前介绍的SBT是一样的.但是Treap维持平衡的方法和SBT不太一样,有些许区别,相比 ...

  2. 【CCCC】L2-012 关于堆的判断 (25分),,手写堆,二叉树编号,向上调整

    problem L2-012 关于堆的判断 (25分) 将一系列给定数字顺序插入一个初始为空的小顶堆H[].随后判断一系列相关命题是否为真.命题分下列几种: x is the root:x是根结点: ...

  3. 一目了然——堆的概念及结构

    文章目录 1.堆的概念和结构 1.1堆的概念 1.2堆的性质 1.3小根堆与大根堆 1.4堆的意义 1.5堆的实现 1.5.1完整代码 1.6选择题 1.堆的概念和结构 1.1堆的概念 如果有一个关键 ...

  4. 数据结构-二叉树和堆的实现

    二叉树 树的概念和结构 概念 结构 树的其他概念名词 树的孩子兄弟表示法 树的实际应用 二叉树的概念和结构 概念 特殊的二叉树 二叉树的性质 二叉树的存储结构 二叉树的顺序结构-堆 堆的实现 堆的向下 ...

  5. 数据结构与算法 —— 二叉树

    二叉树 定义: 来自于百度百科. 在计算机科学中,二叉树是每个节点最多有两个子树的树结构.通常子树被称作"左子树"(left subtree)和"右子树"(ri ...

  6. 数据结构-二叉树面试 常考

    摘要]计算机科学中,二叉树是每个节点最多有两个子树的树结构.通常子树被称作"左子树"(left subtree)和"右子树"(right subtree).二叉 ...

  7. 数据结构与算法-二叉树(java描述)

    一.概述 1.1.树的概念 树状图是一种数据结构,它是由n(n>=1)个有限节点组成一个具有层次关系的集合.把它叫做"树"是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而 ...

  8. 树与二叉树的深度优先与广度优先算法(递归与非递归)

    本博客前面文章已对树与二叉树有过简单的介绍,本文主要是重点介绍有关二叉树的一些具体操作与应用 阅读本文前,可以先参考本博客 各种基本算法实现小结(三)-- 树与二叉树   和  各种基本算法实现小结( ...

  9. java 对称的二叉树

    1. 对称的二叉树 1. 题目描述 请实现一个函数,用来判断一颗二叉树是不是对称的.注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的. 2. 解题思路 可以按照类似层次遍历,来判断是否是堆 ...

最新文章

  1. Spring MVC+Spring+MyBatis实现支付宝扫码支付功能(图文详解)
  2. struts2_HelloWorld
  3. java控制台打印图片_java——控制台输入打印图形
  4. Tiny210 编译Linux3.0.8
  5. java支持闭包_JAVA 需要引入闭包吗
  6. php读取大文件某行内容,PHP读取和修改大文件的某行内容_PHP教程
  7. 比特红:万物可直播、人人能带货
  8. 【软件工程】结构图(SC)——期末复习用
  9. 人工雨量计_自动站与人工站遥测雨量计降水量对比分析
  10. 专业技术问题:UI设计师岗位面试反馈的常见问题
  11. 从Technorati看博客搜索的发展
  12. 【Unity】Button基础-按钮更换图片样式
  13. 名词用作动词举例_中学文言文词类活用详解:名词活用作动词(一)
  14. python同切圆_Python绘制同切圆和同心圆
  15. 敏捷项目中的进度控制
  16. js经典代码200句
  17. c++运算符优先级归纳
  18. 洛谷刷题:小玉家的电费、小玉在游泳、小鱼的航程(改进版)、小鱼的游泳时间、小鱼会有危险吗
  19. LeetCode 力扣 算法题解 1109. 航班预订统计(Corporate Flight Bookings) n 个航班,它们分别从 1 到 n 进行编号,请返回每个航班预定的座位总数。
  20. JPA 关联表添加关联条件@Where、@WhereJoinTable()

热门文章

  1. vector赋值操作
  2. p6-day01 作业
  3. 计算机专业开日语选修课,大学最“值钱”的四门选修课,选上了真幸运,上课别“摸鱼”...
  4. 6-4 删除字符 (10分)
  5. android 接入阿里百川,阿里百川android 引入SDK
  6. LWN:扩展KVM社区!
  7. QT+OpenGL光照
  8. DBCO-Sulfo-NHS ester,1400191-52-7含有DBCO部分的水溶性硫化试剂
  9. VS生成的exe文件在VS运行没问题,在文件夹打开直接运行出问题的bug解决办法
  10. B1016_部分A+B