目录
1.2 栈的 ADT (Abstract Data Type)
一、数据结构-栈
1.1 栈的定义
栈(Stack)可以看成是一种特殊的线性表。
限定仅只能在表尾端进行插入和删除的线性表。
栈顶:表尾端被称之为栈顶。
栈底:和表尾相对应的另一端,称之为栈底。
时间有序表:LIFO (Last In First Out)后进先出特征的线性结构。
1.2 栈的 ADT (Abstract Data Type)
template <class ElemType>
class AbsStack {
public:
AbsStack ( ) { } // 默认构造函数
virtual ~ AbsStack ( ) { } // 析构函数
virtual int IsEmpty ( ) const = 0; // 判栈空吗?
virtual int IsFull ( ) const = 0; // 判栈满吗?
virtual void MakeEmpty( ) = 0; //将栈清空。
virtual void Push ( const ElemType & X ) = 0; //新结点进栈。
virtual void Pop ( ) = 0; // 栈顶结点出栈。
virtual const ElemType & Top( ) const = 0; // 取栈顶结点数据值。
private:
AbsStack( const AbsStack & ) { } // 冻结复制另一堆栈的构造函数。
};
1.3 栈的顺序存储结构及实现
与线性表类似,栈也有两种存储结构,即顺序存储和链表存储结构。
栈的顺序存储结构亦称顺序栈。
栈的顺序存储结构是利用一批地址连续的存储单元依次存放自栈底到栈顶的数据元素,同时设指针 top 指向栈顶元素的当前位置。
通常用一维数组来实现栈的顺栈存储,习惯上以数组下标小的一端做栈底,当top=0时为空栈。数据元素不断进栈时,栈顶指针top不断地加1,当top达到数组的最大下标值时为栈满。
顺序表示的栈的程序实现:
static const int InitStackSize = 10;
template <class ElemType> class Stack: public AbsStack<ElemType> {
private:
ElemType * Array; // 存放结点的数组名。
int top; // top - 栈顶指针。
int MaxSize; // 栈内能够存放结点的最大个数,即栈的容量。
void DoubleArray( int Max ); // 更新数组的容量。
public:
Stack ( ); // 构造函数, 初始时构造大小为InitStackSize的栈。
~Stack ( ) { delete [ ] Array; }; // 析构函数,释放占用的连续空间。
void MakeEmpty ( ) { top = -1; }; // 将栈清空。
int IsEmpty ( ) const { return top = = -1; }; //栈空为True,否则为False。
int IsFull ( ) const { return top = = MaxSize-1; }; //栈满为True,否则为False。
const ElemType & Top( ) const ; // 读取栈顶结点。
void Push ( const ElemType & X ); // 将X的值进栈。
void Pop ( ); // 栈顶结点出栈。
const Stack & operator = ( const Stack & R );
};
template<class ElemType>
Stack<ElemType> :: Stack( ) : top( -1), MaxSize(InitStackSize) {
//构造函数, 空间大小为MaxSize
Array = new ElemType[MaxSize];
}
template <class ElemType> const ElemType & Stack<ElemType> :: Top( ) const {
// 对非空栈,读取栈顶结点并返回结点的值。
Exception( IsEmpty( ), ”Underflow:Satck is Empty!”);
return Array[top];
}
template <class ElemType> void Stack<ElemType>::Push ( const ElemType & X ) {
if ( top + 1 = = MaxSize ) DoubleArray( 2 * MaxSize );
Array[++top] = X; // 新结点放入新的栈顶位置。
}
template <class ElemType> void Stack<ElemType>::Pop() { //对非空栈,将栈顶结点出栈
Exception( IsEmpty( ), ”Stack is underflow!”);
top--;
}
template <class ElemType>
const Stack<ElemType> & Stack<ElemType> :: operator = ( const Stack<ElemType> & R ) {
if ( this = = &R ) return *this;
delete [ ]Array;
Array = new ElemType[R.MaxSize]; // 分配存储单元。
top = R.top;
for( int j=0; j<= top; j++ ) Array[j] = R.Array[j]; // 逐个复制结点。
return *this;
}
template <class ElemType>
void Stack<ElemType> :: DoubleArray( int Max ) {
ElemType * oldarr = Array;
Exception( MaxSize≥Max, “New size is too small!”);
Array = new ElemType[Max];
for( int k = 0; k <= top; k++ ) Array[k] = oldarr[k]; // 逐个复制结点。
MaxSize = Max;
delete [ ] oldarr;
return;
}
多栈共享一块顺序存储空间:栈顶指针指向实际栈顶的下一个单元。
二个栈共享一块顺序存储空间:栈顶指针指向实际栈顶的下一个单元。指针相遇时,栈满。
top 是栈顶指针。栈顶和栈底如图所示。
栈的 Push 操作:
栈的 Pop 操作:
二、数据结构-队列
2.1 队列的定义
队列(Queue)也是一种特殊的线性表。在现实中例子很多,如客户到银行办理业务往往需要排队,先来的先办理,晚来的则排在队尾等待。
在表的一端进行插入,而在另一端进行删除的线性表。
队尾:进行插入的一端。
队首:进行删除的一端。
时间有序表:FIFO (先进先出)特征的线性结构。
2.2 队列的 ADT
template <class ElemType> class AbsQueue {
public:
AbsQueue ( ) { } // 默认构造函数
virtual ~ AbsQueue ( ) { } // 析构函数
virtual int IsEmpty ( ) const = 0; // 判队空吗?
virtual int IsFull ( ) const = 0; // 判队满吗?
virtual void MakeEmpty( ) = 0; //将队清空。
virtual void EnQueue( const ElemType & X ) = 0; //新结点进队。
virtual void DeQueue( ) = 0; // 队首结点出队。
virtual const ElemType & Front( ) const = 0; // 取队首结点数据值。
private:
AbsQueue ( const AbsQueue & ) { } // 冻结复制另一队列的构造函数。
};
2.3 队列的顺序存储结构与实现
队列的表示
出队时应先判队是否空:条件 rear == front
不空则出队,注意 front 是否会由最高下标跳至最低下标(循环)。
进队时应先判队是否满:条件 ( ( rear + 1) % maxSize ) == front
不满则进队,注意 rear 是否会由最高下标跳至最低下标(循环)。
基本操作的实现程序:进队。
template <class ElemType>
void Queue<ElemType>::EnQueue(const ElemType & x) {
// 值为x的结点进队。
if ( IsFull( ) ) DoubleQueue( ); Array[rear] = x; // 若队满,则数组容量扩大一倍。
Increment( rear); // rear 加 1;若为 MaxSize,则rear取0。
}
int IsFull( ) const {return ( rear + 1) % MaxSize = = front ; }
基本操作进队的实现程序:扩大数组容量
template <class ElemType>
void Queue<ElemType>::EnQueue(const ElemType & x) {
// 值为x的结点进队。
if ( IsFull( ) ) DoubleQueue( ); Array[rear] = x;
Increment( rear);
}
template <class ElemType>
int IsFull( ) const {return ( rear + 1) % MaxSize = = front ; }
template <class ElemType>
void Queue<ElemType>::DoubleQueue( ) {
//重新创建数组单元个数多一倍的新数组,复制原队列中的结点。
int NewSize = 2 * MaxSize; ElemType * old = Array;
Array = new ElemType[NewSize];
for ( int j = 0, k = front; k < rear; j++, Increment(k) ) Array[j] = old[k];
front = 0; // 新的队首指针。
rear = j; // 新的队尾指针。
MaxSize = NewSize; delete [ ]old;
}
基本操作出队的实现程序:
template <class ElemType> void Queue<ElemType>::DeQueue( ) {
//对于非空队列,将队首结点出队。
Exception( IsEmpty( ), ”Queue is underflow!”);
Increment( front );
}
int IsEmpty() const {return front = = rear;}
//判断队列是否空.。为空返回True,否则返回False。
求队中结点的个数:( rear - front + MaxSize ) % MaxSize
front 和 rear 分别是队首和队尾指针。它们指示着真正的队首和真正的队尾结点。
template <class ElemType> class Queue : public AbsQueue<ElemType> {
private:
ListNode<ElemType> * front; // 队首指针。
ListNode<ElemType> * rear; // 队尾指针。
public:
Queue ( ) : front(NULL), rear(NULL) { }
// 构造函数: 队首指针和队尾指针初始化。
~Queue ( ) { MakeEmpty( ); } //析构函数,释放占用的连续空间。
void MakeEmpty ( ); // 将队列清空。
int IsEmpty ( ) const { return front = = NULL; }
// 队空为True,否则为False。
int IsFull ( ) const { return 0; } // 总认为为False。
const ElemType & Front ( ) const ; // 读取队首结点数据值。
void EnQueue ( const ElemType & X ); // 将X的值进队。
void DeQueue ( ); // 将队首结点出队。
const Queue & operator = ( const Queue & R );
};
进队操作:
template <class ElemType>
void Queue<ElemType>::EnQueue ( const ElemType & X ) {
if ( IsEmpty( ) ) front = rear= new ListNode <ElemType> ( X );
else rear = rear->Next = new ListNode<ElemType> ( X );
}
2.4 优先队列
优先权有序表:具有特征高优先权的结点将先离开的线性结构。和到达时刻无关。
实现方法:结点中处包含数据场外,还有本结点的优先权数。优先权数越小(如本书) ,优先级越高。或者优先权数越大,优先级越高。
顺序存储的优先队列:用数组