队列的基本操作我使用的是链式结构的方式来实现
关于队列:
1.队列的特性特点:队列是一种“先进先出”缩写为FIFO的线性表。它只允许在表的一端进行插入,而在另一端“删除”元素。
2.队列的两端分别叫做:队头、队尾。队尾:允许插入数据的一端。队头:允许“删除”数据的一端。
链队列:
1.在链队列中 它的队头就是头结点(表头),而队尾无需固定(插入时确定)。
2.链队列创建之初需要确定两个结构,一个是结点结构、一个是链队结构。
结点结构:
typedef struct QN{
ElemType data;
struct QN *next;
}QN, *QP;
链队结构:
typedef struct{
QP front;
QP rear;
}LinkQ;
3.链队列的几个基本操作:(前提是要先构造一个空队列)
实现队列的清空首先肯定会想到这样写“Q.front = Q.rear; ” 让头等于尾 ,这其实也算是清空,但是这样并没有实现真正意义上的清空它会不断的向内存申请空间造成严重的空间浪费。具体怎样实现清空的看参考下面的代码。
队列数据的输出的关键在于怎样对队列进行遍历输出。由于我使用的是链队列的方式来实现队列的所以可以把它看成是单链表,用单链表的遍历输出模式来进行 放法是:定义一个指针 p 来先指向队列头的next域,然后以“p != NULL”为循环条件来进行遍历输出,当然也不能忘掉空队列的情况,所以用到一个人变量 i 来进行判断。
在入队列时要先考虑一下队列的特性 思考一下用哪种方式来进行入队列比较合适(头插法/尾插法),队列是“先进先出”的如果采用头插法的话不仅遍历起来会很麻烦在查找数据的时候也会很麻烦,所以采用尾插法来进行。 在这里我要特别提醒一下一旦入队列成功一个,那么你的尾指针的指向就要顺移一个“Q.rear = p;”。
定义一个指针p来进行遍历输出
由于队列存在“先进先出”的特点,如若采用头插法来实现入队列就会显得很困难所以采用尾插法来实现
在数据出队列时按照老规矩先判断是否为空队列,若非空那么p指针指向头,将p指针指向的数据赋给要出队列的 e,
当p指针指向最后一个(即 尾rear)时 就将队列置为空。
#include
#include
#define OK 1
#define ERROR 0
typedef int Status;
typedef int ElemType;
//结点结构
typedef struct QN{
ElemType data;
struct QN *next;
}QN, *QP;
//链队列结构
typedef struct{
QP front;
QP rear;
}LinkQ;
void menu()
{
printf("*************************队列基本操作************************\n");
printf("\t\t\t1 队列清空\n");
printf("\t\t\t2 队列数据输出\n");
printf("\t\t\t3 数据入队列\n");
printf("\t\t\t4 数据出队列\n");
printf("\t\t\t0 退出系统\n");
printf("*************************队列基本操作************************\n\n\n");
}
//构造一个空队列
Status InitQ(LinkQ &Q)
{
Q.front=Q.rear=(QP) malloc (sizeof(QN)); //分配空间
if(!Q.front)
exit(ERROR);
Q.front->next=NULL; //头的next指针域为空NULL,表示空队列
return OK;
}
//清空队列
Status ClearQ(LinkQ &Q)
{
QP p,q; //定义;两个指针来指向头(然后依次向后直至尾部)
p = Q.front;
while(p) // 当p指针指向不为空时 从头开始 指一个清空一个
{
q = p;
p = p->next;
free(q);
}
Q.front->next = NULL; //最后将链队列的头front的next域置为空
Q.front = Q.rear; //最后将尾rear 置回来等于 front 重新回到空队列
return OK;
}
//输出队列数据
void PopQ(LinkQ Q)
{
QP p; //定义一个结点结构类型的指针 p
int i = 0;
p = Q.front->next; //让p指针先指向头的next域
while (p!=NULL)
{
i++;
printf("%d\n",p->data);
p = p->next; //让指针p指向下一个
}
if (i == 0)
printf("空队列! 没有数据!\n");
}
//入队列
Status EnterQ(LinkQ &Q,ElemType e)
{
QP p; //定义一个结点结构类型的指针 p
p = (QP)malloc(sizeof (QN)); //给他分配一个空间
if (!p) exit(ERROR);
p->data = e; //p的data域用来存放要如队列的数据
p->next = NULL;
Q.rear->next = p; //采用尾插法
Q.rear = p; //入队列一个,尾指针就移动一个
return OK;
}
//出队列
Status DeleQ(LinkQ &Q,ElemType &e)
{
QP p;
if (Q.rear == Q.front)
return ERROR; //如果是空队列就返回ERROR
p = Q.front->next; //p指针指向头
e = p->data; //将p指针指向的数据赋给要出队列的 e
Q.front->next = p->next; //"尾进头出"
if (Q.rear == p)
Q.rear = Q.front; //当p指针指向最后一个(即 尾rear)时 就将队列置为空
free(p); //释放队列空间
return OK;
}
void main()
{
LinkQ Q;
int choose;
ElemType e=0;
InitQ(Q);
while(1)
{
menu();
printf("Please choose:");
scanf("%d",&choose);
switch(choose)
{
case 1:
if(ClearQ(Q) == OK)
printf("清空成功!\n");
else
printf("清空失败!\n");
getchar(); getchar();
system("cls");
break;
case 2:
PopQ(Q);
getchar(); getchar();
system("cls");
break;
case 3:
printf("请输入数据:");
scanf("%d",&e);
if(EnterQ(Q,e) == OK)
printf("入队成功!\n");
else
printf("入队失败!\n");
getchar(); getchar();
system("cls");
break;
case 4:
printf("出队数据为:\n");
if(DeleQ(Q,e) == OK)
printf("%d\n",e);
else
printf("队空不能出队!\n");
getchar(); getchar();
system("cls");
break;
case 0:
printf("欢迎下次使用,再见!\n");
exit(0);
break;
default:
printf("输入功能选项错误 请输入选项0~4!\n");
getchar(); getchar();
system("cls");
}
}
}