赞
踩
目录
概念:
栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端 称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫出栈。出数据也在栈顶。
注意:
(1)通常称入栈(插入)、出栈(删除)的这一端为栈顶(top),另一端称为栈底(Bottom)。
(2)当线性表中没有元素时叫称为空栈。
(3)栈为后进先出(Last In First Out)的线性表,简称为LIFO表。
栈的结构: 如下图。
(1)StackInit(Stack* ps):构造一个空栈。
(2)StackEmpty(Stack* ps):判栈空。若为空栈,则返回TRUE,否则返回FALSE。
(3)StackPush(Stack* ps, StackDataType x):进栈。将元素 x 插入到栈顶。
(4)StackPop(Stack* ps):退栈。若栈非空,则将栈顶的元素删去。
(5)StackTop(Stack* ps):取栈顶的元素。若栈非空,则返回栈顶元素,但不改变栈的状态。
(6)StackSize(Stack* ps):栈的大小。也就是栈的元素个数。
(7)StackDestroy(Stack* ps):销毁栈。栈使用结束,就对栈进行销毁。
实现栈的基本运算选择的是顺序表呢?还是链表呢?两者都是可以实现的,但是为了选择更为优一些的方法。首先,来对比一下这两个的优缺点,再做抉择。
顺序表:
优点:
(1)支持随机访问(用小标访问)。需要随机访问的结构支持的算法可以很好的适用/
(2)CPU高速缓存命中率更高(不懂需要百度)。
缺点:
(1)头部中部插入删除时间效率低(原因:删除头部,还要把头部后面的全部数据往前移)。O(N)
(2)连续的物理空间,空间不够了以后需要增容。
a.增容有一定程度消耗。
b.为了避免频繁增容,一般我们都是按倍数去增容,用不完可能存在一定的空间浪费。
链表(带头双向循环链表):
优点:
(1)任意位置插入删除效率高。O(1)
(2)按需申请释放空间。
缺点:
(1)不支持随机访问。(不支持用下标访问)意味着:一些排序、二分查找等在这种结构不适合用。
(2)链表存储一个值,同时要存储链接指针,有一定的消耗。
(3) CPU高速缓存命中率更低(不懂需要百度)。
对比以上顺序表和链表的优缺点,基本上可以判断出顺序表实现栈更为优一些。栈的性质就是先进后出。假设顺序表和链表实现栈的结构如下图:
两者都是尾插和尾删。时间复杂度基本一致。链表(带头双向循环)唯一缺点就是CPU高速缓存命中率更低。基于这一缺点,这里我们是使用顺序表来实现栈的基本操作。
stack.h
- #pragma once
- #include<stdlib.h>
- #include<stdio.h>
- #include<assert.h>
- #include<stdbool.h>
-
- typedef int StackDataType;//栈的数据类型
-
- //顺序栈类型的定义----动态顺序表
- typedef struct Stack
- {
- StackDataType* data; //栈的数据
- int top; //栈顶
- int capacity; //栈的容量
- }Stack;
-
- //栈基本操作的接口函数
- void StackInit(Stack* ps);//初始化栈---构造一个空栈
- void StackDestroy(Stack* ps);//销毁栈
- void StackPush(Stack* ps, StackDataType x);//栈顶插入一个元素---进栈
- void StackPop(Stack* ps);//删除栈的元素---退栈/出栈
- StackDataType StackTop(Stack* ps);//取栈顶的数据
- int StackSize(Stack* ps);//栈的元素个数
- bool StackEmpty(Stack* ps);//判空
stack.c
- #define _CRT_SECURE_NO_WARNINGS 1
- #include "stack.h"
-
- void StackInit(Stack* ps)//初始化栈---构造一个空栈
- {
- assert(ps);
- ps->data = NULL;
- ps->top = 0; // top=-1,top指向栈顶的数据;top=0,top指向栈顶的下一个
- ps->capacity = 0;//栈的初始容量
- }
-
- void StackDestroy(Stack* ps)//销毁栈
- {
- assert(ps);
- free(ps->data); //释放内存
- ps->capacity = 0;
- ps->top = 0;
- }
-
- void StackPush(Stack* ps, StackDataType x)//栈顶插入一个元素---进栈
- {
- assert(ps);
- if (ps->capacity == ps->top)//开辟内存及其内存空间不足扩容
- {
- ps->capacity = ps->capacity == 0 ? 6 : ps->capacity * 2;
- StackDataType* temp = (StackDataType*)realloc(ps->data, sizeof(StackDataType) * ps->capacity);
- if (temp == NULL)
- {
- printf("realloc fail\n");
- exit(-1);//开辟失败异常退出
- }
- ps->data = temp;
- }
- ps->data[ps->top] = x;//插入元素数据
- ps->top++;//指向栈顶元素的下一个
- }
-
- void StackPop(Stack* ps)//删除栈的元素---退栈/出栈
- {
- assert(ps);
- assert(!StackEmpty(ps));//栈为空就不能删除了
- ps->top--;//开始删除
- }
-
- StackDataType StackTop(Stack* ps)//取栈顶的数据
- {
- assert(ps);
- assert(!StackEmpty(ps));//当栈为空时不取出数据
- return ps->data[ps->top - 1];//因为top是指向栈顶数据的下一个,所以 top-1 才能取到栈顶的元素
- }
-
- int StackSize(Stack* ps)//栈的元素个数
- {
- return ps->top;
- }
-
- bool StackEmpty(Stack* ps)//判空---判断栈是否为空
- {
- assert(ps);
- //if (ps->top == 0)
- //{
- // return true;
- //}
- //else
- //{
- // return false;
- //}
-
- return ps->top == 0;//当 top初始化为-1是需要写为 return ps->top==-1;
-
- }
test.c
- #define _CRT_SECURE_NO_WARNINGS 1
- #include"stack.h"
-
- void TestStack()
- {
- Stack st;
- StackInit(&st);
- StackPush(&st, 1);//插入数据
- StackPush(&st, 2);
- StackPush(&st, 3);
- StackPush(&st, 4);
- StackPush(&st,5);
- //后进先出原则:5 4 3 2 1
- //栈是不能像顺序表、链表那样直接随便取数据
- //取栈的数据只有一个方式,就是需要把栈顶的数据取出来了才能取下一个,才符合栈的性质
-
- while (!StackEmpty(&st))
- {
- printf("%d ", StackTop(&st));//先取栈顶的数据
- //取了栈顶的数据,想要取栈顶的下一个数据,把当前的栈顶的数据 pop 掉,就是删除掉
- //才能取下一个栈的数据
- StackPop(&st);
- }
-
- StackDestroy(&st);//销毁栈
- }
-
- int main()
- {
- TestStack();
- return 0;
- }
概念:
注意:
(1)允许删除的一端称为队头(Front)。
(2)允许插入的一端称为队尾(Back)。
(3)当队列中没有元素时称为空队列。
(4)队列亦称做先进先出(First In First Out)的线性表,简称为 FIFO 表。
队列的结构:如下图。
(1)QueueInit(Queue* pq):置空队列。构造一个空队列。
(2)QueueEmpty(Queue* pq):判队空。若队列为空,则返回真值,否则返回假值。
(3)QueuePush(Queue* pq, QueueDataType x):将元素 x 插入队列的队尾,此操作简称为入队。
(4)QueuePop(Queue* pq):若队列非空,则删去队列的队头元素,此操作简称为出队。
(5)QueueFront(Queue* pq):取队头元素数据。若队列非空,则返回队头元素,但不改变队列的状态。
(6)QueueBack(Queue* pq):取队尾元素。若队列非空,则返回队尾元素,但不改变队列的状态。
(7)QueueSize(Queue* pq):队列元素个数。
(8)QueueDestroy(Queue* pq):销毁队列。
入队:
出队:
queue.h
- #pragma once
- #include<stdlib.h>
- #include<stdio.h>
- #include<assert.h>
- #include<stdbool.h>
-
- typedef int QueueDataType;//队列元素的数据类型
-
- //链表队列类型定义
- typedef struct QueueNode
- {
- struct QueueNode* next;
- QueueDataType data;
- }QueueNode;
-
- typedef struct Queue
- {
- QueueNode* head; //队列头指针
- QueueNode* tail; //队列尾指针
-
- }Queue;
-
- //队列基本操作的函数接口
- void QueueInit(Queue* pq);//初始化队列--置空队列。构造一个空队列。
- void QueueDestroy(Queue* pq);//销毁队列
- void QueuePush(Queue* pq, QueueDataType x);//向队尾插入一个元素---入队列
- void QueuePop(Queue* pq);//删除队头元素
- QueueDataType QueueFront(Queue* pq);//取队头元素
- QueueDataType QueueBack(Queue* pq);//取队尾元素
- int QueueSize(Queue* pq);//队列元素个数
- bool QueueEmpty(Queue* pq);//判空--判断队列是否为空
queue.c
- #define _CRT_SECURE_NO_WARNINGS 1
- #include"queue.h"
-
- void QueueInit(Queue* pq)//初始化队列--置空队列。构造一个空队列。
- {
- assert(pq);
- pq->head = NULL;
- pq->tail = NULL;
- }
-
- void QueueDestroy(Queue* pq)//销毁队列
- {
- assert(pq);
- QueueNode* current = pq->head;//记录头指针
- while (current)
- {
- QueueNode* next = current->next;//记录头指针的下一个结点的指针
- free(current);
- current = next;
- }
- pq->head = pq->tail = NULL;//释放结束将头尾指针置空
- }
-
- void QueuePush(Queue* pq, QueueDataType x)//向队尾插入一个元素---入队列
- {
- assert(pq);
- QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
- newnode->data = x;
- newnode->next = NULL;
- //尾插
- if (pq->head == NULL)//第一次入队
- {
- pq->head = pq->tail = newnode;
- }
- else
- {
- pq->tail->next = newnode;
- pq->tail = newnode;//更新尾指针
- }
- }
-
- void QueuePop(Queue* pq)//删除队头元素
- {
- assert(pq);
- assert(!QueueEmpty(pq));
- //开始头删
- QueueNode* headNext = pq->head->next;
- free(pq->head);
- pq->head = headNext;
- if (pq->head == NULL)//当把队列删空了,不仅要把 head 置空,还要把 tail 置空
- {
- pq->tail = NULL;
- }
- }
-
- QueueDataType QueueFront(Queue* pq)//取队头元素
- {
- assert(pq);
- assert(!QueueEmpty(pq));//队列非空就取
- return pq->head->data;
- }
-
- QueueDataType QueueBack(Queue* pq)//取队尾元素
- {
- assert(pq);
- assert(!QueueEmpty(pq));//队列非空就取
- return pq->tail->data;
- }
-
- int QueueSize(Queue* pq)//队列元素个数
- {
- //遍历队列,进行计数,返回出结果
- assert(pq);
- int count = 0;
- QueueNode* current = pq->head;
- while (current)
- {
- ++count;
- current = current->next;
- }
-
- return count;
- }
-
- bool QueueEmpty(Queue* pq)//判空--判断队列是否为空
- {
- assert(pq);
- return pq->head == NULL;//队列为空就为真,否则为假
- }
test.c
- #define _CRT_SECURE_NO_WARNINGS 1
- #include"queue.h"
-
- void TestQueue()
- {
- Queue qu;
- QueueInit(&qu);
- QueuePush(&qu, 1);//入队
- QueuePush(&qu, 2);
- QueuePush(&qu, 3);
- QueuePush(&qu, 4);
- QueuePush(&qu, 5);
-
- //出队-----先进先出----1 2 3 4 5
- //取队头的元素,想要取出队头的下一个元素,将队头 Pop,才能取下一个
- while (!QueueEmpty(&qu))
- {
- QueueDataType front = QueueFront(&qu);
- printf("%d ", front);
- QueuePop(&qu);
- }
- printf("\n");
-
- QueueDestroy(&qu);//销毁队列
- }
-
- int main()
- {
- TestQueue();
- return 0;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。