栈
定义:栈是一种只能在一端进行插入或删除操作的线性表。
栈顶:允许进行插入、删除操作的一端。
栈底:表的另一端。
空栈:栈中没有数据元素。
进栈/入栈:栈的插入操作。
退栈/出栈:栈的删除操作。
主要特点:后进先出。
栈的顺序存储结构及其基本运算实现
假设栈元素最大不超过MaxSize,所有元素都具有同一数据类型ElemType
定义顺序栈
typedef struct
{ ElemType data[MaxSize];
int top;//栈顶指针
}SqStack;
总结:
约定top总指向栈顶元素,初始值为-1
当top=MaxSize-1时不能再进栈
进栈top+1,出栈top-1
顺序栈4要素:
栈空条件:top=-1
栈满条件:top=MaxSize-1
进栈e操作:top++,将e放在top处
退栈操作:从top处取出元素e,top–
1、初始化栈InitStack(&s)
void InitStack(SqStack *&s)
{ s=(SqStack *)malloc(sizeof(SqStack));
s->top=-1;
}
2、销毁栈DestroyStack(&s)
void DestroyStack(SqStack *&s)
{ free(s);
}
3、判断栈是否为空StackEmpty(s)
bool StackEmpty(SqStack *s)
{
return(s->top==-1);
}
4、进栈Push(&s,e)
bool Push(SqStack *&s,ElemType e)
{ if(s->top==MaxSize-1)
return False;
s->top++;
s->data[s->top]=e;
return true;
}
5、出栈Pop(&s,&e)
bool Pop(SqStack *&s,ElemType &e)
{ if(s->top==-1)
return false;
e=s->data[s->top];
s->top--;
return true;
}
6、取栈顶元素GetTop(s,&e)
bool GetTop(SqStack *s,ElemType &e)
{
if(s->top==-1)
return false;
e=s->data[s->top];
return true;
}
链栈
数据节点定义如下:
typedef struct linknode
{ ElemType data;
struct linknode *next;
}LiStack;
1、初始化栈InitStack(&s)
void InitStack(LiStack *&s)
{ s=(LiStack *)malloc(sizeof(LiStack));
s->next=NULL;
}
2、销毁栈DestroyStack(&s)
{ LiStack *p=s,*q=s->next;
while(q!=NULL)
{ free(p);
p=q;
q=p->next;
}
free(p);
}
3、判断栈是否为空StackEmpty(s)
bool StackEmpty(LiStack *s)
{
return(s->next==NULL);
}
4、进栈Push(&s,e)
void Push(LiStack *&s,ElemType e)
{ LiStack *p;
p=(LiStack *)malloc(sizeof(LiStack));
p->data=e;
p->next=s->next;
s->next=p;
}
5、出栈Pop(&s,&e)
bool Pop(LiStack *&s,ElemType &e)
{ LiStack *p;
if(s->next==NULL)
return false;
p=s->next;
e=p->datal
s->next=p->next;
free(p);
return true;
}
6、取栈顶元素GetTop(s,e)
bool GetTop(LiStack *s,ElemType &e)
{ if(s->next==NULL)
return false;
e=s->next->data;
return true;
}
队列
定义:队列只能选取一个端点进行插入操作,另一个端点进行删除操作
概念:
队尾:进行插入的一端
队首/队头:进行删除的一端
进队/入队:向队列中插入新元素,新元素进队后就成为新的队尾元素
出队/离队:元素出队后,其后继元素就成为队首元素
主要特点:先进先出
队列的顺序存储结构及其基本运算的实现
顺序队类型SqQueue定义如下:
typedef struct
{ ElemType data[MaxSize];
int front,rear;//队首和队尾指针
}SqQueue;
总结:约定rear总是指向队尾元素
元素进队,rear增1
约定front指向当前队中队头元素的前一位置
元素出队,front增1
当rear=MaxSize-1时不能再进队
顺序队4要素:
队空条件:front=rear
队满条件:rear=MaxSize-1
元素e进队:rear++;data[rear]=e;
元素e出队:front++;e=data[front];
缺点:当队满条件为真时,队中可能还有若干空位置。
这种溢出并不是真正的溢出,称为假溢出。
1、初始化队列
void InitQueue(SqQueue *&q)
{ q=(SqQueue *)malloc(sizeof(SqQueue));
q->front=q->rear=-1;
}
2、销毁队列
void DestroyQueue(SqQueue *&q)
{
free(q);
}
3、判断队列是否为空
bool QueueEmpty(SqQueue *q)
{
return(q->front==q->rear);
}
4、进队列
bool enQueue(SqQueue *&q,ElemType e)
{ if(q->rear==MaxSize-1)
return false;
q->rear++;
q->data[q->rear]=e;
return true;
}
5、出队列
bool deQueue(SqQueue *&q,ElemType &e)
{ if(q->front==q->rear)
return false;
q->front++;
e=q->data[q->front];
return true;
}
环形队列
4要素:
1、队空条件:front=rear
2、队满条件:(rear+1)%MaxSize=front
3、进队e操作:rear=(rear+1)%MaxSize;
4、出队操作:front=(front+1)%MaxSize
1、已知front、rear,求队中元素个数count:
count=(rear-front+MaxSize)%MaxSize
2、已知front、count,求rear:
rear=(front+count)%MaxSize
3、已知rear、count,求front:
front=(rear-count+MaxSize)%MaxSize
环形队列类型:
typedef struct
{ ElemType data[MaxSize];
int front; //队头指针
int count; //队列中元素个数
}QuType;
进队运算算法
bool EnQueue(QuType *&qu,ElemType x)
{ int rear; //临时队尾指针
if(qu->count==MaxSize)
return false;
else{
rear=(qu->front+qu->count)%MaxSize;
rear=(rear+1)%MaxSize;//队尾循环增1
qu->data[rear]=x;
qu->count++;
return true;
}
}
出队运算算法:
bool DeQueue(QuType *&qu,ElemType &x)
{ if(qu->count==0)
return false;
else{
qu->front=(qu->front+1)%MaxSize;
x=qu->data[qu->front];
qu->count--;
return true;
}
}
比较:
1、环形队列比非环形队列更有效利用内存空间,即环形队列会重复使用已经出队元素的空间,不会出现假溢出。
2、如果算法中需要使用所有进队元素来进一步求解,此时可以使用非环形队列。
链队
定义:采用链表存储的队列,采用不带头节点的单链表实现。
组成:1、存储队列元素的单链表节点
2、指向队头和队尾指针的链队头节点
单链表中数据节点类型QNode
typedef struct qnode
{ ElemType data;//数据元素
struct qnode *next;
}QNode;
链队中头节点类型LiQueue
typedef struct
{ QNode *front;
QNode *rear;
}LiQueue;
链队4要素:
1、队空条件:front=rear=NULL
2、队满条件:不考虑
3、进队e操作:将包含e的节点插入到单链表表尾
4、出队操作:删除单链表首数据节点
链队的存储结构及其基本运算的实现
1、初始化队列
void InitQueue(LiQueue *&q)
{ q=(LiQueue *)malloc(sizeof(LiQueue));//即只创建一个链队头节点
q->front=q->rear=NULL;
}
2、销毁队列
void DestroyQueue(LiQueue *&q)
{ QNode *p=q->front,*r;
if(p!-NULL)
{ r=p->next;
while(r!=NULL)
{ free(p);
p=r;r=p->next;
}
}
free(p);free(q);
}
3、判断队列是否为空
bool QueueEmpty(LiQueue *q)
{
return(q->rear==NULL);
}
4、进队
void enQueue(LiQueue *&q,ElemType e)
{ QNode *p;
p=(QNode *)malloc(sizeof(QNode));
p->data=e;
p->next-NULL;
if(q->rear==NULL)//若链队为空,新节点是队首节点又是队尾节点
q->front=q->rear=p;
else
{ q->rear->next=p;//将p节点链到队尾,并将rear指向它
q->rear=p;
}
}
5、出队
void deQueue(LiQueue *&q,ElemType &e)
{ QNode *t;
if(q->rear==NULL) return false;
t=q->front;
if(q->front==q->rear)
q->front=q->rear=NULL;
else
q->front=q->front->next;
e=t->data;
free(t);
return true;
}