第三章限定线性表-------栈与队列
栈
1.栈是一种线性表,但限定这种线性表只能在某一端进行插入或删除的操作,栈的特性:后进先出。
栈顶:允许进行插入和删除的那一端
栈厎:固定的,不允许进行插入或删除的另一端。
n个不同元素进栈,出栈元素不同排列的个数为1/(n+1)C2nn
1.顺序栈
typedef int ElemType; #define true 1 #define false 0 #define MaxSize 100//定义栈中元素的最大个数 typedef struct { ElemType data[MaxSize];//存放栈中元素的一维数组 int top;//栈顶指针 }SqStack; //栈顶指针S.top,初始时设-1,栈顶元素S.data[S.top] // 栈空:S.top==-1,栈满:S.top==MaxSize-1,栈长:S.top+1; //初始化 void InitStack(SqStack* S) { S->top = -1; } //判栈空 int IsEmptyStack(SqStack S) { if (S.top == -1) return true; else return false; } //进栈 int Push(SqStack* S, ElemType x) { if (S->top == MaxSize - 1) return false; S->top++; S->data[S->top] = x; return true; } //出栈 int Pop(SqStack* S, ElemType* x) { if (S->top == -1) return false; *x = S->data[S->top]; S->top--; return true; } //读取栈顶元素 int GetTop(SqStack *S, ElemType *x) { if (S->top == -1) return false; *x = S->data[S->top]; }
2.多栈共享技术:最常用的是两个栈的共享技术,双端栈,两个栈共享一片空间,提高内存资源利用率,降低发生上溢的可能。
#include "stdlib.h" #include "stdio.h"; #include "stdbool.h" #define M 100 #define StackElemType int typedef struct { StackElemType Stack[M]; StackElemType top[2]; }DqStack; void InitStack(DqStack* S) { S->top[0] = -1; S->top[1] = M; } int Push(DqStack* S, StackElemType x, int i) { if (S->top[0] + 1 == S->top[1]) return false; switch (i){ case 0: S->top[0]++; S->Stack[S->top[0]] = x; break; case 1: S->top[1]--; S->Stack[S->top[1]] = x; break; default: return false; } return true; } int Pop(DqStack* S, StackElemType* x, int i) { switch (i) { case 0: if (S->top[0] == -1) return false; *x = S->Stack[S->top[0]]; S->top[0]--; break; case 1: if (S->top[1] == M) return false; *x = S->Stack[S->top[1]]; S->top[1]++; break; default: return false; } return true; }
3.链栈
链栈即采用链表作为存储结构实现的栈,链表的表头指针就作为栈顶指针,栈顶指针始终指向当前栈顶元素前面的头结点。若top->next==NULL,则代表栈空。
采用链栈不必预先估计栈的最大容量,只要系统有可用空间,链栈就不会出现溢出,对于链栈,在使用完毕时,应该释放相应空间
#include "stdlib.h" #include "stdio.h" #define true 1 #define false 0 typedef int ElemType; typedef struct node { ElemType data; struct node* next; }LinkStackNode; typedef LinkStackNode* LinkStack; //链栈进栈 int Push(LinkStack top, ElemType x) { LinkStackNode *temp; temp = (LinkStackNode*)malloc(sizeof(LinkStackNode)); if (temp == NULL)//申请空间失败 return false; temp->data = x; temp->next = top->next; top->next = temp;//修改当前栈顶指针 return true; } //链栈出栈 int Pop(LinkStack top, ElemType *x) { LinkStackNode *temp; temp = top->next; if (temp == NULL)//栈空 return false; top->next = temp->next; *x = temp->data; free(temp); return true; }
队列
一种操作受限的线性表,只允许在表的一端插入,而在表的另一端删除,特性:先进先出
队头:允许删除的一端,又称队首。
队尾:允许插入的一端
1.顺序存储结构:
重点看循环队列:为了解决假溢出现象并使队列得到充分利用,将顺序队列想象成一个环状的空间,即把存储队列元素的表从逻辑上视为一个环,称为循环队列。
在非空循环队列中,队头指针始终指向当前的队头元素,而队尾指针始终指向真正队尾元素后面的单元
当队首指针Q.font=Q.MaxSize-1后,再前进一个位置就自动到0,这就可以利用除法取余运算来实现。
初始时:Q.front=Q.rear=0
队首指针进1:Q.front=(Q.front+1)%MaxSize
队尾指针进1:Q.rear=(Q.rear+1)%MaxSize
队列长度:(Q.rear+MaxSize-Q.front)%MaxSize
出队入队时:指针都顺时针方向进1
判队空:Q.front=Q.rear
队满:1.损失一个元素空间,当队尾指针所指向的空单元的后继单元是队头元素所在的单元时,则停止入队。队满:(Q.rear+1)%MaxSize==Q.front
2.增设表示元素个数的数据单元,队空:Q.size=0;队满:Q.size=MaxSize
3.增设tag数据成员,初始化时:rear=front=tag=0;每次删除成功:tag=0;每次插入成功:tag=1;
队满:front==rear&&tag==1 队空:front==rear&&tag=0,删除才可能致空,插入才可能致满。
#include "stdio.h" #include "stdlib.h" typedef int ElemType; #define MaxSize 50 #define true 1 #define false 0 typedef struct { ElemType data[MaxSize];//存放队列元素 int front, rear;//队头指针和队尾指针 }SqQueue; //初始化 void InitQueue(SqQueue* Q) { Q->rear = Q->front = 0; } //判断空 int IsEmpty(SqQueue Q) { if (Q.rear == Q.front) return true; else return false; } //入队 int EnterQueue(SqQueue *Q, ElemType x) { if ((Q->rear + 1) % MaxSize == Q->front)//队满则报错 return false; Q->data[Q->rear] = x; Q->rear = (Q->rear + 1) % MaxSize;//队尾指针加1取模 return true; } //出队 int DeQueue(SqQueue* Q, ElemType* x) { if (Q->rear == Q->front)//队空则报错 return false; x = Q->data[Q->front]; Q->front = (Q->front + 1) % MaxSize;//队头指针加1取模 return true; }
typedef struct { ElemType data[MaxSize]; int front, rear; int tag; }SeqQueue; void InitQueueC(SeqQueue* Q) { Q->rear = Q->front = 0; Q->tag = 0; } int Isempty(SeqQueue Q) { if (Q.front == Q.rear && Q.tag == 0) return true; else return false; } int enterQueue(SeqQueue* Q, ElemType x) { if (Q->front == Q->rear && Q->tag == 1) return false; Q->data[Q->rear] = x; Q->rear = (Q->rear + 1) % MaxSize; Q->tag = 1; return true; } int Dequeue(SeqQueue* Q, ElemType* x) { if (Q->front == Q->rear && Q->tag == 0) return false; *x = Q->data[Q->front]; Q->front = (Q->front + 1) % MaxSize; Q->tag = 0; return true; } typedef struct { ElemType data[MaxSize]; int front, rear; int size; }Queue; void init(Queue* Q) { Q->rear = Q->front = 0; Q->size = 0; } int isEmpty(Queue Q) { if (Q.size == 0) return true; else return false; } int enqueue(Queue* Q, ElemType x) { if (Q->size == MaxSize) return false; Q->data[Q->rear] = x; Q->rear = (Q->rear + 1) % MaxSize; Q->size++; return true; } int dequeue(Queue* Q, ElemType* x) { if (Q->size == 0) return false; *x = Q->data[Q->front]; Q->front = (Q->front + 1) % MaxSize; Q->size--; return true; }
队列长度:(rear+MaxSize-front)%MaxSize;
2.链队列
若采用带头结点的链表结构:队头指针始终指向头结点,队尾指针指向最后一个元素,空的链队列的队头指针和队尾指针均指向头结点。
typedef struct Node{//链式队列结点 ElemType data; struct Node *next; }LinkQueueNode; typedef struct{//链式队列 LinkQueueNode *front, * rear;//队列的队头和队尾指针 }LinkQueue; int Initqueue(LinkQueue* Q) { Q->front = (LinkQueueNode*)malloc(sizeof(LinkQueueNode)); if (Q->front != NULL) { Q->rear = Q->front; Q->front->next = NULL; return true; } else return false; } //链队列入队 int EnterLinkQueue(LinkQueue *Q, ElemType x) { LinkQueueNode *NewNode; NewNode = (LinkQueueNode*)malloc(sizeof(LinkQueueNode)); if (NewNode != NULL) { NewNode->data = x; NewNode->next = NULL; Q->rear->next = NewNode; Q->rear = NewNode; return true; } else return false; } //链队列出队 int DeleteQueue(LinkQueue* Q, ElemType* x) { LinkQueueNode* p; if (Q->front == Q->rear) return false; p = Q->front->next; Q->front->next = p->next;//队头元素p出队 if (Q->rear == p)//若队中只有一个元素p,则p出队后为空队列 Q->rear = Q->front; *x = p->data; free(p); return true; }

浙公网安备 33010602011771号