数据结构 【栈与队列】
栈
栈满足下列两点:
1.栈只能从表的一端存取数据,另一端是封闭的。
2.在栈中,无论是存数据还是取数据,都必须遵循"先进后出"的原则,即最先进栈的元素最后出栈。
总结:栈是一种只能从表的一端存取数据且遵循 "先进后出" 原则的线性存储结构。
如图:栈存储结构存储 {1,2,3,4}
栈的顺序表实现:
顺序表就是采用数组+尾指针的方式,尾指针一直指向最后一个元素,这里特殊的地方在于,栈为空时,尾指针指向-1.
#include <stdio.h> #define Size 100 typedef struct stacktag { int a[Size]; int top; }stack; #入栈 int rush(int* a,int top,int elem){ if(++top>=Size) { printf("栈已满\n"); return --top; } a[++top]=elem; printf("插入元素:%d\n",a[top]); return top; }
#出栈 int pop(int * a,int top){ if (top==-1) { printf("空栈"); return -1; } printf("弹栈元素:%d\n",a[top]); top--; return top; } int main () { stack stack1; stack1.top = -1; printf("初始化成功\n"); stack1.top = rush(stack1.a,stack1.top,1); stack1.top = rush(stack1.a,stack1.top,5); stack1.top = pop(stack1.a,stack1.top); return 0; }
初始化成功 插入元素:1 插入元素:5 弹栈元素:5
栈的链表实现:
使用链表实现注意一点:
数据插入采用头插法,数据每次弹出头部的元素
#include <stdio.h> #include<malloc.h> //声明链表节点类型 typedef struct LISTtag LISTtagNode; struct LISTtag{ int value; LISTtagNode *next; }; int size=0; //创建链表 LISTtagNode * create(){ LISTtagNode *head; head = (LISTtagNode*)malloc(sizeof(LISTtagNode)); head->next = NULL; return head; } //在链表头新增节点 int push(LISTtagNode *head,int value){ if(head == NULL){ return -1; } //新建节点 LISTtagNode *node; node = (LISTtagNode*)malloc(sizeof(LISTtagNode)); //节点赋值,此节点跟在头节点后 node->value = value; node->next = head->next; head->next = node; size++; return 1; } //打印链表 int PrindLinKList(LISTtagNode *head){ if(head == NULL){ return -1; } LISTtagNode *t = head; while (t->next != NULL) { t = t->next; printf("%d ", t->value); } return 1; } int pop(LISTtagNode *head){ if(head ==NULL){ return -1; } LISTtagNode *node; int index = 0; while(head->next!=NULL&&index<1){ node = head->next; index++; } if(index == 1){ printf("\n%d ",node->value); if(head->next->next != NULL){ head->next = head->next->next; }else{ head->next =NULL; } free(node); size--; return 1; } return -1; } int top(LISTtagNode *head){ if(head ==NULL){ return -1; } LISTtagNode *node; int index = 0; while(head->next!=NULL&&index<1){ node = head->next; index++; } if(index == 1){ printf("%d ",node->value); return 1; } return -1; } int empty(LISTtagNode *head){ if(head ==NULL){ return -1; } if(head->next!=NULL){ return 0; } return 1; } int length(LISTtagNode *head){ if(head ==NULL){ return -1; } return size; } int main () { LISTtagNode *head = create(); push(head,7); push(head,9); push(head,23); push(head,43); push(head,45); push(head,65); printf("\n正序打印链表:"); PrindLinKList(head); printf("\n链表长度:%d",length(head)); pop(head); printf("\n正序打印链表:"); PrindLinKList(head); printf("\n链表长度:%d",length(head)); return 0; }
队列
队列满足下列两点:
1.队列从一端表存储数据,从另一端是读取数据。
2.数据的入队和出队遵循"先进先出"的原则;
总结:队列是一种从表的一端存储数据,从另一端读取数据,满足“先进先出”的数据结构。
队列的实现:
#include <stdio.h> #define max 5//表示顺序表申请的空间大小 int enQueue(int *a,int front,int rear,int data){ //添加判断语句,如果rear超过max,则直接将其从a[0]重新开始存储,如果rear+1和front重合,则表示数组已满 if ((rear+1)%max==front) { printf("空间已满"); return rear; } a[rear%max]=data; rear++; return rear; } int deQueue(int *a,int front,int rear){ //如果front==rear,表示队列为空 if(front==rear%max) { printf("队列为空"); return front; } printf("%d ",a[front]); //front不再直接 +1,而是+1后同max进行比较,如果=max,则直接跳转到 a[0] front=(front+1)%max; return front; } int main() { int a[max]; int front,rear; //设置队头指针和队尾指针,当队列中没有元素时,队头和队尾指向同一块地址 front=rear=0; //入队 rear=enQueue(a,front,rear, 1); rear=enQueue(a,front,rear, 2); rear=enQueue(a,front,rear, 3); rear=enQueue(a,front,rear, 4); //出队 front=deQueue(a, front, rear); //再入队 rear=enQueue(a,front,rear, 5); //再出队 front=deQueue(a, front, rear); //再入队 rear=enQueue(a,front,rear, 6); //再出队 front=deQueue(a, front, rear); front=deQueue(a, front, rear); front=deQueue(a, front, rear); front=deQueue(a, front, rear); return 0; }
1 2 3 4 5 6
使用环形表实现顺序队列的方法需要注意的是,顺序队列在判断数组是否已满时,出现下面情况:
- 当队列为空时,队列的头指针等于队列的尾指针;
- 当数组满员时,队列的头指针等于队列的尾指针;
顺序队列初始状态没有存储任何元素,因此 top 指针和 rear 指针重合,且由于顺序队列底层实现靠的是数组,因此 top 和 rear 实际上是两个变量,它的值分别是队头元素和队尾元素所在数组位置的下标。
顺序队列的存储状态不同,但是判断条件相同。为了对其进行区分,最简单的解决办法是:牺牲掉数组中的一个存储空间,判断数组满员的条件是:尾指针的下一个位置和头指针相遇,就说明数组满了,即程序中第 5 行所示。