本章讨论用指针的简单数据结构来表示动态集合

  • 运用指针可构造复杂的数据结构,
    • 这里只介绍几种:
      • 栈、队列、链表和有根树
  • 还介绍由数组构造对象和指针的方法

10.1 栈和队列

栈和队列是动态集合,其上进行DELETE操作移除的元素是预先设定的

  • 在stack中,被删除的是最近插入的元素
    • 实现一种后进先出last-in, first-out
  • 在queue,被删去的总是在集合中存在时间最长的那个元素:
    • 队列实现的是一种先进先出FIFO
  • 在计算机上实现栈和队列有几种有效方式
  • 本节介绍用简单数组
    • 实现这两种结构

  • 栈上的INSERT称PUSH,而无元素参数的DELETE称POP
  • 名称使人联想到现实中的栈
    • 餐馆里装有弹簧的摞盘子的栈
    • 盘子从栈中弹出的次序同它们压入的次序相反
    • 因为只有最上的盘子才能取下

如图10-1,用数组S[1…n]来实现最多有n个元素的栈。

ten 基本数据结构

  • 数组有属性S.top,指向最新插入的元素。
  • 栈中包含的元素为S[1…S.top],
    • S[1]是栈底,而S[S.top]是栈顶

S.top=0时,栈无元素,栈是(empty)的。

  • 测试栈是否空可用STACK-EMPTY
  • 若对空栈弹出,栈下溢( underflow),通常是错误
  • 若S.top>n,栈上溢( overflow)
  • (下面的伪代实现中,不考虑栈的上溢)

栈的几种操作的几行代码

ten 基本数据结构

ten 基本数据结构

队列

  • 队列上的INSERT称ENQUEUE,DELETE称出队DEQUEUE
  • 如栈的POP, DEQUEUE操作也无参。
  • 队列的先进先出特性
  • 类似于收银台前排队顾客。
  • 队列有队头head和队尾tail,
  • 当有一个元素入队时,它被放在队尾的位置,就像一个新到来的顾客排在队伍末端一样。
  • 而出队的元素则是队头的那个,就像排在队伍前面等待最久的那个顾客一样。

图10-2用数组Q[1…n]实现最多n-1个元素的队列

ten 基本数据结构

  • 队列有属性Q.head指队头
  • Q.tail指下一个新元素要插的位置
  • 队列中的元素存放在Q.head, Q.head+1,…, Q.tail-1
    • 并在最后的位置“环绕”
    • 感觉好像1紧邻在n后
    • 形成环序
  • Q.head=Q.tail时,队列空
  • 初始时Q.head=Q.tail=1
    • 从空队列中删,则下溢
  • 当Q.head=Q.tail+1时,队列满
    • 此时若插,则上溢

ENQUEUE和DEQUEUE中,我们省略对下溢和上溢的检査。

  • (练习10.1-4要求读者给出检查两种错误情况的代码。)
  • 下列伪代码中,假设n=Q.length。

ten 基本数据结构

  • 图10-2为ENQUEUE和DEQUEUE操作
    • 俩操作的时间都O(1)

10.2 链表

linked list是这样的数据结构

  • 各对象按线性顺序排
  • 数组的线性顺序由数组下标决定
    • 链表的顺序由各个对象里的指针决定
  • 链表为动态集合提供 简单、灵活的表示方法
    • 且支持10.1节中列出的所有操作,未必有效

如图10-3,

ten 基本数据结构

  • 双向链表(doubly linked list)L的元素

    • 都是个对象,
    • 对象有key和俩指针next和preu。
    • 对象中还可包含其他的辅助数据(称卫星数据)。
  • x为链表元素,

    • x.next指向它在链表中的后继
    • x.prev指向它的前驱
    • 若x.prev=NIL,则x无前驱,
      • 即x头
    • 若x.next=NIL,x无后继,
      • 即x尾
  • L.head指向链表的第一个元素,即头

    • 若L.head=NIL,则链表空

链表有多种形式

  • 单链接、双链接
  • 已排序、未排序
  • 循环、非循环
  • 若singly linked,则省略元素中的prev指针
  • 若sorted的,则链表的线性顺序与链表元素中关键字的线性顺序一致;
    • 最小是头,最大是尾
  • 若unsorted的,则各元素可以以任何顺序
  • circular list中,
    • 表头的prev指针指向表尾,
    • 而表尾的next指向表头
    • 可将循环链表想成一个各元素组成的圆环
  • 本节余下部分,假设链表未排序的且双链接

10.3 指针和对象的实现

10.4 有根树的表示

  • 上节介绍的表示链表的方法可推广到任意同构的数据结构上
  • 本节讨论用链式数据结构
    • 表示有根树
  • 先论二叉树
    • 然后给出针对结点的孩子数任意的有根树的表示法

树的结点用对象表示

  • 与链表类似,设结点都有关键字key
  • 其余感兴趣的属性
    • 指向其他结点的指针,它们随树种类不同有所变化

二叉树

图10-9展示了在二又树T中用属性p、left和right存放指向父、左和右子的指针

ten 基本数据结构

  • 若x.p=NIL,则x是根
  • 若x无左,则x.left=NIL
  • T.root指向整棵树T的根
  • 若T.root=NIL,则树为空。

分支无限制的有根树

  • 二叉树的表示方法可推广到
    • 结点的孩子数至多为k的任意类型的树
    • 只需将left和right用child1, child2,…, childk代替。
  • 当孩子的结点数无限制时,这种方法就失效了
    • 因为不知道预先分配多少个属性
    • (在多数组表示法中就是多少个数组)
  • 即使孩子数k限制在一个大的常数以内
    • 但若多数结点只有少量孩子
    • 则浪费大量空间

孩子数任意的树

  • 对任意n结点的有根树,只要O(n)存储空间
  • (left-child,right-sibling representation)如图10-10

ten 基本数据结构

  • 结点都包含父结点指针p,且T.root指向树T的根
  • 结点只有俩针
    • x.leftchild指x最左孩
    • x.rightsibling指x右邻兄
  • 若x无孩子,则x.leftchild=NIL;
  • 若x是其父的最右孩,则x.rightsibling=NIL。

树的其他表示方法

  • 第6章,对完全二叉树用堆表示
    • 堆用一个数组加上
    • 堆的最末结点的下标表示
  • 21章中的树只需向根结点方向遍历
    • 因此只需提供父指针
    • 而无孩指针
  • 还有其他的表示方法
    • 哪种方法最优取决于具体应用

相关文章:

  • 2021-11-19
  • 2021-09-15
  • 2021-05-29
  • 2021-05-22
  • 2022-02-11
  • 2021-11-14
  • 2022-12-23
猜你喜欢
  • 2021-11-02
  • 2021-05-22
  • 2021-11-12
  • 2022-01-18
相关资源
相似解决方案