數據結構之隊列的鏈式存儲結構 C語言版

前言

在上次的文章中,我們實現了隊列的順序存儲,也就是循環隊列,既然有順序存儲,那就有鏈式存儲。鏈式有個問題,究竟是需要頭結點呢,還是不需要頭結點呢,其實都可以,在鏈棧中我們使用的是沒有頭結點,那麼在鏈隊中我們就用有頭結點的結構

1.循環隊列和鏈隊列的區別

在空間上,鏈隊列比較靈活。在可以確定隊列長度最大值的情況下,建議使用循環隊列,如果你無法預估隊列的長度時,則用鏈隊列

2.鏈隊的定義

鏈隊也和鏈棧一樣,需要兩個結構體來定義,但是在實現過程中發現統計隊列長度時不好統計,那麼我們就和鏈棧一樣,給直接他設置一個計數器。來統計隊列的長度。統計時直接返回計數器的值。

//定義結點
typedef struct QNode
{
	QElemType data;
	struct QNode* next;
}QNode,*QueuePtr;

//定義鏈隊列
typedef struct
{
	QueuePtr front,rear;//隊頭指針和隊尾指針
	int count;//計數器
}LinkQueue;

3.有無頭結點之分

有無頭結點之分,其實是體現在初始化上
1.在鏈棧中,我們沒有使用頭結點,從代碼中可以看到,沒有頭結點時棧頂指針直接指向空,其初始化:

//沒有頭結點的鏈棧初始化
Status InitStack(LinkStack *s)
{
	s->top = NULL;
	s->count = 0;
	return OK;
}

2.在這片鏈隊的初始化中,有頭結點,利用第一個結構體創造出頭結點,讓隊頭和隊尾指針都指向這個創造的頭結點,其初始化:

//有頭結點鏈隊的初始化
Status InitQueue(LinkQueue *Q)
{
	QueuePtr head = (QueuePtr)malloc(sizeof(QNode));
	head->next = NULL;
	Q->front = head;
	Q->rear = head;
	Q->count = 0;
	return OK;
}

4.內容佈局

本篇文章所涉及的主要操作有:
1.入隊

Q->rear->next = s;
Q->rear = s;
Q->count++;

2.出隊

QueuePtr p;
	QElemType e;
	if(Q->front == Q->rear)//隊空
		return ERROR;
	p = Q->front->next;
	e = p->data;
	Q->front->next = p->next;
	if(Q->rear == p)
		Q->front=Q->rear;
	free(p);
	Q->count--;

3.顯示
先定義一個指針,顯示之後再逐漸爲空,直到指針移到空

QueuePtr p=Q->front->next;
	printf("棧內容爲:\n");
	while(p)
	{
		printf("%d ",p->data);
		p = p->next;
	}

代碼如下

/*
程序名稱:鏈棧的建立與基本操作
編譯環境:vs2010
最後修改:2019.8.3
作者:xuan
*/
#include<stdio.h>
#include<stdlib.h>

#define M 5
#define OK 1
#define ERROR 0
typedef int Status;
typedef int QElemType;

//定義結點
typedef struct QNode
{
	QElemType data;
	struct QNode* next;
}QNode,*QueuePtr;

//定義鏈隊列
typedef struct
{
	QueuePtr front,rear;//隊頭指針和隊尾指針
	int count;//計數器
}LinkQueue;

Status InitQueue(LinkQueue *Q);//初始化循環隊列
Status EnQueue(LinkQueue *Q);//入隊
Status DeQueue(LinkQueue *Q);//出隊
Status Display(LinkQueue *Q);//顯示
Status Clear(LinkQueue *Q);//置空

int main()
{
	Status i;
	LinkQueue Q;
	int n=0;
	InitQueue(&Q);
	while(n!=-1)
	{
		printf("						\n");
		printf(" 1.入隊 2.出隊 3.清空隊 -1.退出 \n");
		scanf("%d",&n);
		switch(n)
		{
		case 1:
			i = EnQueue(&Q);
			if(i == ERROR)
				printf("失敗\n");
			Display(&Q);
			break;
		case 2:
			i = DeQueue(&Q);
			if(i == ERROR)
				printf("失敗\n");
			Display(&Q);
			break;
		case 3:
			Clear(&Q);
			printf("操作後的順序棧:\n");
			Display(&Q);
			break;
		}
	}
	return 0;
}

//初始化循環隊列
Status InitQueue(LinkQueue *Q)
{
	QueuePtr head = (QueuePtr)malloc(sizeof(QNode));
	head->next = NULL;
	Q->front = head;
	Q->rear = head;
	Q->count = 0;
	return OK;
}

//入隊
Status EnQueue(LinkQueue *Q)
{
	QElemType x = 0;
	printf("請輸入數據,-1時停止\n");
	while(x != -1)
	{
		scanf("%d",&x);
		if(x != -1)
		{
			QueuePtr s = (QueuePtr)malloc(sizeof(QNode));
			s->data = x;
			s->next = NULL;
			Q->rear->next = s;
			Q->rear = s;
			Q->count++;
		}
	}
	return OK;
}

//出隊
Status DeQueue(LinkQueue *Q)
{
	QueuePtr p;
	QElemType e;
	if(Q->front == Q->rear)//隊空
		return ERROR;
	p = Q->front->next;
	e = p->data;
	Q->front->next = p->next;
	if(Q->rear == p)
		Q->front=Q->rear;
	free(p);
	Q->count--;
	printf("出隊的元素爲:%d\n",e);
	return OK;
}

//顯示
Status Display(LinkQueue *Q)
{
	QueuePtr p=Q->front->next;
	printf("棧內容爲:\n");
	while(p)
	{
		printf("%d ",p->data);
		p = p->next;
	}
	printf("\n");
	printf("隊列的長度爲:%d\n",Q->count);
	return OK;
}

//置空
Status Clear(LinkQueue *Q)
{
	Q->front = Q->rear;
	Q->count = 0;
	return OK;
}

運行結果

運行結果

後記

上述代碼把鏈隊的各種操作柔和到一個方程裏面,以致於代碼有些龐大,但是在實際操作中還可以適當加減操作

以上就是鏈棧的表示和各種操作,喜歡的多多支持哦~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章