第十七章:经典抽象数据类型

Github 链接:ch17. 经典抽象数据类型

抽象数据类型 (ADT) 是非常常用的,最为常见的就是数组、顺序表、链表、栈和队列等等。诸如 OS 内部的任务调度有队列、双向链表、红黑树等均被广泛应用。熟练掌握各种数据结构是非常重要且必要的。

本章总结及注意点



部分课后习题解答

17.9 问题

  1. 栈。

  2. 队列。

  3. 当然可以。程序员封装即可。top() 取栈顶元素但不进行栈顶元素的出栈,pop() 函数进行栈顶元素的出栈。

  4. 并不觉得有多强大。对于静态数组模拟的堆栈来讲,只需要将 top_element() = -1 这样进行赋值即能达到栈清空的效果。当然,C++ STL 容器中有单独的 clear 函数用来清空容器。

  5. 这完全取决于它的初始化是 -1 还是 0。

  6. 首先 assert() 主要在此用于栈判空、判满,其实也就是为了不让数组出现越界访问。若删除所有断言,则相当于数组可能会产生越界访问,这两者等价。

  7. 链式堆栈中节点都是单独申请的,所以得单独释放。且 pop() 函数中已经实现了内存的释放,所以直接栈判空+pop() 即可。

  8. 肯定不可以!这是个常见问题,当 malloc() 空间被 free 后,对应指针不可再访问一个已经被释放的内存空间。所以拿个临时指针变量保存其指向的空间地址,最后释放这个指针变量指向的空间即可。

  9. 答案给出了一个很不错的解释:

  10. 书中提到过。采用计数器确实比较简单,而空出一个数组元素不使用,则造成了空间浪费,当元素的大小较大时,这个空间浪费就越大。

  11. 这确实是一个比较麻烦的问题,总共会产生四种情况,队列为空、为满、 front 在前、在后。注意最后需要给算得的元素进行取模,当队列为空时,取模运算也会给出正确答案。见 demo01.c

  12. 队列又不需要反向遍历,双向链表在此并不适用,STLdeque 双端队列,就慢的鬼一样…

  13. BST 插入只会在其叶节点位置插入,不会修改原来树的结构,这点注意下就行了。

  14. 和数组、链表相当,O(n)O(n)O(n)。

  15. 简单问题。

  16. 中序:左-根-右。后序:左-右-根。前序:根-左-右。其实能够发现:将前序遍历简单修改一下,变成:根-右-左,那么前序的逆序就是后序遍历。当然,我在此说的是迭代的写法,至于递归没啥好写的。可以见博文,四种遍历详细总结过:[M二叉树] lc145. 二叉树的后序遍历(栈+dfs)

  17. 同上。简单看下参考答案吧:

  18. 中序遍历。四大遍历中没有可以直接得到降序序列的,但是简单修改中序遍历即可,另起变为 右-根-左,即可得到降序序列。

  19. 当然是后序遍历了,其在处理根节点之前,会将子节点处理完毕。

17.10 编程练习

  1. 这个函数必须为新的堆栈分配空间,并将旧堆栈的值复制到新的。然后它必须释放旧数组。断言用于确保新数组很大足够保存栈上当前的所有数据。见 demo02.c

  2. 此模块被转换为 stack 模块。resize 函数更有趣:并不是数组中的每个位置都需要复制,而且当数据绕到数组的末尾时,frontrear 很容易变得不正确。见 demo03.c

  3. 懒得写了,自行写完看看课后答案即可。就是简单的链表尾插和头删的基本操作。

  4. 这是简单的,堆栈数据被简单地声明为数组,作为参数传递的堆栈号选择要操作的元素。见 demo04.h、demo05.c

  5. 简单的 dfs(),统计二叉树的节点数量。

  6. 常见的 bfs() 模板问题,在这是数组形式实现的 BST,也可参考我的博文 [M二叉树] lc102. 二叉树的层序遍历(队列+bfs)

  7. 没啥意思,中序序列是否为严格升序即可。拿递归直接判断也可以,力扣上这题肯定是有的,上去练手就行了,在这还得建树、写测试用例还测不全。

  8. 我的博文:[C++系列] 76. 详解BST二叉搜索树。数组形式实现大同小异。删除的四种情况需要额外注意,找不到该值,找到且为叶子节点,找到有单独的孩子节点,找到有两个孩子节点。还要找左子树中的最大值进行值替换,这个应该是前驱节点,最后删除这个前驱节点即可。

  9. 这最好使用后序遍历。不幸的是,遍历函数的接口设计传递一个指向节点的值,而不是一个指向该节点包含的值,所以我们必须编写自己的。

  10. 同 8。

  11. 书中采用一个宏使堆栈具备可声明多个、解决命名冲突、泛型等问题。但是还是瑕疵,例如同类型的函数命名将会一致等。在此将堆栈功能分解为三个宏,解耦合,很不错的想法。且在日常学习中针对宏写的还是太少了,尤其是利用宏来写函数功能,更是少之又少,见一个得积累一个。见 demo08.c

随笔

  1. 栈的三种实现方式。静态数组、动态数组、链式栈实现。一般在算法题中会选择静态数组的方式来进行模拟实现。动态数组实现涉及到内存分配函数的使用,以及一定要防止的内存泄露问题。链式栈的空间利用率相当高,但是涉及大量的改变指针指向的相关操作,我个人觉得效率上来讲肯定没有静态数组高!

  2. 队列的三种实现方式,和栈相同。但是由于静态数组实现队列的情况下会造成大量的空间浪费,所以采用循环数组的方式来进行优化,我们在此一般称其为循环队列。采用两个指针加一个空余数组元素进行判空、判满。其实采用一个计数变量也是相当香的。循环队列两个指针,其中 rear 指针初始化为 0,是为了在添加第一个元素的时候能和 front 指针指向同一个位置。故每次 push 元素的时候都是先将 rear 指针先向后移动一位再对该位置进行赋值。判空判满的两个式子也是相当巧妙:(rear+1)%SIZE==front 即队列已空,这个可以从初始化中就可以看出来,一开始队列为空的时候 front 是 1,rear 是 0。当 rear == front 的时候,整个队列中就只有一个元素,再出队后 front++ 则在 rear 的前面一个位置,所以上式判空成立。且由于 rearfront 中至少间隔一个空元素,那么当 (read+2)%SIZE == front 的时候说明这个队列已经满了。动态队列书中未实现,链式队列比较简单。

  3. 树,在此书中着重讲解了 BST 树,可参考我的博文,拿 C++ 实现的:[C++系列] 76. 详解BST二叉搜索树,同在该专栏下讲解了 AVL 树和红黑树。链式 BST 蛮不错的,消除了数组空间利用不充分的问题。其中,P377 链式二叉树的插入函数采用了两个指针,其中一个一级指针、一个二级指针,一级指针存储当前遍历到的树中的节点,二级指针指向当前节点的左右孩子指针指向的空间。二叉搜索树下所有的插入都只会在叶子节点中进行插入。

  4. 实现的改进提出了 ADT 的三个问题:用户声明多个堆栈、支持泛型、解决命名冲突问题。在 C++ STL 中,有了模板,这些问题自然迎刃而解。在 C 语言中可以采用宏来解决这个问题。在 ch14 中就已经提到过了:宏是类型无关的。并且实现了一个支持任意类型的 malloc 函数。书中运用宏参数实现类型无关,将堆栈代码写成了一个宏,且添加了用户可以自定义的命名标识,用 ## 的方式加到函数名称的后面。用 C 语言来实现泛型是相当困难的,然而面向对象的语言对泛型是具备良好的支持的。

疑问

  1. 链式实现栈、队列、BST 等其实都比较生疏,以往确实没有写过。静态数组是写的最多的。

  2. 关于利用宏来实现 C 语言下的泛型是值得考虑学习研究的事情!

  3. 数据结构就得多刷题。

[C和指针] ch17. 经典抽象数据类型相关推荐

  1. C的指针疑惑:C和指针17(经典抽象数据类型)

    堆栈这种数据最鲜明的特点是:后进先出. 用动态数组实现堆栈: #include "C17.h" #include <stdio.h> #include <stdl ...

  2. 【 C 】经典抽象数据类型(ADT)之内存分配

    C中的一些抽象数据类型(ADT)如链表.堆栈.队列和树等,链表已经在前几篇博文有所讨论,见: [ C ]在单链表中插入一个新节点的尝试(一) [ C ]在单链表中插入一个新节点的尝试(二) [ C ] ...

  3. 《C和指针》笔记(十四)-- 经典抽象数据类型

    C/C++ 笔记 QQ : 1841545843 邮箱 : jiaxx903@163.com 一. 堆栈 /* ** 堆栈模拟接口 */#define STACK_TYPE int// push vo ...

  4. 【 C 】经典抽象数据类型(ADT)之堆栈(用静态数组实现堆栈)

    堆栈简介 堆栈(stack)最鲜明的特点就是后进先出(Last-In First-Out,LIFO)的数据进出方式. 基本的堆栈操作通常被称为 push 和 pop.push就是将一个新值压入到堆栈的 ...

  5. 数据结构第一次作业——抽象数据类型

    1.作业内容(1分) ADT Rational{ 数据对象:D={e1,e2|e1,e2都是Elemtype类型} 数据关系:R={<e1,e2>} 基本操作:Builtration(&a ...

  6. 面向对象C语言编程--抽象数据类型-AbstractDataTypes

    AbstractDataTypes C语言的灵活 C语言很灵活,不但有基础数据类型,char.int.double等,还允许程序员自定义类型,如: 定义一个链表使用的数据类型,其中有Node节点和自己 ...

  7. 实验报告:抽象数据类型的表现和实现

    实验报告:抽象数据类型的表现和实现 实验内容 基本要求: 设计实现抽象数据类型"三元组",要求动态分配内存.每个三元组由任意三个实数的序列构成,基本操作包括:创建一个三元组,取三元 ...

  8. c语言 数据结构 list、queue、tree抽象数据类型的定义与实现 详尽代码和注释

    本文使用c语言定义并实现list.queue.tree抽象数据类型,代码有详尽注释,可以通过代码熟悉原理并运用数据结构. 0.ADT基础知识 类型包括两类信息,属性和操作.在编程时,根据编程问题匹配合 ...

  9. 链表 队列 基本概念 为什么使用二叉查找树 抽象数据类型

    文章目录 0.抽象数据类型(ADT)的优点? 1.为什么需要链表? 2.链表的概念? 3.队列的概念? 4.为什么需要二叉查找树? 0.抽象数据类型(ADT)的优点? ADT版本可读性高,隐藏编程细节 ...

最新文章

  1. k8s系列----一个简单的例子
  2. python-opencv3 kmeans图像分类
  3. python tkinter怎么读_Tkinter GUI与阅读系列
  4. tensorflow 小于_坐姿不对,屏幕就变模糊!教你用TensorFlow做一款“隐形背背佳”...
  5. 用python分析小说_用Python对哈利波特系列小说进行情感分析
  6. 希尔排序java写法_java高级排序之希尔排序
  7. Tensorflow Data Adapter Error: ValueError: Failed to find data adapter that can handle input
  8. Django 分页查询并返回jsons数据,中文乱码解决方法
  9. 1725.可以形成最大正方形的矩阵数目
  10. PHP高级——抽象类与接口的区别(转)
  11. 编程思想 —— 哨兵的使用
  12. MYSQL获取自增ID的四种方法
  13. HashMap,,ConcurrentHashMap------------------浅谈!!
  14. Windows网络编程之(二)Socket通信非阻塞模式Select(TCP和UDP)
  15. Java实现学生管理系统代码
  16. 《HBase权威指南》读书笔记6:第六章 可用客户端
  17. 网络安全——计算机网络拓扑图
  18. SpringBoot之下载Excel
  19. 读《人性的优点》有感
  20. 小菜鸟的自我激励与不服输的心

热门文章

  1. wifidog认证接口
  2. 黑马程序员——网络编程
  3. linux修改SSH密码的方法
  4. 机器学习基础 LR学习
  5. IAR 配置ICF跟项目走
  6. 消防人员实操训练模拟培训虚拟仿真实训系统软件
  7. php个框架的优缺点,PHP主流框架优缺点分析
  8. 高性能MySQL之 Chapter13
  9. 效应论——破窗效应(zt)
  10. 2131数据结构实验之栈与队列一:进制转换