线性表栈队列

243 阅读4分钟

形如A0,A1,...An的称为表list。她只有一个开始节点和终止节点,其他的为中间节点。并且节点之间的前驱和后继关系具有反对称性和传递性。 我们讨论数据结构关注逻辑结构,存储结构和运算。 逻辑结构: 长度 表头 表尾 当前节点 存储结构: 顺序存储(数组),顺序表 链式存储(单链表,双向链表,循环链表),链表 操作: 线性表(不限制操作) 栈stack(先进后出) 队列queue(后进先出) 在c++ STL中,有采用数组实现的vector和采用双向链表实现的list。

先看下顺序表的数据结构:

class arrList : public List<T> { // 顺序表,向量
private: // 线性表的取值类型和取值空间
 T * aList ; // 私有变量,存储顺序表的实例
 int maxSize; // 私有变量,顺序表实例的最大长度
 int curLen; // 私有变量,顺序表实例的当前长度
 int position; // 私有变量,当前处理位置
public:
 arrList(const int size) { // 创建新表,设置表实例的最大长度
 maxSize = size; aList = new T[maxSize];
 curLen = position = 0;
 }
 ~arrList() { // 析构函数,用于消除该表实例
 delete [] aList;
 }
 void clear() { // 将顺序表存储的内容清除,成为空表
 delete [] aList; curLen = position = 0;
 aList = new T[maxSize];
 }
 int length(); // 返回当前实际长度
 bool append(const T value); // 在表尾添加元素 v
 bool insert(const int p, const T value); // 插入元素
 bool delete(const int p); // 删除位置 p 上元素
 bool setValue(const int p, const T value); // 设元素值
 bool getValue(const int p, T& value); // 返回元素
 bool getPos(int &p, const T value); // 查找元素
};

链表的数据结构:

template <class T> class lnkList : public List<T> {
private:
Link<T> * head,
*tail; // 单链表的头、尾指针
Link<T> *setPos(const int p); // 第p个元素指针
 public:
lnkList(int s); // 构造函数
~lnkList(); // 析构函数
bool isEmpty(); // 判断链表是否为空
void clear(); // 将链表存储的内容清除,成为空表
int length(); // 返回此顺序表的当前实际长度
bool append(cosnt T value); // 表尾添加一个元素 value,表长度增 1
bool insert(cosnt int p, cosnt T value); // 位置 p 上插入一个元素
bool delete(cosnt int p); // 删除位置 p 上的元素,表的长度减 1
bool getValue(cosnt int p, T& value); // 返回位置 p 的元素值
bool getPos(int &p, const T value); // 查找值为 value 的元素
}

插入于删除的代码实现,留给读者去思考。

线性表的主要实现方式比较

  • 顺序表的主要优点

    • 没有使用指针,不用花费额外开销
    • 线性表元素的读访问非常简洁便利
  • 链表的主要优点

    • 无需事先了解线性表的长度
    • 允许线性表的长度动态变化
    • 能够适应经常插入删除内部元素的情况
  • 总结

    • 顺序表是存储静态数据的不二选择
    • 链表是存储动态变化数据的良方

顺序表和链表比较

  • 顺序表
    • 插入、删除运算时间代价 O(n),查找则可常数时间完成
    • 预先申请固定长度的连续空间
    • 如果整个数组元素很满,则没有结构性存储开销
  • 链表
    • 插入、删除运算时间代价 O(1),但找第i个元素运算时间代价 O(n)
    • 存储利用指针,动态地按照需要为表中新的元素分配存储空间
    • 每个元素都有结构性存储开销

顺序表和链表存储密度

n 表示线性表中当前元素的数目, P 表示指针的存储单元大小(通常为 4 bytes) E 表示数据元素的存储单元大小 D 表示可以在数组中存储的线性表元素的最大数目

  • 空间需求
    • 顺序表的空间需求为 DE
    • 链表的空间需求为 n(P + E)
  • n 的临界值,即 n > DE / (P+E)
    • n 越大,顺序表的空间效率就更高
    • 如果P = E,则临界值为 n = D / 2

应用场合的选择

  • 顺序表不适用的场合
    • 经常插入删除时,不宜使用顺序表
    • 线性表的最大长度也是一个重要因素
  • 链表不适用的场合
    • 当读操作比插入删除操作频率大时,不应选择链表
    • 当指针的存储开销,和整个结点内容所占空间相比其比例较大时,应该慎重选择

顺序表和链表的选择

  • 顺序表
    • 结点总数目大概可以估计
    • 线性表中结点比较稳定(插入删除少)
    • n > DE / (P + E)
  • 链表
    • 结点数目无法预知
    • 线性表中结点动态变化(插入删除多)
    • n < DE / (P + E)

可以思考下一元多项式的实现,对于系数稠密情况采用顺序表比较好,而对于稀疏琴况明显采用链表好