c语言数据结构之栈和队列
文章目录
1.栈的表示和实现
1.1 栈的概念及结构
栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除
操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)
的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据也在栈顶。
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/668aeef0131b40c1b7d7ff0c3d870b21.png pic_center
)1.2 栈的实现
栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上
插入数据的代价比较小。
链式表:
如果用尾做栈顶,尾插尾删,要设计成双向链表,否则删除数据效率低.
如果用头做栈顶,头插头删,就可以设计成单链表。1.3 代码实现
// 支持动态增长的栈 typedef int STDataType; typedef struct Stack { STDataType* _a; 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); // 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 int StackEmpty(Stack* ps); // 销毁栈 void StackDestroy(Stack* ps);
2.队列的表示和实现
2.1 队列的概念及结构
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先
进先出FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一
端称为队头
2.2 队列的实现
队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,
出队列在数组头上出数据,效率会比较低。
2.3 代码实现
typedef int QDataType; // 链式结构:表示队列 typedef struct QueueNode { struct QListNode* next; QDataType data; }QNode; // 队列的结构 typedef struct Queue { QNode* head; // 头部 QNode* tail; // 尾部 }Queue; // 初始化队列 void QueueInit(Queue* pq); // 队尾入队列 void QueuePush(Queue* pq, QDataType x); // 队头出队列 void QueuePop(Queue* pq);
3.栈和队列相关的题
3.1 用队列实现栈
问题:
解决问题思路:
- 首先明白栈是后进先出,队列是先进先出。
- 有两个队列,入数据时,往不为空的队列入,保持另一个队列为空。
- 出数据的时候,依次出队头的数据,转移到另一个队列保存。当本来不为空的队列只剩一个数据时,Pop掉。
代码代码实现:
// 用队列实现栈 typedef struct { Queue q1; Queue q2; } MyStack; MyStack* myStackCreate() { MyStack* st = (MyStack*)malloc(sizeof(MyStack)); QueuInit(&st->q1); QueueInit(&st->q2); return st; } void myStackPush(MyStack* obj, int x) { if (!QueueEmpty(&obj->q1)) // 判断是否为空队列 { QueuePush(&obj->q1, x); // 往不为空的队列插入数据 } else { QueuePush(&obj->q2, x); } } int myStackPop(MyStack* obj) { Queue* emptyQ = &obj->q1; // 假设q1为空队列 Queue* nonemptyQ = &obj->q2; if (!QueueEmpty(&obj->q1)) // 假设不成立时在重新赋值 { emptyQ = &obj->q2; nonemptyQ = &obj->q1; } while (QueueSize(nonemptyQ) > 1) { QueuePush(emptyQ, QueueFront(nonemptyQ)); QueuePop(nonemptyQ); } int top = QueueFront(nonemptyQ); QueueDestory(nonemptyQ); return top; } int myStackTop(MyStack* obj) { if (!QueueEmpty(&obj->q1)) { return QueueBack(&obj->q1); } else { return QueueBack(&obj->q2); } } bool myStackEmpty(MyStack* obj) { return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2); } void myStackFree(MyStack* obj) { QueueDestory(&obj->q1); QueueDestory(&obj->q2); free(obj); }
3.2 用栈实现队列
问题:
解决问题思路:
- 首先明白栈是后进先出,队列是先进先出。
- 两个栈一个是pushST(存放数据),一个是popST来删除数据,把pushST栈中的数据全部移入到popST栈,就可以实现队列先进先出的删除了。同时返回popST中的栈顶数据。
*实现peek函数, 如果popST栈中有数据返回popST中栈顶数据,如果没数据将pushST栈中的数据全部放到popST栈中后,再返回popST栈中栈顶的数据。代码实现:
typedef struct { ST pushST; ST popST; }MyQueue; MyQueue* myQueueCreate() { MyQueue* q = (MyQueue*)malloc(sizeof(MyQueue)); StackInit(&q->popST); StackInit(&q->pushST); return q; } void myQueuePush(MyQueue* obj, int x) { StackPush(&obj->pushST,x); } int myQueuePop(MyQueue* obj) { if (StackEmpty(&obj->popST)) //如果popst中没有数>据,将pushst的数据导过去。 { while (!StackEmpty(&obj->pushST)) { StackPush(&obj->popST, StackTop(&obj->pushST)); StackPop(&obj->pushST); } } int front = StackTop(&obj->popST); StackPop(&obj->pushST); return front; } int myQueuePeek(MyQueue* obj) { if (StackEmpty(&obj->popST)) //如果popst中没有数>据,将pushst的数据导过去。 { while (!StackEmpty(&obj->pushST)) { StackPush(&obj->popST, StackTop(&obj->pushST)); StackPop(&obj->pushST); } } return StackTop(&obj->popST); } bool myQueueEmpty(MyQueue* obj) { return StackEmpty(&obj->popST) && >StackEmpty(&obj->pushST); } void myQueueFree(MyQueue* obj) { StackDestory(&obj->popST); StackDestory(&obj->pushST); free(obj); }
最后,这是我在学习c语言数据结构之栈和队列时的笔记,如果有错误的地方希望大家指正。大家一起努力!