栈与队列是特殊的线性表,它们属于线性表,与普通线性表的区别是,站和队列规定了插入和删除的位置。
1.栈
1.逻辑结构:
栈的插入和删除位置规定在表尾操作,允许删除和插入的一端叫做栈顶,另一端叫做栈底。元素先入后出。
2.存储结构:
顺序存储
const int maxsize=100;
template<class T>
class SeqStack{
private:
T data[maxsize]; //顺序存储用一维数组来实现;
int top; //栈顶位置,用栈顶插入和删除
public:
SeqStack();
~SeqStack();
void Push(T x) ; //插入操作。data[++top]=x;j即可实现,加入一个元素并且top上移;
T Pop(T x); //删除操作,规定只能删除栈顶元素,只需栈顶top--即可,数据存在于数组中,但不存在在栈中;
T gettop();
bool empty();
};
顺序存储之两栈共享
两个栈的栈顶相对合成一个栈,栈满时,top1+1=top2;
top1=0;栈1空,top2=maxsize;栈2空;
const int maxsize=100;
template<class T>
class BothStack{
private:
T data[maxsize];
int top1,top2; //两个栈须有两个栈顶;
public:
BothStack();
~BothStack();
void Push(int i,T x) ;
T Pop(int i);
T gettop(int i);
bool empty(int i);
};
链式存储
无需头节点,栈顶作为表头;
template<class T>
class LineStack{
private:
Node<T> *top; //Node是一个自定义结构体,包括模板的数据和指针;
public:
LineStack(){top=NULL;}
~LineStack();
void Push(T x) {
Node *s;
s=new Node<T>; //申请一个新节点s
s->data=x; //赋值数据
s->next=top; //头插,因为栈顶是表头;
top=s; //top移动到表头,即把新插入的节点s位置赋给top;
};
T Pop(); //定义一个工作指针p;用p来暂存top的位置,top后移。删除p即可
T gettop();
bool empty();
};
2.队列
队列顾名思义,像是一个排队,在队尾进入队列,在队首出去队列,先入先出。
1.顺序存储
用一个一维数组来实现队列的顺序存储,用一个int类型的front来表示队头,用rear来表示队尾,(注意:front与rear之间的元素属于队列中的,之外的数据虽然存在,但不属于队列内的元素。front表示队列第一个元素之前的元素,rear表示最后一个元素,或者front表示第一个元素,rear表示最后一个元素之后的元素。)
注意假溢出:
为了解决假溢出问题,用数学公式来将队列构成一个环,
rear=(rear+1)%maxsize;
front=(front+1)%maxsize;
空队列和满队列的临界条件相同,都是front = =rear;
为了区别开,有几种方法:
1.多加一个变量num=0;若num=0时,为空,每次进队列,num++;若num=maxsize为满;
2.修改队列满的条件,使front==rear为队列空,而浪费一个元素的空间,队列只有一个空间时为满。
3.设置一个flag,flag=0,为空,flag=1时为满。
const int maxsize=100;
template<class T>
class Cirqueue{
T data[maxsize];
int front,rear;
public:
Cirqueue();
~Cirqueue();
void in(T x);
void pop();
bool empty(){ //判空操作利用了第二种方法,队满时浪费一个空间。
if(front==rear)
return 1;
else
return 0;
};
};
计算队列的长度是:(rear-front+maxsize)%maxsize;
2.链式存储
template<class T>
class Linkqueuie{
Node<T> *front,*rear;//头指针和尾指针;
public:
Linkqueue(){
front=new Node<T>;
front->next=NULL;
rear=front;
}
void in(T x){ //尾插;
s=new Node<T>;
s->data=x;
s->next=NULL;
rear->next=s;
rear=s;
}
void pop(){
Node<T>*p;
if(rear==front)cout<<"下溢";
else{
p=front->next;
font->next=p->next;
delete p;
if(front->next=NULL)rear=front; //空了
}
}
~Linkqueue(){
Node<T>*p;
while(front){
p=front->next;
delete front;
front=p;
}
}
};
总的来看,栈与队列相较于普通线性表更为简单,时间复杂度更小,操作更方便,专门适用于一些实际问题,火车进站等。