栈和队列
文章目录
一、栈和队列的定义和特点
二、栈的表示和操作的实现
三、栈与递归
四、队列的表示和操作的实现
一、栈和队列的定义和特点
1.1
栈和队列是限定插入和删除只能在表的“端点”进行的线性表。
栈—后进先出–LIFO
队列–先进先出–FIFO
1.11栈
栈:是一个特殊的线性表,是限定仅在一端(表尾)进行插入删除的线性表。
栈的应运:
1、数制转化 2、表达式求值
3、括号匹配的检验 4、八皇后问题
5、 行编辑程序 6、 函数调用
7、迷宫 8、递归调运的实现
表尾—栈顶–top
表头—栈底—base
入栈—插入元素到栈顶的操作----PUSH
出栈—从栈顶删除最后一个元素------POP
1,12
逻辑结构:同线性结构相同,仍为一对一关系
1.13
存储结构:用顺序栈或链栈存储均可;
1.14
运算规则:只能在栈顶运算,LIFO
(一般线性表—运算规则—随机存取)
1.2 对列
1.21
定义:只能在表的一端插入运,在另一端进行删除操作的线性表。
1.22
逻辑结构:同线性结构相同,仍为一对一关系
1.23
存储结构
顺序对或链队
1.24
只能在队首和队尾运算,先进先出(FIFO)
队列应运
1、脱机打印输出
2、所用户系统中。多个用户排成对。每个优先级一个队列
3、网络电文传输,按时间先后顺
4.舞伴问题
二、栈的表示和操作的实现
2.1 顺序栈的表示和实现
空栈:base == top是栈空的标志
栈满:top-base==stacksize(栈可以使用的最大容量)
上溢(overflow):栈已满就,又要压入新元素;
下溢(undetflow):栈已经空,还要弹出新元素;
顺序栈的表示
#define maxsize 100
typedef struct{
selemtype *base;//栈底指针
selemtype *top;//栈顶指针
int stacksize;//栈的可用最大容量
}sqstack;
顺序栈的初始化
status initstack(sqstack &s)//构建一个空栈
{
s.base=new selemtype[maxsize];
//s.base=(selemtype*)malloc(maxsize*sizeof(selemtype));
if(!s.base)exit(overflow);//存储分配失败
s.top=s.base;
s.stacksize=maxsize;
return ok;
}
顺序栈判断栈是否为空
status stackempty(sqstack s)
{//若栈为空,返回1;否则返回0;
if(s.top==s.base)
return 1;
else
return 0;
}
求顺序栈的长度
int stacklength(sqstack s)
{
return s.top-s.base;
}
清空顺序栈
status clearstack(sqstack s)
{
if(s.base)s.top=s.base;
return 1;
}
销毁顺序栈
status destroystack(sqstack &s)
{
if(s.base)
{
delete s.base;
s.stacksize=0;
s.base=s.top=NULL;
}
return ok;
}
顺序栈的入栈
//判断是否栈满
//元素e压入栈
//栈指针加1
status push(sqstack &s,selemtype e)
{
if(s.top-s.base==s.stacksize)//栈满
return 0;
*s.top++=e;//*s.top=e;s.top++;
return 1;
}
顺序栈的出栈
status pop(sqstack &s,selemtype &e)
{
if(s.top==s.base)//等价于 if(stackempty(s));
return 0;
e=*--s.top;//--s.top;e=*s.top;
return ok;
}
/
2.2链栈的表示和实现
链栈是运算受限的单链表,只能在链表头部进行操作
typedef struct stacknode{
selemtype data;
struct stacknode *next;
}stacknode,*linkstack;
linkstack s;
链栈的初始化
void initstack(linkstack &s)
{
//构建一个空栈,栈顶指针置为空;
s=NULL;
return ok;
}
判断链栈是否为空
status stackempty(linkstack s)
{
if(s==NULL)return 1;
else return 0;
}
链栈的入栈
status push(linkstack &s,selemtype e)
{
p=new stacknode;
p->data=e;//将新节点数据域置为e;
p->next=s;//将新节点插入栈顶
s=p;、、修改栈顶指针;
return ok;
}
链栈的出栈
status pop (linkstack &s,selemtype &e)
{
if(s==NULL)return 0;
e=s->data;
p=s;
s=s->next;
delete p;
return ok;
}
取栈顶元素
selemtype gettop(linkstack s)
{
if(s!=NULL)
return s->data;
}
三、栈与递归
递归
优点:结构清晰,程序易读;
缺点:每次调试要生成工作记录,保存状态信息。入栈;返回时要出栈,恢复状态信息。时间开销大。
递归->非递归
方法一:尾递归,单向递归->循环结构;
方法二:自用栈模拟系统的运行时栈
尾递归->循环结构
long fact(long n)
{
if(n==0)return 1;
else return n*fact(n-1);
}
等价于
long fact (long n)
{
t=1;
for(i=1;i<=n;i++)
t=t*i;
return t;
}
单项递归->循环结构
long fib(long n)
{
if(n==1||n==2)return 1;
else return fib(n-1)+fib(n-2);
}
等价于
long fib (long n)
{
t1=1;t2=1;
for(int i=3;i<=n;i++)
{
t3=t1+t2;
t1=t2;t2=t3;
}
return t3;
}
四、队列的表示和操作的实现
1.定义:只能在表的一端插入运,在另一端进行删除操作的线性表。
2.逻辑结构:同线性结构相同,仍为一对一关系
3.存储结构
顺序对或链队
4、实现方式:入队和出队操作。
入队:插入元素
出队:删除元素
4.1队列的顺序表示–用一维数组base[maxqsize]
入队
base[raer]=x;
rear++;
出队
x=base[front];front++;
这样做容易出现假溢出。怎么解决?这就需要引入循环队列;
循环队列
#define maxqsize 100;//最大化队列长度
typedef struct{
qelemtype *base;//初始化的动态分配内存
int front;
int rear;
}sque;
循环队列–队列初始化
status initque(sque &q)
{
q.base=new qelemtype[maxqsize]//分配数组空间c++
//q.base=(qelemtype*)malloc(maxqsize*sizeof(qelemtype));
if(!q.base)exit(overflow);
q.front=q.rear=0;
return ok;
}
队列长度
int quelength(aque q)
{
return (q.rear=q.front +maxqsize)%maxqsize};
入队
status enque(sqque &q,qelemtype e)
{
if((q.rear+1)%maxqsize==q.front )
return error;
q.base[ q.rear]=e;
q.rear=(q.rear+1)%maxqsize;
return ok;
}
出队
status deque(sqque &q,qelemtype &e)
{
if(q.front==q.rear)return error;//对空
e=q.base[q.front];//保存对头元素
q.front=(q.front+1)%maxqsize;//对头指针+1
return ok;
}
取队头元素
status gethead(sqque q)
{
if(q.front!=q.rear)//队列不为空
return q.base[q.front];//返回队头指针元素的值吗,队头指针不变;
}
链队
若无法估计所用队列的长度,则宜采用链队
链队列定义
#define maxqsize 100
typedef struct qnode{
qelemtype data;
struct qnode *next;
}qnode,*queneptr;
typedef strulct {
queneptr front;
queneptr rear;
}linkque;
链队列初始化
status initque(linkqule &q )
{
q.front=q.rear=new qnode;//c++
//q.front=q.rear=(queneptr)malloc(sizeof(qnode));c
if(!q.front)exilt(overflow);
q.front->next=NULL;
return ok;
}
销毁队列
status destroyque(linkque &q)
{
while(q.front)
{
p=q.front->next;free(q.front);
q.front=p;
}
return ok;
}
将元素e入队
status enque(linkque &q,qelemtype e)
{
p=new qnode;
if(!p)exit(overflow);
p->data=e;p->next=NULL:
q.rear->next=p;
q.rear=p;
return ok;
}
链队出队
status deque(linkque &q,qelemtype &e)
{
if(q.front==q.rear)return ERROR;
p=q.front->next;
e=p->data;
q.front->next=p->next;
if(q.rear==p)
q.rear=q.front;
delete p;
return ok;
}e
求链队的队头的元素
status gethead(linkque q,qelemtype &e)
{
if(q.front==q.rear)return error;
e=q.front->next->data;
return ok;
}
代码的话在下一篇文章中;