回顾一下【栈和队列】

下面来回顾一下

数据结构中比较常用的两种类型:栈和队列

栈:是一个特殊的线性表,只能在一端操作,即先进后出

栈顶:允许操作的一端

栈底:不允许操作的一端


空栈:不含任何数据元素的栈,top = -1,当栈中有一个元素时,top = 0;


一、顺序存储(一般采用循环队列)

顺序栈:即栈的顺序存储结构是利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素

顺序存储中,我们通常用数组下标表示结点的位置,因此当 top 为 0 时,并不表示该栈为空,而

表示含有一个结点;

所以在初始化的时候,将 top = -1;


顺序栈的定义:

typedef  struct sqStack{
      int data[MAXSIZE];
      int top;
  }STACK;

栈最重要的操作就是出栈和入栈了

首先是进栈:

 int Push(STACK *S, int e)
  {
       if(S->top == MAXSIZE -1)
       		return error;
       S->top++;
       S->data[S->top]=e;
        return OK; 
  }


其次是出栈:

 int Pop(STACK *S, int *e)
  {
  		if(S->top == -1)
  			return ERROR;
  		*e=S->data[S->top];
  		S->top--;
  		return OK;
 }



二、栈的链式存储(链栈)

栈顶放在单链表的头部;链栈是不需要头结点的;链栈不存在栈满的情况

顺序栈的内存在声明顺序表时就已经分配好了,而链栈的结点在使用时,

利用 malloc 分配就行了


链栈的定义:

struct node
{
	int data;
	struct node *next;
};

typedef struct node Node;
typedef Node * LinkNode;

struct stack
{
	LinkNode top;
	int count;   //负责记录链栈的长度
};


进栈:

栈是先进后出的数据结构,只能在栈顶进行操作,所以刚进入的结点要和 top 建立联系

代码如下:

int Push(LinkStack *s, int e)
{
	LinkNode p = (LinkNode)malloc(sizeof(Node));

	if (p == NULL)
	{
		return ERROR;
	}

	p->data = e;
	p->next = s->top;
	s->top = p;
	s->count++;

	return OK;
}

出栈:

出栈的话首先要定义变量来存储要删除的栈顶指针,其次将栈顶指针指向下一个结点,最后释放变量

代码如下:

int Pop(LinkStack *s, int *e)
{
	LinkNode p;
	if (StackEmpty(s) == OK)
		return ERROR;

	*e = s->top->data;
	p = s->top;
	s->top = s->top->next;
	free(p);
	s->count--;

	return OK;
}


队列:

队列是特殊的线性表,队列仅在线性表两端进行操作(一端进行插入,另一端进行删除)

队头(front)取出数据的一端

队尾(rear)放入数据的一端


队列也分为顺序队列和链式队列

循环队列:

一般规定 front 指针指向队头元素,rear指针指向队尾元素的下一个位置(避免只出现一个元素

队头和队尾的重合处理麻烦),这样当 front 等于 rear的时候,就表示该队列为空队列

rear指针指向队尾元素的下一个位置,当队列满时,这时会出现假溢出的现象,所以对于一个容量

为 MAXSIZE 的队列,最多只能存放 MAXSIZE-1 个元素,为了解决这个问题,通常采用循环队列


循环队列通俗点说就是头尾相接的队列,所以这种情况下,rear 也会出现在 front 的前面,当队满

再插入一个元素时,原先队头元素出队,此时 front 会向后移,而 rear 就在 front 前面


如何判断队满和求该队列的长度

有两个公式:

判断队满:(rear+1)% MAXSIZE == front

求队列长度:(rear-front+MAXSIZE)% MAXSIZE 

这里的 rear 和 front 都是数组的下标


循环队列定义:

 typedef  struct {
   			int data[MAXSIZE];
   			int front;
   			int rear;
   }SqQueue;

循环队列初始化:

 int InitQueue(SqQueue *Q)
   {
   		Q->front = 0;
   		Q->rear  = 0;
   		return OK; 
   }


循环队列入队:

 int EnQueue(SqQueue *Q, int e)
   {
   		if((Q->rear+1)%MAXSIZE ==Q->front)
   			return ERROR;
   		Q->data[Q->rear] = e;
   		Q->rear=(Q->rear+1)%MAXSIZE;
   	   	return OK;
   }



循环队列出队:

 int DeQueue(SqQueue *Q, int *e)
   {
   		if(Q->rear==Q->front)
   			return ERROR;
   		*e=Q->data[Q->front];
   		Q->front=(Q->front+1)%MAXSIZE;
   		return OK;
   }

链式队列:

队列的链式存储结构,其实就是线性表的单链表,只是它只能从尾进队,从头出队

一般我们将队头指针指向链队列的头结点,而将队尾指针指向尾结点


链式队列定义:

struct node
{
	int data;
	struct node *next;
};

typedef struct node *Node;

struct queue
{
	Node front;
	Node rear;
};

typedef struct queue LinkQueue;


链式队列进队:

int EnQueue(LinkQueue *q, int e)
{
	Node s = (Node)malloc(sizeof(node));
	if (NULL == s)
	{
		return ERROR;
	}

	s->data = e;
	s->next = NULL;
	q->rear->next = s;
	q->rear = s;

	return OK;
}


链式队列出队

int DeQueue(LinkQueue *q, int *e)
{
	Node p = q->front->next;
	if (p == NULL)
	{
		return ERROR;
	}

	q->front->next = p->next;
	*e = p->data;
	free(p);

	if (q->front->next == NULL)
	{
		q->front = q->rear;
	}

	return OK;
}


好了,关于栈和队列的介绍就到这了(不是很全),下次再见!




猜你喜欢

转载自blog.csdn.net/ljf_djcrs/article/details/79403609