C语言数据结构-队列

队列的特征:

特殊的线性表,先进先出(FIFO)

(1)数据:对于非空的队列,表头没有直接前驱,表尾没有直接后继,其他有且仅有一个直接前驱和一个直接后继。

(2)操作:只允许在表尾插入数据,在表头删除数据

顺序队列:

定义:

它是顺序表的一种,具有顺序表同样的数据结构,由数组定义,配合用数组下标表示对头指针和队尾指针完成各种操作。

表示:

#define MAXSIZE 10
typedef int datatype;/* 定义队列中数据元素的数据类型*/

typedef struct seq{

	datatype data[MAXSIZE]; /* 用数组作为队列的存储空间*/

	int front;//front:始终存放队头位置的前一个下标;
    int rear; //rear:始终存放队尾元素的下标
 
}seqqueue,*seqqueue_p; /* 顺序队列类型定义*/

存在的问题:

1、入队和出队:随着入队、出队操作的进行,整个队列会整体向后移动,这样就出现了下图的现象:队尾指针虽然已经移到了最后,而队列却未真满的“假溢出”现象,使得队列的空间没有得到有

效的利用。

C语言数据结构-队列_第1张图片

改进前:

C语言数据结构-队列_第2张图片

改进方法:改进为一个循环队列

改进后:

C语言数据结构-队列_第3张图片

2、根据问题1的改进后,可得到一个循环队列,如下图所示,这时候我们初始化队列时就不应该将front和rear初始化为-1了(当然也不是不可以,只是根据循环队列更好理解),那么我们就应该把front和rear初始化为MAXSIZE-1;这时候问题又来了,当我们一直入队操作,当满了之后,front和rear又相等了,这就不能判断队列到底为空还是为满(因为rear==front这个条件也为空队列时的条件)。无法区别满对和空对

C语言数据结构-队列_第4张图片

改进办法:少用(损失)一个空间,以队尾下标加1等于对头下标作为队满的标志。因此:当front=rear=MAXSIZE-1,表示循环队列为空;当front ==(rear+1)% MAXLEN,表示循环队列为满。

示例程序:用循环队列实现如下功能:用户从键盘输入整数,程序将其入队,用户输入字母,程序将对头元素出队,并在每次出队和入队之后打印队列元素。

代码实现:

seqqueue.c

#include "seqqueue.h"

void create_seqqueue(seqqueue_p *seq)//创建一个队列
{
	(*seq) = (seqqueue_p)malloc(sizeof(seqqueue));
	if(NULL == (*seq))
	{
		perror("malloc");
		exit(-1);
	}
	// 断其臂,保其身,最后一个空。定义为满状态 
	(*seq)->front = (*seq)->rear = MAXSIZE-1;//初始化队头以及队尾指针
	
	return;
}
/* 判断队列是否已满*/
bool is_full_seqqueue(seqqueue_p seq)
{
	if( (seq->rear+1)%MAXSIZE == seq->front )
	{
		//已满 
		return true;
	} 
	else
	{
		return false;
	} 
} 
/* 入队*/
bool in_seqqueue(seqqueue_p seq,datatype data)
{
	//判断队列是否已满
	if(is_full_seqqueue(seq)) 
	{
		printf("队列已满\r\n");
		return false;
	}
	//入队
	seq->rear = (seq->rear+1) % MAXSIZE;
	seq->data[seq->rear] = data;
	
	return true; 
} 

/* 判断队列是否为空*/
bool is_empty_seqqueue(seqqueue_p seq)
{
	if(seq->front == seq->rear)
	{
		//已空 
		return true;
	}
	return false; 
} 
/* 出队*/
bool out_seqqueue(seqqueue_p seq,datatype* data)
{
	//判断队列是否为空
	if(is_empty_seqqueue(seq))
	{
		printf("队列已空\r\n");
		return false; 
	}
	//出队
	seq->front = (seq->front+1)%MAXSIZE;
	*data = seq->data[seq->front];
	
	return true;
}
/* 打印*/ 
void show_seqqueue(seqqueue_p seq)
{
	int i;
	if(is_empty_seqqueue(seq))
	{
		/* 空不打印*/
		return;
	} 
	/* 非空时,从对头打印数据到队尾*/
	for(i=(seq->front+1)%MAXSIZE ;i!=(seq->rear+1)%MAXSIZE; i=(i+1)%MAXSIZE) 
	{
		printf("%d\r\n",seq->data[i]);
	}
	
	return;
} 

seqqueue.h

#ifndef __SEQQUEUE_H__
#define __SEQQUEUE_H__

#include 
#include 
#include 
#include 

#define MAXSIZE 10
typedef int datatype;/* 定义队列中数据元素的数据类型*/
typedef struct seq{
	datatype data[MAXSIZE]; /* 用数组作为队列的存储空间*/
	int front,rear;//front:指向队头位置的前一个元素的下标; rear;指向队尾元素的下标 
}seqqueue,*seqqueue_p; /* 顺序队列类型定义*/

/**************************函数声明*******************************/
void create_seqqueue(seqqueue_p *seq);//创建一个队列 
/* 入队*/
bool in_seqqueue(seqqueue_p seq,datatype data); 
/* 出队*/
bool out_seqqueue(seqqueue_p seq,datatype* data);
/* 打印*/
void show_seqqueue(seqqueue_p seq);

#endif

main.c

#include "seqqueue.h"

int main()
{
	datatype data,t;
	seqqueue_p seq;
	int ret;
	
	
	create_seqqueue(&seq);//顺序队列初始化
	
	while(1)
	{
		printf("请输入一个整数:");
		ret = scanf("%d",&data);
		//输入的是整数,入队 
		if(ret == 1)
		{
			if(in_seqqueue(seq,data))
			{
				//插入元素成功 
				show_seqqueue(seq);
			}
		}
		//输入为字符时,出队 
		else
		{
			if(out_seqqueue(seq,&t))
			{
				printf("out:%d\r\n",t);
				show_seqqueue(seq);
			}
			//将前一个scanf输入的缓冲区通过循环全部清空
			while (getchar() != '\n');//表示只要字符不是回车就继续吃缓冲区字符
		}	
	} 
	
	return 0;
}

链式队列

定义:

链式队列中每个元素定义成一个结点,含数据域与指针域(指向下一结点),并设头尾指针。用图表示就是。

规定:

front: 指向队头节点的前一个节点(头节点)的指针。

rear: 指向队尾节点的指针。

 表示:

typedef int datatype;    /* 定义链对列中数据元素的数据类型*/

typedef struct node{

    datatype data;        /* 数据域*/
    struct node *next;    /* 链接指针域*/

}linklist;                /* 链对元素类型定义*/

typedef struct{

    linklist *front,*rear;       /* 链队列指针*/

}linqueue,*linqueue_p;                /* 链队列类型定义*/

链队的基本操作

1. 链队的初始化

lsqueue *CreateLqueue()
{
	linkqueue * head = (linkqueue *)malloc(sizeof(linkqueue));
	if(head == NULL)
		return NULL;
	head->data = -1;
	head->next = NULL;
	
	lsqueue * lq = (lsqueue *)malloc(sizeof(lsqueue));
	if(lq == NULL)
		return NULL;
	lq->front = lq->rear = head;

	return lq;
}

2、入队

int EnLqueue(lsqueue *lq,data_t data)
{
	if(lq == NULL)
		return -1;
	linkqueue *new = (linkqueue *)malloc(sizeof(linkqueue));
	if(new == NULL)
		return -1;
	new->data = data;
	new->next = NULL;

	lq->rear->next = new;

	lq->rear = new;
	return 0;
}

3、出队

data_t DeLqueue(lsqueue *lq)
{
	if(lq == NULL || Lsqueue_is_Empty(lq))
		return -1;
	linkqueue *p = lq->front->next;
	data_t m = p->data;
	//如果p是最后一个有效结点 那么需要把rear 调整回跟 front 相等
	if(p->next != NULL)
	{

	lq->front->next = p->next;
	free(p);
	p = NULL;
	}else{

	lq->front->next = p->next;
	lq->rear = lq->front;
	free(p);
	p = NULL;
	}
	return m;

}

4、判断队列是否为空

int Lsqueue_is_Empty(lsqueue *lq)
{
	if(lq == NULL)
		return -1;
	return lq->front == lq->rear;
}

5、打印队列

int PrintLinkqueue(lsqueue *lq)
{
	if(lq == NULL)
		return -1;
	linkqueue *p = lq->front->next;
	while(p != NULL)
	{
		printf(" %d ",p->data);
		p = p->next;
	}
	printf("\n");
}

你可能感兴趣的:(C语言,数据结构,c语言)