数据结构-3.4-栈与队列
学习资料:数据结构C语言版 清华大学出版社(以后的略)
这次一次过把栈和队列都写好了。栈和队列 存储结构和顺序表有些像。不过栈是先进后出,队列是先进先出。
栈和队列的应用其实还是挺多的,不过我属于入门学习阶段……所以就先把最基本的代码给实现了……学完整本课内要求的数据结构内容后会将这些各种各样的数据结构应用在别的题目上的!!!
栈:时限定仅在表尾进行插入或者删除操作的线性表。表尾成为栈顶,表头段称为栈底。不含元素的栈称为空栈。
栈的实现:
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<iostream> 4 using namespace std; 5 #define TRUE 1 6 #define FALSE 0 7 #define OK 1 8 #define ERROR 0 9 #define OVERFLOW -2 10 #define STACK_INIT_SIZE 100//存储空间的初始分配量 11 #define STACKINCREMENT 10//存储空间分配增量 12 13 typedef int Status; 14 typedef int Selemtype; 15 typedef struct node 16 { 17 int data; 18 struct node *next; 19 } Stack; 20 21 22 Status IsEmpty(Stack *t) 23 { 24 if(t->next==NULL) 25 { 26 return TRUE; 27 } 28 return FALSE; 29 } 30 void InitStack(Stack *top) 31 { 32 top->next=NULL;//将栈顶设为空 33 } 34 Status Push(Stack *top,Selemtype e) 35 { 36 //创造新的节点 存放传入的e 37 Stack *p; 38 p=(Stack*)malloc(sizeof(Stack)); 39 if(p==NULL) 40 { 41 return 0; 42 } 43 p->data=e; 44 p->next=top->next; 45 top->next=p; 46 return OK; 47 } 48 Status Pop(Stack *top,Selemtype &e) 49 { 50 if(IsEmpty(top)) return 0; 51 Stack *p; 52 p=top->next;//栈顶下面第一个节点是要出栈的 53 e=p->data; 54 top->next=p->next;//栈内元素的前移 55 free(p); 56 return OK; 57 } 58 59 60 int main() 61 { 62 int a; 63 Stack *top=(Stack*)malloc(sizeof(Stack));//生成一个栈顶指针 64 InitStack(top); 65 while(~scanf("%d",&a)) 66 { 67 Push(top,a); 68 } 69 Stack *p=top->next; 70 printf("the elemet in the stack:\n"); 71 while(p) 72 { 73 printf("%d ",p->data); 74 p=p->next; 75 } 76 cout<<endl; 77 78 int x; 79 Pop(top,x); 80 cout<<"The ele that you delete is "<<x<<" ."<<endl; 81 82 p=top->next; 83 printf("the elemet in the stack:\n"); 84 while(p) 85 { 86 printf("%d ",p->data); 87 p=p->next; 88 } 89 p=NULL; 90 91 cout<<endl; 92 cout<<"Now pop all the data:"<<endl; 93 while(Pop(top,x)) 94 { 95 printf("%d ",x); 96 } 97 cout<<endl; 98 free(top); 99 return 0; 100 }
功能函数:
1、IsEmpty:判断栈是否为空,传入指向头结点的指针,判断栈顶项是否为空。若为空返回true,否则返回false。
2、InitStack:使传入的头结点指针一个指为空。
3、Push:创造一个新的结点(分配相应的存储空间),在该生成的结点的数据域里面存放传入的Selemtype e。该生成的结点放在栈顶位置,原栈顶元素及以下均往后推一个位置。(实现的时候只是改变了指针的指向,像单链表)。
4、Pop:需要判断栈是否为空。生成一个指向栈的指针指向栈顶元素,释放栈顶元素的空间,原指向栈顶的头指针指向栈顶指向的next地址。会将出栈数据赋值到传入的Selemtype e上。方便输出检查结果。
5、主函数:对上述几个函数进行了相应的测试。先为栈顶分配sizeof(Stack)的内存空间,调用InitStack函数将栈置空。将栈置空后调用Push函数,以ctrl+z结束输入。输入一定的数据,将数据按顺序压入栈内,再调将压入栈内的元素按照从栈顶到栈尾的顺序输出(其实我觉得我可以将这一段再写一个小函数,使代码功能划分更强……)。调用Pop函数删除栈顶元素后再遍历输出一次栈内元素。最后顺序调用Pop函数将所有剩余的存储的数据出栈。
{写到这里我想到了一个问题,为什么每一次分配内存空间的时候都要将分配的内存空间置空(或者清0)呢?
询问了老师和百度了一下才知道原来(不要打我,我真的今天才知道这么一回事……以前都是按照书本代码养成的习惯……)在分配新的内存空间的时候这个空间里原本是存放着一些数据的。按理来说,是可以直接使用这段内存,可是万一存放的时候存在没有存放新数据但是却分配了内存的空间段,在检查结果输出数据的时候很可能会把原来存放在这个内存空间里的数据输出来,可能会造成难以发现的错误。}
队列:是一种先进先出的线性表结构。只允许在表的一端插入,在另一端删除元素。类似我们日常生活中的排队。允许插入的一端称为队尾,删除的一端称为队头。这里用了链队列的链式表示实现的代码。
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<iostream> 4 using namespace std; 5 #define TRUE 1 6 #define FALSE 0 7 #define OK 1 8 #define ERROR 0 9 #define OVERFLOW -2 10 11 typedef int Status; 12 typedef int ElemType; 13 14 //定义队列 15 typedef struct node{ 16 int data; 17 struct node *next; 18 }Queue; 19 //定义队首队尾 20 typedef struct pointer{ 21 Queue *front;//队首指针,不存放队列元素(类似链表中的表头 22 Queue *rear;//队尾指针,存放队尾的数据元素 23 }Qpointer; 24 25 //队列的初始化 26 void QueueInit(Qpointer *qp) 27 { 28 Queue *que; 29 que=(Queue*)malloc(sizeof(Queue)); 30 que->next=NULL;//队首和队尾指向同一个内存空间,指针域为NULL 31 qp->front=que; 32 qp->rear=que; 33 } 34 35 int IsEmpty(Qpointer *qp) 36 { 37 if(qp->front==qp->rear) 38 { 39 return TRUE; 40 } 41 return FALSE; 42 } 43 44 int QueuePush(Qpointer *qp,int e) 45 { 46 Queue *que; 47 que=(Queue*)malloc(sizeof(Queue));//为新生成的结点分配内存空间 48 if(que==NULL) 49 { 50 return 0; 51 } 52 que->data=e; 53 que->next=NULL; 54 qp->rear->next=que;//将节点插入队列尾 55 qp->rear=que; 56 return 0; 57 } 58 int QueuePop(Qpointer *qp,int *e) 59 { 60 Queue *que; 61 if(IsEmpty(qp)) 62 { 63 return 0; 64 } 65 que=qp->front->next;//que指向队列头结点的下一个节点,即真正的队首 66 *e=que->data;//将要出队列的元素 67 qp->front->next=que->next; 68 //判断队列是否就只剩下一个元素 69 if(qp->rear==que) 70 { 71 qp->rear=qp->front; 72 } 73 free(que); 74 return OK; 75 } 76 77 int main() 78 { 79 Qpointer *qp; 80 int x;//队列的初始化 81 qp=(Qpointer*)malloc(sizeof(Qpointer)); 82 QueueInit(qp); 83 84 scanf("%d",&x);//以零结束 85 while(x!=0) 86 { 87 QueuePush(qp,x); 88 scanf("%d",&x); 89 } 90 cout<<"Now output the queue. "<<endl; 91 Queue *p=qp->front->next; 92 if(p==NULL) return 0; 93 while(p) 94 { 95 printf("%d ",p->data); 96 p=p->next; 97 } 98 printf("\n"); 99 //队列的删除 100 101 printf("delete the first data of queue:\n"); 102 QueuePop(qp,&x); 103 p=qp->front->next; 104 if(p==NULL) 105 return 0; 106 while(p) 107 { 108 printf("%d ",p->data); 109 p=p->next; 110 } 111 cout<<endl; 112 //队列的最后删除 113 printf("delete queue:\n"); 114 while(QueuePop(qp,&x)) 115 { 116 printf("%d ",x); 117 } 118 printf("\n"); 119 p=qp->front; 120 free(p); 121 free(qp); 122 return 0; 123 124 }
队列的定义:使用了两个结构体去定义队列。node结构体定义了一个数据域和一个指针域。pointer定义了队首指针和队尾指针,其中队首指针指向的node数据域为空,队尾指针指向的node存放队尾的数据元素。
1、QueueInit:队列的初始化。在主函数中会生成一个指向Queue的指针。传入这个指针,为其分配sizeof(Queue)的内存空间。并使队首和队尾指向同一个内存空间。
2、IsEmpty:判断队列是否为空。判断方法:队首指针和队尾指针是否相同。是返回true,否则返回false。
3、QueuePush:为新生成的结点分配内存空间,需要判断队列是否为空。(为啥呢……)将传入的e值赋给新生成结点的数据域。将新生成结点插入到队尾。
4、QueuePop:需要判断队列是否为空。将要出队的元素赋值给传入的地址e方便输入检查结果。需要最后判断一下队列是否只剩下了一个元素,如果是的话就要将队列的队首赋值给队尾(好销毁)。最后释放que指针。
5、主函数:队列的初始化,先生成一个指向Qpointer的指针,为其分配内存空间。调用QueueInit函数初始化。输入数据以0结束(原本想用~scanf来写,可是不知道为什么不好使了……改了就出错……)调用QueuePush函数再次将输入的数据入队。顺序输出输入的函数(其实我觉得可以写一个void的函数来实现这个过程……)。调用QueuePop函数,将队首元素出队,再遍历输入队里的数据。最后像栈一样多次调用QueuePop函数将所有队员出队,最后销毁指针,释放内存空间。
实现了基础的栈和队列……比较开心。