返回首页返回书籍《Hello 算法》
目录

目录 · CONTENTS

  1. 01序
  2. 02前言
  3. 03关于本书
  4. 04如何使用本书
  5. 05小结
  6. 06初识算法
  7. 07算法无处不在
  8. 08算法是什么
  9. 09小结
  10. 10复杂度分析
  11. 11算法效率评估
  12. 12迭代与递归
  13. 13时间复杂度
  14. 14空间复杂度
  15. 15小结
  16. 16练习
  17. 17数据结构
  18. 18数据结构分类
  19. 19基本数据类型
  20. 20数字编码
  21. 21字符编码
  22. 22小结
  23. 23练习
  24. 24数组与链表
  25. 25数组
  26. 26链表
  27. 27列表
  28. 28内存与缓存
  29. 29小结
  30. 30练习
  31. 31栈与队列
  32. 32栈
  33. 33队列
  34. 34双向队列
  35. 35小结
  36. 36练习
  37. 37哈希表
  38. 38哈希表
  39. 39哈希冲突
  40. 40哈希算法
  41. 41小结
  42. 42练习
  43. 43树
  44. 44二叉树
  45. 45二叉树遍历
  46. 46二叉树数组表示
  47. 47二叉搜索树
  48. 48AVL 树
  49. 49小结
  50. 50练习
  51. 51堆
  52. 52堆
  53. 53建堆操作
  54. 54Top-k 问题
  55. 55小结
  56. 56练习
  57. 57图
  58. 58图
  59. 59图的基础操作
  60. 60图的遍历
  61. 61小结
  62. 62练习
  63. 63搜索
  64. 64二分查找
  65. 65二分查找插入点
  66. 66二分查找边界
  67. 67哈希优化策略
  68. 68重识搜索算法
  69. 69小结
  70. 70练习
  71. 71排序
  72. 72排序算法
  73. 73选择排序
  74. 74冒泡排序
  75. 75插入排序
  76. 76快速排序
  77. 77归并排序
  78. 78堆排序
  79. 79桶排序
  80. 80计数排序
  81. 81基数排序
  82. 82小结
  83. 83练习
  84. 84分治
  85. 85分治算法
  86. 86分治搜索策略
  87. 87构建二叉树问题
  88. 88汉诺塔问题
  89. 89小结
  90. 90练习
  91. 91回溯
  92. 92回溯算法
  93. 93全排列问题
  94. 94子集和问题
  95. 95n 皇后问题
  96. 96小结
  97. 97练习
  98. 98动态规划
  99. 99初探动态规划
  100. 100动态规划问题特性
  101. 101动态规划解题思路
  102. 1020-1 背包问题
  103. 103完全背包问题
  104. 104编辑距离问题
  105. 105小结
  106. 106练习
  107. 107贪心
  108. 108贪心算法
  109. 109分数背包问题
  110. 110最大容量问题
  111. 111最大切分乘积问题
  112. 112小结
  113. 113练习
  114. 114附录
  115. 115编程环境安装
  116. 116一起参与创作
  117. 117术语表
  118. 118参考文献
  119. 119纸质书
第 23 / 119 节

第 23 节 · SECTION 23

练习

知识巩固

生活场景中的数据关系

请根据数据之间的关系,为下面三个场景选择“线性结构、树形结构、网状结构”中的一种,并说明理由:

  1. 同学们排成一列,每人只关心自己前面和后面的人;
  2. 学校按“学校 → 年级 → 班级”分层管理;
  3. 城市道路连接多个路口,一个路口可以通向多个其他路口,也可能形成环路。

参考答案

  1. 是线性结构。除排在最前和最后的人外,每个人都只与前面和后面各一人相邻,关系沿一条线展开。

  2. 是树形结构。每个班级属于一个年级,每个年级又属于学校,关系从上到下分层展开。

  3. 是网状结构。一个路口可以连接多个路口,路线之间还能形成环,不能排成单一顺序或严格层级。

    判断结构时应先观察元素之间的关系,而不是先考虑它在内存中占多少空间。

逻辑顺序怎样存进内存

为了保存逻辑顺序 A → B → C,现有两种简化的内存安排:

  • 方案甲:A、B、C 分别放在编号为 20、21、22 的内存格中;
  • 方案乙:A、B、C 分别放在编号为 20、7、31 的内存格中,并由 A 记录 B 的位置、B 记录 C 的位置。
  1. 哪个方案属于连续空间存储?哪个属于分散空间存储?
  2. 两个方案分别更接近数组还是链表?
  3. 方案乙的内存格编号没有按大小排列,为什么仍能表示 A → B → C 的逻辑顺序?

参考答案

  1. 方案甲使用连续的内存格,属于连续空间存储;方案乙的节点分散在不同位置,属于分散空间存储。

  2. 方案甲更接近数组,方案乙更接近链表。

  3. 逻辑顺序由节点之间记录的连接关系决定,而不是由内存格编号的大小决定。 从 A 记录的位置可以找到 B,再从 B 记录的位置找到 C,所以仍能依次访问 A、B、C。

    这也说明逻辑结构和物理结构是观察同一组数据的两个不同角度。

作业记录中的数据类型与结构

某学习小组按座位顺序记录 4 名同学是否交了作业,得到:

[true, false, true, true]

  1. 每个元素适合使用哪种基本数据类型?
  2. 这 4 个元素按座位顺序排成一列,使用了什么逻辑结构?
  3. 如果以后改为记录每人的作业分数 [90, 0, 85, 100],改变的是数据的“内容类型”还是“组织方式”?说明理由。

参考答案

  1. 每个元素只表示“是”或“否”,适合使用布尔类型 bool。

  2. 这些元素按座位顺序排列,形成线性结构,可以用数组保存。

  3. 改变的是内容类型:元素由布尔值变成了整数。组织方式没有改变, 这些数据仍然按座位顺序排成一列,仍可使用数组这一线性结构。

    基本数据类型描述“存的是什么”,数据结构描述“数据怎样组织”。

编程练习

统计二进制表示中的 1

给定非负整数 n,请统计它的二进制表示中共有多少个 1。

要求使用位运算完成,不把二进制表示转换成字符串,也不使用直接统计 1 的内置函数。

解题提示

  1. n & 1 可以取出 n 的最右边一位,用它判断这一位是否为 1
  2. 右移一位表示丢掉当前最右边的二进制位;多数语言使用运算符 >>
  3. 完成逐位检查并右移的方法后,再观察:n & (n - 1) 会把 n 中最右边的一个 1 变成 0

LeetCode 题目解析