1.栈
目录
1.1栈的概念及结构
栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据也在栈顶。
1.2栈的实现
栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小。
Stack.h文件
#define _CRT_SECURE_NO_WARNINGS
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
#include<stdio.h>
//对结构体进行定义
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;
}ST;
void STInit(ST* pst);//栈初始化
void STDestroy(ST* pst);//栈销毁
void STPush(ST* pst,STDataType x);//入栈
void STPop(ST* pst);//出栈
bool STEmpty(ST* pst);//判断栈是否为空
int STSize(ST* pst); //判断栈的大小
STDataType STTop(ST* pst);//取栈顶元素
Stack.c
#include"Stack.h"
void STInit(ST* pst)
{
assert(pst);
pst->a = NULL;
//pst->top = -1; //top指向栈顶数据
pst->top = 0; //top指向栈顶数据的下一个位置
pst->capacity = 0;
}
void STDestroy(ST* pst)
{
assert(pst);
free(pst->a);
pst->a = NULL;
pst->top = pst->capacity = 0;
}
void STPush(ST* pst, STDataType x)
{
if (pst->top == pst->capacity)
{
int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
STDataType* tmp = (STDataType*)realloc(pst->a, newcapacity * sizeof(STDataType));
if (tmp == NULL)
{
perror("realloc fail");
return;
}
pst->a = tmp;
pst->capacity = newcapacity;
}
pst->a[pst->top] = x;
pst->top++;
}
void STPop(ST* pst)
{
assert(pst);
assert(!STEmpty(pst));
pst->top--;
}
bool STEmpty(ST* pst)
{
assert(pst);
return pst->top == 0;
}
int STSize(ST* pst)
{
assert(pst);
return pst->top;
}
STDataType STTop(ST* pst)
{
assert(pst);
assert(!STEmpty(pst));
return pst->a[pst->top - 1];
}
注意:栈不要写打印函数,因为如果在函数在遍历一遍栈打印并不符合栈后进先出的特点,需要打印时只需根据栈的特点进行打印,打印完一个元素就出栈。
while(!STEmpty(&stack))
{
printf("%d ",STTop(&stack));
STPop(&stack);
}
比如:
void stack_test1()
{
ST stack;
STInit(&stack);
STPush(&stack, 1);
STPush(&stack, 2);
STPush(&stack, 3);
STPush(&stack, 4);
while (!STEmpty(&stack))
{
printf("%d,", STTop(&stack));
STPop(&stack);
}
STDestroy(&stack);
}
int main()
{
stack_test1();
return 0;
}
2.队列
2.1队列的概念及结构
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)的特点。
入队列:进行插入操作的一端称为队尾
出队列:进行删除操作的一端称为队头
如果:入队列:1 2 3 4 那么,出队列:1 2 3 4
DFS——深度优先遍历——递归/栈实现非递归
BFS——广度优先遍历——队列
2.2队列的实现
队列也可以数组和链表的结构实现,使用链表的结构实现更优一些。
数组的尾插效率可以,但数组的头删效率较低,而链表尾插和头删效率都比较高。
Queue.h
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
#include<stdio.h>
typedef int QdataType;
//定义两个结构体,一个表示队列的结点的结构,一个表示队列的结构
typedef struct QueueNode
{
struct QueueNode* next;
QdataType data;
}QNode;
typedef struct Queue
{
QNode* phead;
QNode* ptail;
int size;//方便读取数据,避免每次遍历
}Queue;
void QueueInit(Queue* pq);//初始化
void QueueDestroy(Queue* pq);//销毁
void QueuePush(Queue* pq,QdataType x);//尾插
void QueuePop(Queue* pq);//头删
QdataType QueueFront(Queue* pq);//取队列头元素
QdataType QueueBack(Queue* pq);//取队列尾元素
int QueueSize(Queue* pq);//队列长度
bool QueueEmpty(Queue* pq);//判断队列是否为空
Queue.c
#include"Queue.h"
void QueueInit(Queue* pq)
{
assert(pq);
pq->phead = pq->ptail = NULL;
pq->size = 0;
}
void QueueDestroy(Queue* pq)
{
assert(pq);
QNode* cur = pq->phead;
while (cur)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
pq->phead = pq->ptail = NULL;
pq->size = 0;
}
void QueuePush(Queue* pq, QdataType x)
{
assert(pq);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
perror("malloc fail");
return;
}
newnode->data = x;
newnode->next = NULL;
if (pq->ptail == NULL)//如果队列为空
{
assert(pq->phead == NULL);//避免ptail和phead不一致
pq->phead = pq->ptail = newnode;
}
else
{
pq->ptail->next = newnode;
pq->ptail = newnode;
}
pq->size++;
}
void QueuePop(Queue* pq)
{
assert(pq);
assert(pq->phead);//Pop不能为空
if (pq->phead->next == NULL)//只有一个节点
{
free(pq->phead);
pq->phead = pq->ptail = NULL;
}
else//多个节点
{
QNode* next = pq->phead->next;
free(pq->phead);
pq->phead = next;//如果是单节点,此时ptail是野指针,所以需要单独处理单节点情况
}
pq->size--;
}
QdataType QueueFront(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->phead->data;
}
QdataType QueueBack(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->ptail->data;
}
int QueueSize(Queue* pq)
{
assert(pq);
return pq->size;
}
bool QueueEmpty(Queue* pq)
{
assert(pq);
/*return pq->phead == NULL
&& pq->ptail == NULL;*/
return pq->size == 0;
}
3.例题
1.用队列实现栈
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
#include<stdio.h>
typedef int QdataType;
// 定义两个结构体,一个表示队列的结点的结构,一个表示队列的结构
typedef struct QueueNode
{
struct QueueNode* next;
QdataType data;
}QNode;
typedef struct Queue
{
QNode* phead;
QNode* ptail;
int size;//方便读取数据,避免每次遍历
}Queue;
bool QueueEmpty(Queue* pq)
{
assert(pq);
/*return pq->phead == NULL
&& pq->ptail == NULL;*/
return pq->size == 0;
}
void QueueInit(Queue* pq)
{
assert(pq);
pq->phead = pq->ptail = NULL;
pq->size = 0;
}
void QueueDestroy(Queue* pq)
{
assert(pq);
QNode* cur = pq->phead;
while (cur)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
pq->phead = pq->ptail = NULL;
pq->size = 0;
}
void QueuePush(Queue* pq, QdataType x)
{
assert(pq);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
perror("malloc fail");
return;
}
newnode->data = x;
newnode->next = NULL;
if (pq->ptail == NULL)//如果队列为空
{
assert(pq->phead == NULL);//避免ptail和phead不一致
pq->phead = pq->ptail = newnode;
}
else
{
pq->ptail->next = newnode;
pq->ptail = newnode;
}
pq->size++;
}
void QueuePop(Queue* pq)
{
assert(pq);
assert(pq->phead);//Pop不能为空
if (pq->phead->next == NULL)//只有一个节点
{
free(pq->phead);
pq->phead = pq->ptail = NULL;
}
else//多个节点
{
QNode* next = pq->phead->next;
free(pq->phead);
pq->phead = next;//如果是单节点,此时ptail是野指针,所以需要单独处理单节点情况
}
pq->size--;
}
QdataType QueueFront(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->phead->data;
}
QdataType QueueBack(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->ptail->data;
}
int QueueSize(Queue* pq)
{
assert(pq);
return pq->size;
}
typedef struct {
Queue q1;
Queue q2;
} MyStack;
MyStack* myStackCreate() {
MyStack* s = (MyStack*)malloc(sizeof(MyStack));
if(s == NULL)
{
perror("malloc fail");
return;
}
QueueInit(&s->q1);
QueueInit(&s->q2);
return s;
}
void myStackPush(MyStack* obj, int x) {
if(!QueueEmpty(&obj->q1))
{
QueuePush(&obj->q1,x);
}
else
{
QueuePush(&obj->q2,x);
}
}
int myStackPop(MyStack* obj) {
Queue* NoEmptyQueue = &obj->q1;
Queue* EmptyQueue = &obj->q2;
if(QueueEmpty(&obj->q1))
{
EmptyQueue = &obj->q1;
NoEmptyQueue = &obj->q2;
}
while(QueueSize(NoEmptyQueue)>1)
{
QueuePush(EmptyQueue,QueueFront(NoEmptyQueue));
QueuePop(NoEmptyQueue);
}
int val = QueueFront(NoEmptyQueue);
QueuePop(NoEmptyQueue);
return val;
}
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) {
QueueDestroy(&obj->q1);
QueueDestroy(&obj->q2);
free(obj);
}
/**
* Your MyStack struct will be instantiated and called as such:
* MyStack* obj = myStackCreate();
* myStackPush(obj, x);
* int param_2 = myStackPop(obj);
* int param_3 = myStackTop(obj);
* bool param_4 = myStackEmpty(obj);
* myStackFree(obj);
*/
2.用栈实现队列
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
#include<stdio.h>
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;
}ST;
void STInit(ST* pst)
{
assert(pst);
pst->a = NULL;
//pst->top = -1; //top指向栈顶数据
pst->top = 0; //top指向栈顶数据的下一个位置
pst->capacity = 0;
}
void STDestroy(ST* pst)
{
assert(pst);
free(pst->a);
pst->a = NULL;
pst->top = pst->capacity = 0;
}
void STPush(ST* pst, STDataType x)
{
if (pst->top == pst->capacity)
{
int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
STDataType* tmp = (STDataType*)realloc(pst->a, newcapacity * sizeof(STDataType));
if (tmp == NULL)
{
perror("realloc fail");
return;
}
pst->a = tmp;
pst->capacity = newcapacity;
}
pst->a[pst->top] = x;
pst->top++;
}
bool STEmpty(ST* pst)
{
assert(pst);
return pst->top == 0;
}
void STPop(ST* pst)
{
assert(pst);
assert(!STEmpty(pst));
pst->top--;
}
int STSize(ST* pst)
{
assert(pst);
return pst->top;
}
STDataType STTop(ST* pst)
{
assert(pst);
assert(!STEmpty(pst));
return pst->a[pst->top - 1];
}
typedef struct {
ST pushst;
ST popst;
} MyQueue;
MyQueue* myQueueCreate() {
MyQueue* q = (MyQueue*)malloc(sizeof(MyQueue));
if(q == NULL)
{
perror("malloc fail");
return NULL;
}
STInit(&q->pushst);
STInit(&q->popst);
return q;
}
void myQueuePush(MyQueue* obj, int x) {
STPush(&obj->pushst,x);
}
int myQueuePeek(MyQueue* obj) {
if(STEmpty(&obj->popst))
{
while(!STEmpty(&obj->pushst))
{
STPush(&obj->popst,STTop(&obj->pushst));
STPop(&obj->pushst);
}
}
return STTop(&obj->popst);
}
int myQueuePop(MyQueue* obj) {
int val = myQueuePeek(obj);
STPop(&obj->popst);
return val;
}
bool myQueueEmpty(MyQueue* obj) {
return STEmpty(&obj->pushst) && STEmpty(&obj->popst);
}
void myQueueFree(MyQueue* obj) {
STDestroy(&obj->pushst);
STDestroy(&obj->popst);
free(obj);
}
/**
* Your MyQueue struct will be instantiated and called as such:
* MyQueue* obj = myQueueCreate();
* myQueuePush(obj, x);
* int param_2 = myQueuePop(obj);
* int param_3 = myQueuePeek(obj);
* bool param_4 = myQueueEmpty(obj);
* myQueueFree(obj);
*/
3.环形队列
typedef struct {
int* a;
int front;
int rear;
int k;
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* obj =(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
obj->a = (int*)malloc(sizeof(int)*(k+1));
obj->front = 0;
obj->rear = 0;
obj->k = k;
return obj;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
return obj->rear == obj->front;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {
return (obj->rear+1)%(obj->k+1) == obj->front;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
if(myCircularQueueIsFull(obj))
return false;
obj->a[obj->rear] = value;
obj->rear++;
obj->rear %= (obj->k+1);
return true;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return false;
obj->front++;
obj->front %= (obj->k+1);
return true;
}
int myCircularQueueFront(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return -1;
return obj->a[obj->front];
}
int myCircularQueueRear(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return -1;
return obj->a[(obj->rear+obj->k) % (obj->k+1)];
}
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->a);
free(obj);
}
/**
* Your MyCircularQueue struct will be instantiated and called as such:
* MyCircularQueue* obj = myCircularQueueCreate(k);
* bool param_1 = myCircularQueueEnQueue(obj, value);
* bool param_2 = myCircularQueueDeQueue(obj);
* int param_3 = myCircularQueueFront(obj);
* int param_4 = myCircularQueueRear(obj);
* bool param_5 = myCircularQueueIsEmpty(obj);
* bool param_6 = myCircularQueueIsFull(obj);
* myCircularQueueFree(obj);
*/
4.有效的括号
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
#include<stdio.h>
typedef char STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;
}ST;
void STInit(ST* pst);
void STDestroy(ST* pst);
void STPush(ST* pst,STDataType x);
void STPop(ST* pst);
bool STEmpty(ST* pst);
int STSize(ST* pst);
STDataType STTop(ST* pst);
void STInit(ST* pst)
{
assert(pst);
pst->a = NULL;
//pst->top = -1; //top指向栈顶数据
pst->top = 0; //top指向栈顶数据的下一个位置
pst->capacity = 0;
}
void STDestroy(ST* pst)
{
assert(pst);
free(pst->a);
pst->a = NULL;
pst->top = pst->capacity = 0;
}
void STPush(ST* pst, STDataType x)
{
if (pst->top == pst->capacity)
{
int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
STDataType* tmp = (STDataType*)realloc(pst->a, newcapacity * sizeof(STDataType));
if (tmp == NULL)
{
perror("realloc fail");
return;
}
pst->a = tmp;
pst->capacity = newcapacity;
}
pst->a[pst->top] = x;
pst->top++;
}
void STPop(ST* pst)
{
assert(pst);
assert(!STEmpty(pst));
pst->top--;
}
bool STEmpty(ST* pst)
{
assert(pst);
return pst->top == 0;
}
int STSize(ST* pst)
{
assert(pst);
return pst->top;
}
STDataType STTop(ST* pst)
{
assert(pst);
assert(!STEmpty(pst));
return pst->a[pst->top - 1];
}
bool isValid(char * s){
ST stack;
STInit(&stack);
while(*s)
{
if(*s == '(' ||
*s == '['||
*s == '{')
{
STPush(&stack,*s);
s++;
}
else
{
if(STEmpty(&stack)) return 0;
if(STTop(&stack) == '('&& *s == ')' ||
STTop(&stack) == '['&& *s == ']'||
STTop(&stack) == '{'&& *s == '}' )
{
s++;
STPop(&stack);
}
else
return 0;
}
}
if(STEmpty(&stack))
return 1;
else
return 0;
}
4.概念选择题
1.一个栈的初始状态为空。现将元素1、2、3、4、5、A、B、C、D、E依次入栈,然后再依次出栈,则元素出
栈的顺序是( )。
A 12345ABCDE
B EDCBA54321
C ABCDE12345
D 54321EDCBA
2.若进栈序列为 1,2,3,4 ,进栈过程中可以出栈,则下列不可能的一个出栈序列是()
A 1,4,3,2
B 2,3,4,1
C 3,1,4,2
D 3,4,2,1
3.循环队列的存储空间为 Q(1:100) ,初始状态为 front=rear=100 。经过一系列正常的入队与退队操作后, front=rear=99 ,则循环队列中的元素个数为( )
A 1
B 2
C 99
D 0或者100
4.以下( )不是队列的基本运算?
A 从队尾插入一个新元素
B 从队列中删除第i个元素
C 判断一个队列是否为空
D 读取队头元素的值
5.现有一循环队列,其队头指针为front,队尾指针为rear;循环队列长度为N。其队内有效长度为?(假设
队头不存放数据)
A (rear - front + N) % N + 1
B (rear - front + N) % N
C ear - front) % (N + 1)
D (rear - front + N) % (N - 1)
1.B
2.C
3.D
4.B
5.B