前言:最近看各大公司的面试笔试题,发现对栈和队列的考察还是挺多,而且这两个都是经典的数据结构,我想虽然简单,但是基础非常重要,还是有必要总结总结;
1 栈的概念
栈(Stack):是限制在表的一端进行插入和删除操作的线性表。又称为后进先出LIFO (Last In First Out)或先进后出FILO (First In Last Out)线性表。
栈顶(Top):允许进行插入、删除操作的一端,又称为表尾。用栈顶指针(top)来指示栈顶元素。
栈底(Bottom):是固定端,又称为表头。
空栈:当表中没有元素时称为空栈。
2 栈的实现:
栈有两种实现,一种是顺序储存,一种是链式储存;
实现代码:
Stack.h
#define MAX_STACK_SIZE 100 /* 栈向量大小 */
typedef int ElemType ;
//栈的顺序储存
/*typedef struct sqstack
{ ElemType stack_array[MAX_STACK_SIZE] ;
int top;
int bottom;
}SqStack ;
SqStack Init_Stack();
void push(SqStack &S , ElemType e);
void pop( SqStack &S, ElemType &e );
*/
//栈的链式表示
typedef struct Stack_Node
{ ElemType data ;
struct Stack_Node *next ;
} Stack_Node ;
Stack_Node *Init_Link_Stack(void);
void push(Stack_Node *top , ElemType e);
void pop(Stack_Node *top , ElemType *e);
Stack.c
#include "Stack.h"
#include <stdlib.h>
/*
SqStack Init_Stack(void)
{ SqStack S ;
S.bottom=S.top=0 ;
return(S) ;
}
void push(SqStack &S , ElemType e)
{ if (S.top==MAX_STACK_SIZE-1)
return ;
S.stack_array[++S.top]=e ;
}
void pop( SqStack &S, ElemType &e )
{ if ( S.top==0 )
return ;
e=S.stack_array[S.top--] ;
}
*/
//链表实现
Stack_Node *Init_Link_Stack(void)
{ Stack_Node *top ;
top=(Stack_Node *)malloc(sizeof(Stack_Node )) ;
top->next=NULL ;
return(top) ;
}
void push(Stack_Node *top , ElemType e)
{ Stack_Node *p ;
p=(Stack_Node *)malloc(sizeof(Stack_Node)) ;
if (!p) return;
p->data=e ;
p->next=top->next ;
top->next=p ; /* 钩链 */
}
void pop(Stack_Node *top , ElemType *e)
/* 将栈顶元素出栈 */
{ Stack_Node *p ;
if (top->next==NULL )
return ;
p=top->next ;
*e=p->data ; /* 取栈顶元素 */
top->next=p->next ; /* 修改栈顶指针 */
free(p) ;
}
main:
#include <stdio.h>
#include "Stack.h"
void main(){
int e= 0;
Stack_Node *s=Init_Link_Stack();
push(s,1);
push(s,2);
pop(s,&e);
printf("%d\n",e);
}
2 队列的基本概念
队列(Queue):也是运算受限的线性表。是一种先进先出(First In First Out ,简称FIFO)的线性表。只允许在表的一端进行插入,而在另一端进行删除。
队首(front) :允许进行删除的一端称为队首。
队尾(rear) :允许进行插入的一端称为队尾。
例如:排队购物。操作系统中的作业排队。先进入队列的成员总是先离开队列。
实现:queue.h
#define MAX_QUEUE_SIZE 100
typedef int ElemType;
//队列的顺序储存
/*
typedef struct queue
{ ElemType Queue_array[MAX_QUEUE_SIZE] ;
int front ;
int rear ;
}SqQueue;
SqQueue Init_Queue(void);
void enQueue(SqQueue &Q , ElemType e);
void deQueue(SqQueue &Q, ElemType *x );
*/
//队列的链式储存
typedef struct Qnode
{ ElemType data ;
struct Qnode *next ;
}QNode ;
typedef struct link_queue
{ QNode *front , *rear ;
}LinkQueue ;
LinkQueue *Init_LinkQueue(void);
void enLinkQueue(LinkQueue *Q , ElemType e);
void deLinkQueue(LinkQueue *Q, ElemType *x);
queue.c
#include "queue.h"
#include <stdlib.h>
/*
SqQueue Init_Queue(void)
{ SqQueue Q ;
Q.front=Q.rear=0;
return(Q) ;
}
void enQueue(SqQueue &Q , ElemType e)
{ if(Q.rear==MAX_QUEUE_SIZE-1)
return ;
Q.Queue_array[Q.rear++]=e ;
}
void deQueue(SqQueue &Q, ElemType *x )
{ if (Q.front== Q.rear)
return ;
*x=Q.Queue_array[Q.front++] ;
}
*/
LinkQueue *Init_LinkQueue(void)
{
QNode *p=(QNode *)malloc(sizeof(QNode)) ; /* 开辟头结点 */
p->next=NULL ;
LinkQueue *Q=(LinkQueue *)malloc(sizeof(LinkQueue)) ;
/* 开辟链队的指针结点 */
(*Q).front=(*Q).rear=p ;
return(Q) ;
}
void enLinkQueue(LinkQueue *Q , ElemType e)
/* 将数据元素e插入到链队列Q的队尾 */
{ QNode* p=(QNode *)malloc(sizeof(QNode)) ;
if (!p) return;
p->data=e ;
p->next=NULL ; /* 形成新结点 */
(*Q).rear->next=p ;
(*Q).rear=p ; /* 新结点插入到队尾 */
}
void deLinkQueue(LinkQueue *Q, ElemType *x)
{ QNode *p ;
if ((*Q).front==(*Q).rear) return ; /* 队空 */
p=(*Q).front->next ; /* 取队首结点 */
*x=p->data ;
(*Q).front->next=p->next ; /* 修改队首指针 */
if (p==(*Q).rear) (*Q).rear=(*Q).front ;
/* 当队列只有一个结点时应防止丢失队尾指针 */
free(p) ;
}
循环队列:
为充分利用向量空间,克服上述“假溢出”现象的方法是:将为队列分配的向量空间看成为一个首尾相接的圆环,并称这种队列为循环队列(Circular Queue)。
在循环队列中进行出队、入队操作时,队首、队尾指针仍要加1,朝前移动。只不过当队首、队尾指针指向向量上界(MAX_QUEUE_SIZE-1)时,其加1操作的结果是指向向量的下界0。
这种循环意义下的加1操作可以描述为:
if (i+1==MAX_QUEUE_SIZE) i=0;
else i++ ;
其中: i代表队首指针(front)或队尾指针(rear)
cirqueue.h
#define MAX_QUEUE_SIZE 100
typedef int ElemType;
typedef struct queue
{ ElemType Queue_array[MAX_QUEUE_SIZE] ;
int front ;
int rear ;
}SqQueue;
SqQueue Init_CirQueue(void);
int length(SqQueue Q);
void enCirQueue(SqQueue Q , ElemType e);
void deQueue(SqQueue Q, ElemType *x );
cirqueue.c
#include "cirqueue.h"
SqQueue Init_CirQueue(void)
{ SqQueue Q ;
Q.front=Q.rear=0;
return(Q) ;
}
int length(SqQueue Q){
return (Q.rear-Q.front+MAX_QUEUE_SIZE)%MAX_QUEUE_SIZE;
}
void enCirQueue(SqQueue Q , ElemType e)
/* 将数据元素e插入到循环队列Q的队尾 */
{ if ((Q.rear+1)%MAX_QUEUE_SIZE== Q.front)
return ; /* 队满,返回 */
Q.Queue_array[Q.rear]=e ; /* 元素e入队 */
Q.rear=(Q.rear+1)% MAX_QUEUE_SIZE ;
}
void deQueue(SqQueue Q, ElemType *x )
/* 将循环队列Q的队首元素出队 */
{ if (Q.front+1== Q.rear)
return ; /* 队空,返回错误标志 */
*x=Q.Queue_array[Q.front] ; /* 取队首元素 */
Q.front=(Q.front+1)% MAX_QUEUE_SIZE ;
/* 队首指针向前移动 */
}