目录
栈
栈的基本操作:
·InitStack(&S)
·StackEmpty(S)
·Push(&S,x)
·Pop(&S,&x)
·GetTop(S,&x)
·DestroyStack(&S)
顺序栈
顺序栈的定义
1 #define MaxSize 10//定义栈中元素的最大个数
2 typedefstruct{
3 ElemType data[MaxSize];//静态数组存放栈中元素
4 inttop;//栈顶指针
5 }SqStack;
初始化
1 voidInitStack(SqStack &S){
2 S.top=-1;
3 }
1 voidInitStack(SqStack &S){
2 S.top=0;
3 }
判断栈空
1 boolStackEmpty(SqStack S){
2 if(S.top==-1)//栈空
3 return true;
4 else
5 return false;
6 }
1 boolStackEmpty(SqStack S){
2 if(S.top==0)//栈空
3 return true;
4 else
5 return false;
6 }
进栈
1 boolPush(SqStack &S,ElemType x){
2 if(S.top==MaxSize-1)//栈满报错
3 return false;
4 S.data[++S.top]=x;
5 return true;
6 }
1 boolPush(SqStack &S,ElemType x){
2 if(S.top==MaxSize)//栈满报错
3 return false;
4 S.data[S.top++]=x;
5 return true;
6 }
出栈
1 boolPop(SqStack &S,ElemType &x){
2 if(S.top==-1)//栈空报错
3 return false;
4 x=S.data[S.top--];//栈顶元素先出栈
5 return true;
6 }
1 boolPop(SqStack &S,ElemType &x){
2 if(S.top==0)//栈空报错
3 return false;
4 x=S.data[S.--top];//栈顶元素先出栈
5 return true;
6 }
读栈顶元素
1 boolGetTop(SqStack S,ElemType &x){
2 if(S.top==-1)
3 return false;
4 x=S.data[S.top];
5 return true;
6
7 }
共享栈
好处:节省存储空间,降低发生上溢的可能
1 #define MaxSize 10
2 typedefstruct{
3 ElemType data[MaxSize];
4 inttop0;
5 inttop1;
6 }ShStack;
1 voidInitStack(ShStack &S){
2 S.top0=-1;
3 S.top1=MaxSize;
4 }
栈满条件:top0+1=top1
0号栈进栈时,top0先+再赋值 出栈相反
1号栈进栈时,top1先-再赋值 出栈相反
链栈
1 typedefstructLinknode{
2 ElemType data;//数据域
3 structLinknode *next;//指针域
4 }*LinkStack,StackNode;
1 //初始化栈
2 voidInitStack(LinkStack &s)
3 {
4 s =NULL;
5 }
1 //判定空
2 boolStackEmpty(LinkStack S)
3 {
4 if(S==NULL)
5 return true;
6 else
7 return false;
8 }
1 //入栈
2 boolPush(LinkStack &S,SElemType e){
3 p =newStackNode;//生成结点
4 p->data=e;//将新结点数据域置为e
5 p->next=S;//将新结点插入栈顶
6 S=p;//修改栈顶指针
7 return true;
8
9
1 //出栈
2 boolPop(LinkStack &S,SElemType &e){
3 if(S==NULL)
4 return false;
5 e=S->data;
6 p=S;
7 S=S->next;
8 deletep;
9 return true;
10 }
1 //取栈顶元素
2 SElemType GetTop(LinkStack S){
3 if(S!=NULL)
4 returnS->data;
5 }
队列
队列的顺序实现
顺序存储类型描述
1 #define MaxSize 50//定义队列中元素的最大个数
2 typedefstruct{
3 ElemType data[MaxSize];//用数组存放队列元素
4 intfront,rear;
5 }SqQueue;
初始化
1 voidInitQueue(SqQueue &Q){
2 Q.rear=Q.front=0;
3 }
判断是否为空
1 boolQueueEmpty(SqQueue Q){
2 if(Q.rear==Q.front)
3 return true;
4 else
5 return false;
6 }
队列长度:(Q.rear+MaxSize-Q.front)%MaxSize;
判断队列已满/已空? 若入队速度大于出队速度,队尾指针赶上队首指针,队满时也会有Q.rear==Q.front
方案一:
牺牲一个单元来区分队空和队满,入队时少用一个队列单元,“队头指针在队尾指针的一下位置作为队满的标志”
队满条件:(Q.rear+1)%MaxSize==Q.front;
队空条件:Q.front==Q.rear;
队列中元素的个数:(Q.rear-Q.front+MaxSize)%MaxSize;
方案二:
增设size数据成员,表示元素个数,删除成功size-1,插入成功size+1。
队空:Q.size==0;
队满:Q.size==MaxSize;
两种情况都有Q.rear==Q.front;
1 #define MaxSize 10
2 typedefstruct{
3 ElemType data[MaxSize];
4 intfront,rear;
5 intsize;//队列当前长度
6 }SqQueue;
初始化时
rear=front=0;
size=0;
方案三:
增设tag数据成员,区分是队满还是队空。删除成功置tag=0,若导致Q.front==Q.rear,则为队空;插入成功置tag=1,若导致Q.front==Q.rear,则队满;
队满:Q.front==Q.rear && tag==1
队空:Q.front==Q.rear && tag==0
队列的链式实现
typedefstructLinkNode{//链式队列结点
2 ElemType data;
3 structLinkNode *next;
4 }LinkNode;
5
6 typedefstruct{//链式队列
7 LinkNode *front,*rear;//队列的队头和队尾指针
8 }LinkQueue;
不带头结点时,当Q.front==NULL && Q.front==NULL 为空
用单链表表示的链式队列适合于数据元素变动比较大的情形,而且不存在队列满且产生溢出的问题。
初始化(带头结点)
1 voidInitQueue(LinkQueue &Q){
2 //初始化时 front和rear都指向头结点
3 Q.front=Q.rear=(LinkNode*)malloc(sizeof(LinkNode));
4 Q.front->next=NULL;
5 }
初始化(不带头结点)
1 voidInitQueue(LinkQueue &Q){
2 Q.front=NULL;
3 Q.rear=NULL;
4 }
判断为空(带)
1 boolIsEmpty(LinkQueue Q){
2 if(Q.front==Q.rear)
3 return true;
4 else
5 return false;
6 }
判断为空(不带)
1 boolIsEmpty(LinkQueue Q){
2 If(Q.front==NULL)
3 return true;
4 else
5 return false;
8 }
入队(带)
1 voidEnQueue(LinkQueue &Q,ElemType x){
2 LinkNode *s=(LinkNode*)malloc(sizeof(LinkNode));
3 s->data=x;
4 s->next=NULL;
5 Q.rear->next=s;//新结点插入到rear之后
6 Q.rear=s;//修改表尾指针
7 }
入队(不带头结点)
1 voidEnQueue(LinkQueue &Q,ElemType x){
2 LinkNode *s=(LinkNode*)malloc(sizeof(LinkNode));
3 s->data=x;
4 s->next=NULL;
5 if(Q.front==NULL){//在空队列中插入第一个元素
6 Q.front=s;
7 Q.rear=s;//不带头结点的队列,第一个元素入队特殊处理
8 }
9 else{
10 Q.rear->next=s;
11 Q.rear=s;
12
13 }
出队(带头结点)
1 boolDeQueue(LinkQueue &Q,ElemType &x){
2 if(Q.front==Q.rear)
3 return false;
4 LinkNode *p=Q.front->next;
5 x=p->data;
6 Q.front->next=p->next;//修改头结点的next指针
7 if(Q.rear==p)//修改rear指针
8 Q.rear=Q.front;
9 free(p);
10 return true;
11 }
出队(不带头结点)
1 //队头元素出队(不带)
2 boolDeQueue(LinkQueue &Q,ElemType &x){
3 if(Q.front==NULL)
4 return false;//空队
5 LinkNode *p=Q.front;//p指向此次出队的结点
6 x=p->data;//用变量x返回队头元素
7 Q.front=p->next;//修改front指针
8 if(Q.rear==p){//此次是最后一个结点出队
9 Q.front=NULL;
10 Q.rear=NULL;
11 }
12 free(p);
13 return true;
14
链式存储-一般不会队满,除非内存不足
双端队列
允许两端都可以进行插入和删除的线性表。
输入受限的双端队列:只允许一端插入、两端删除的线性表
输出受限的双端队列:只允许两端插入、一端删除的线性表
判断输出序列是否合法:
栈中合法的序列,双端队列中一定合法
栈和队列的应用
栈在括号匹配中的应用:
遇到左括号就入栈
遇到右括号就“消耗”一个左括号
1 boolbracketCheck(charstr[],intlength){
2 SqStack S;
3 InitStack(S);
4 for(inti=0;i<length;i++){
5 if(str[i]=='('||str[i]=='['||str[i]=='{'){
6 Push(S,str[i]);//扫描到左括号,入栈
7 }
8 else{
9 if(StackEmpty(S))//扫描到右括号,且当前栈空
10 return false;
11 chartopElem;
12 Pop(S,topElem);//栈顶元素出栈
13 if(str[i]==')'&&topElem!='(')
14 return false;
15 if(str[i]==']'&&topElem!='[')
16 return false;
17 if(str[i]=='}'&&topElem!='{')
18 return false;
19 }
20 }
21 returnStackEmpty(S);//检查最后栈是否为空
22
匹配失败情况:
①左括号单身 ②右括号单身 ③左右括号不匹配
表达式求值
逆波兰表达式=后缀表达式
波兰表达式=前缀表达式
栈在递归中的应用
适合用“递归”算法解决:可以把原始问题转换为属性相同,但规模较小的问题
数组与特殊矩阵
一维数组的存储结构
起始地址:LOC
a[i]的存放地址=LOC+i*sizeof(ElemType)
数组下标默认从0开始
二维数组的存储结构
分为行有限存储或者列优先存储
对称矩阵的压缩存储
压缩存储策略:只存储主对角线+下三角区(上三角区)
行优先存入一维数组:数组大小(1+n)*n/2
对阵矩阵压缩存储后:可以实现一个“映射”函数 矩阵下标->一维数组下标
三角矩阵的压缩存储
压缩策略:按行优先原则将主对角线和下三角区(/上三角区)存入一维数组,并在最后一个位置存储常量c
三对角矩阵
稀疏矩阵
压缩存储策略:
三元组表
链式存储-十字链表法 向右域right:指向第i行的第一个元素 向下域down:指向第j列的第一个元素