数据结构学习笔记(二)栈和队列
栈和队列
数据结构的线性结构是一种很基础也很重要的结构,通常说的栈和队列只是线性结构中的两种特殊类型,最大的特征在于插入和删除室友规则的,且只能在一端进行。
栈(先进后出)
Insert(S,n+1,e)只能从尾端插入
Delete(S,n)只能从尾端删除
队列(先进先出)
Insert(Q,n+1,x)只能从尾端插入
Delete(Q,1)只能从头部删除
除此之外,同样的两者都可以分别用数组和链表来表示,以下的实现方式也分别用数组和链表完成。
栈
顺序栈
顺序栈的结构定义为
typedef struct Stack { ElementType *base;//栈底指针 ElementType *top;//栈顶指针 //指针也可以用int型,表示元素的下标 int StackSize;//数组最大容量 }Stack;
由于栈先进后出的特性,所以常常会画成这样

由此可见,顺序栈的状态可以表示为
栈满:top-base=stacksize
栈空:top=base
相关操作如下
1、初始化操作
Status InitStack(Stack &S){ S.base = new ElementType[MaxSize];//初始大小 // S.base = (ElementType*)malloc(MaxSize*sizeof(ElementType)); if(!S.base)exit ERROR;//分配失败 S.top = S.base; S.StackSize = MaxSize; return OK; }
2、判断是否为空,求长度,对应两种特殊状态
//判断栈是否为空 Status StackEmpty(Stack S){ if(S.top == S.bsae) return TRUE; else FALSE; } //求长度 int StackLength(Stack S){ reutrn S.top-S.base; }
3、销毁与清空
销毁是完全释放出空间;清空置为空表
//销毁 Status DestroyStack(Stack S{ if(S.base){ delete S.base; S.StackSize = 0; S.top = S.base = NULL; } return OK; } //清空 Status ClearStack(Stack &S){ if(S.base)S.top = S.base; return OK; }
4、出栈与入栈
//出 Status Pop(Stack &S,ElementType &e){ if(S.top==S.base)//栈空 return ERROR; e = *--S.top; return OK; } //入 Status Push(Stack &S,ElementType e){ if(S.top-S.base==S.StackSize)//栈满 return ERROR; *S.top++=e; return OK; }
链栈
链栈的结构与一般的链表差不多
//链栈 //表示方法 typedef struct StackNode{ ElementType data; struct StackNode *next; }StackNode,*LinkStack;
由于链表独特的结构特性——找到最后一个需要顺着指针一个一个寻找,对于栈这种一边存取的结构显然是很费时间的。于是采用反向指针

相关操作
1、初始化
//初始化 void InitStack(LinkStack &S){ S = NULL; return OK; }
2、判断是否为空
//判断是否为空 Status StackEmpty(LinkStack S){ if(S==NULL)return TRUE; else return FALSE; }
3、出栈和入栈
//入栈 Status Push(LinkStack &S,ElementType e){ p = new StackNode;//新建节点 p->data = e;//赋值 p->next = S;//接到栈顶上 S = p;//S指针上移 return OK; } //出栈 Status Pop(LinkStack &S,ElementType &e){ if(S==NULL)return ERROR;//判断是否为空 e = S->data;//把删除的值记录下来 p = S; S = S->next;//S指针下移 delete p;//释放空间 return OK; }
4、取栈顶元素
//取栈顶元素 ElementType GetTop(LinkStack S){ if(S!=NULL) return S->data; }
队列
队列可分为顺序队列与循环队列
队列的表示方法与栈类似,这里顺序队列为例
typedef struct Queue{ ElementType *base;//初始空间 int front;//头指针 int rear;//尾指针,下标 }Queue; //头指针和尾指针可以用下标代替,所以直接用的int型
从存取过程可以看出

入队的一头会越来越长,出队的一头会越来越短。但是,出队一头的空间按照规定不能用的,这就造成了极大的空间浪费,
为解决这个问题,于是有了循环队列。
当队列入队的那一头满了,就又从另一端开始加

但是这样也产生了问题,队空和队列满都是front=rear,怎么判断?
1,另外设置一个标志表示空还是满
2,另外设置一个量表示元素个数
3,少用一个元素空间
三种方法选哪个?
另外front-rear为负数怎么办?
对于这两个问题,一般采用的是,少用一个空间,求余数的办法
综上,队列的状态为
队空:front = rear
队满:(rear+1)%Maxsize == front
顺序队列
上述关于循环队列的引入就是以顺序队列为例子,相关操作为
1、队列的初始化
//初始化 Status InitQueue(Queue &Q){ Q.base = new ElementType[MaxSize];//分配空间 if(!Q.base)exit ERROR;//分配失败 Q.front = Q.rear=0;//头尾指针都为零 return OK; }
2、求队列长度
//求队列长度 int QueueLength(Queue Q){ return (Q.rear-Q.front+MaxSize)%MaxSize;//求余操作,应对出现负数的情况 }
3、出队和入队
//入队 Status EnQueue(Queue &Q,ElementType e){ if((Q.rear+1)%MaxSize==Q.front) return ERROR;//队列已满,溢出错误 Q.base[Q.rear] = e;//把e加在队尾 Q.rear = (Q.rear+1)%MaxSize;//队尾指针加一 return OK; } //出队 Status DeQueue(Queue &Q,ElementType &e){ if(Q.front==Q.rear) return ERROR;//队列为空,出现错误 e = Q.base[Q.front];//删除的值记录在e中 Q.front = (Q.front+1)%MaxSize;//队头元素加一 return OK; }
4、取出头部元素front
//取出对头元素 ElementType GetHead(Queue Q){ if(Q.front!=Q.rear)//队列不能为空 return Q.base[Q.front]; }
链队
无论是栈还是队列,采用链表的一个好处就是,几乎不用担心空间的大小,因为可以动态申请与释放
typedef struct QueueNode{ ElementType data; struct QueueNode *next; }QueueNode,*QueuePtr;
由于链表的两端时间复杂度相差太大,所以采用头尾两个指针的形式,带有头节点,rear端插入,front端删除

Status InitQueue(LinkQueue &Q){ Q.front=Q.rear=(QueuePtr)malloc(sizeof(QueueNode)); if(!Q.front)exit ERROR;//失败 Q.front->next = NULL; return OK; }
2、销毁队列
Status DestroyQueue(LinkQueue &Q){ while(Q.front){ p = Q.front->next; free(Q.front); Q.front = p;//依次释放 } return OK; }
3、出队和入队
//出队 Status DeQueue(LinkQueue &Q,ElementType &e){ if(Q.rear==Q.front) return ERROR; p = Q.front->next; e = p->data;//记录下删除的值 Q.front->next = p->next;//头节点指向下下一节点 if(Q.rear==p)Q.rear=Q.front;//如果头节点后面就是rear节点... free(p);//释放空间 return OK; } //入队 Status EnQueue(LinkQueue &Q,ElementType e){ p = (QueuePtr)malloc(sizeof(QueueNode)); if(!p)exit ERROR; p->data = e;//赋值 p->next = NULL; Q.rear->next = p;//把p接在队尾 Q.rear = p;//尾指针后移 }
4、取得对头元素
Status GetHead(LinkQueue Q,ElementType &e){ if(Q.front==Q.rear)retur ERROR; e = Q.front->next->data; }

浙公网安备 33010602011771号