前言
为什么会定义栈和队列这两种数据结构呢?
原因在于:
之所以会定义栈和队列这样的数据结构
是因为他们有两大特性:
第一: 他们可以保存程序运行路径中各个点的信息,以便用于回溯操作或其他需要访问已经访问过的节点信息的操作。
比如: 栈用于解决迷宫问题,就是用到了若线路不通,需要回溯到已访问过的结点,从那个结点再做一次与这次路径不同的选择。
第二: 先进后出 和 先进先出的 次序
先进后出次序 其实就是一种将序列反序操作的次序
先进先出次序 其实就是一种将序列顺序操作的次序
比如: 利用栈的先进后出可以解决进制转化问题 ,即:先将个位余数进栈,再将十位余数进栈,然后百位,千位 等 ,这样出栈的时候顺序就成了反序出栈,即:先千位,百位,然后十位,最后个位。
目录
1.栈的表示和实现
2.队列的表示和实现
1.栈的表示和实现
1.1栈的概念和基本结构
栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底 。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据也在栈顶。
1.2栈的实现
栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小。
链栈的进出示意图
// 下面是定长的静态栈的结构,实际中一般不实用,所以我们主要实现下面的支持动态增长的栈typedef int STDataType;#define N 10typedef struct Stack{STDataType arr[N];int top; // 栈顶}Stack;// 支持动态增长的栈typedef int STDataType;typedef struct Stack{STDataType* arr;int top; // 栈顶int capacity;// 容量}Stack;// 初始化栈void StackInit(Stack* ps);// 入栈void StackPush(Stack* ps, STDataType data);// 出栈void StackPop(Stack* ps);// 获取栈顶元素STDataType StackTop(Stack* ps);// 获取栈中有效元素个数int StackSize(Stack* ps);// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0int StackEmpty(Stack* ps);// 销毁栈void StackDestroy(Stack* ps);
1.2.1初始化栈
//初始化void StackInit(stack* ps){assert(ps);ps->arr = (STDataType*)malloc(4 * sizeof(STDataType)); if (ps->arr == NULL) { printf("malloc fail\n"); exit(-1); }ps->capacity = 4;ps->top = 0;}
1.2.2 入栈/压栈
//压栈void StackPush(stack* ps, STDataType x){assert(ps);if (ps->top == ps->capacity){STDataType* temp= (STDataType*)realloc(ps->arr, ps->capacity *2* sizeof(STDataType));if (temp == NULL){printf("realloc fail\n");exit(-1);}else{ps->arr = temp;ps->capacity *= 2;}}ps->arr[ps->top] = x;ps->top++;}
1.2.3出栈
//出栈void StackPop(stack* ps){assert(ps);assert(ps->top > 0);ps->top--;}
1.2.4获取栈顶元素
//返回栈顶元素STDataType StackTop(stack* ps){assert(ps);assert(ps->top > 0);return (ps->arr[ps->top - 1]);}
1.2.5获取栈中有效个数
//返回栈顶元素STDataType StackTop(stack* ps){assert(ps);assert(ps->top > 0);return (ps->arr[ps->top - 1]);}
1.2.6 返回栈中有效元素个数
//栈长int StackSize(stack* ps){assert(ps);return ps->top;}
1.2.7 判空
//判空bool StackEmpty(stack* ps){assert(ps);return ps->top == 0;}
1.2.8 销毁栈
//销毁void StackDestroy(stack* ps){assert(ps);free(ps->arr);ps->arr = NULL;ps->capacity = 0;ps->top = 0;}
2 队列的表示和实现
2.1队列的概念及结构
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头
2.2队列的实现
// 链式结构:表示队列typedef struct QListNode{struct QListNode* next;QDataType data;}QNode;// 队列的结构typedef struct Queue{QNode* head;QNode* tail;}Queue;// 初始化队列void QueueInit(Queue* pq);// 队尾入队列void QueuePush(Queue* pq, QDataType data);// 队头出队列void QueuePop(Queue* pq);// 获取队列头部元素QDataType QueueFront(Queue* pq);// 获取队列队尾元素QDataType QueueBack(Queue* pq);// 获取队列中有效元素个数int QueueSize(Queue* pq);// 检测队列是否为空,如果为空返回非零结果,如果非空返回0int QueueEmpty(Queue* pq);// 销毁队列void QueueDestroy(Queue* pq);
2.2.1初始化队列
//初始化void QueueInit(Queue* pq){assert(pq);pq->head = NULL;pq->tail = NULL;}
2.2.2 队尾入队列
//队尾入void QueuePush(Queue* pq, QDataType x){assert(pq);QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){printf("malloc fail\n");exit(-1);}newnode->data = x;newnode->next = NULL;if (pq->tail == NULL){pq->tail = newnode;pq->head = newnode;}else{pq->tail->next = newnode;pq->tail = newnode;}}
2.2.3 队头出队列
//队头出void QueuePop(Queue* pq){//1.一个//2.多个assert(pq);assert(pq->head);if (pq->head->next == NULL){free(pq->head);pq->head = pq->tail = NULL;}else{QNode* next = pq->head->next;free(pq->head);pq->head = next;}}
2.2.4 获取队列头部元素
//取队列的队头元素QDataType QueueFront(Queue* pq){assert(pq);assert(pq->head);return pq->head->data;}
2.2.5 获取队列队尾元素
//取队列的队尾元素QDataType QueueBack(Queue* pq){assert(pq);assert(pq->head);return pq->tail->data;}
2.2.6 获取队列有效元素个数
//返回队列长度int QueueSize(Queue* pq){assert(pq);int size = 0;QNode* cur = pq->head;while (!cur){size++;cur = cur->next;}return size;}
2.2.7 判空
//判空bool QueueEmpty(Queue* pq){assert(pq);return pq->head == NULL;}
2.2.8 销毁队列
//销毁队列void QueueDestroy(Queue* pq){assert(pq);QNode* cur = pq->head;while (cur){QNode* next = cur->next;free(cur);cur = next;}pq->head = pq->tail = NULL;}