数据结构(初阶)——栈和队列

目录

一、栈

1.1栈的概念及结构

1.2栈的实现

二、队列

2.1队列的概念

2.2队列的实现

三、循环队列

3.1循环队列

3.2循环队列的实现 

四、两栈实现队列+两队列实现栈

4.1两栈实现队232. 用栈实现队列 - 力扣(LeetCode)

4.1两队列实现栈225. 用队列实现栈 - 力扣(LeetCode)

五、栈和队列小题


一、栈

1.1栈的概念及结构

栈:一种特殊的 线性表 ,其只允许在固定的一端进行插入和删除元素操作。 进行数据插入和删除操作的一端 称为 栈顶 ,另一端称为 栈底 栈中的数据元素遵守 后进先出 LIFO Last In First Out )的原则。
压栈:栈的插入操作叫做进栈 / 压栈 / 入栈, 入数据在栈顶
出栈:栈的删除操作叫做出栈。 出数据也在栈顶
数据结构(初阶)——栈和队列_第1张图片

1.2栈的实现

         数据结构(初阶)——栈和队列_第2张图片

//Stack.h
#pragma once
#include
#include
#include
#include

// 支持动态增长的栈
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);
//Stack.c
#define _CRT_SECURE_NO_WARNINGS 
#include"Stack.h"
// 初始化栈
void StackInit(Stack* ps) {
	assert(ps);
	ps->_a = NULL;
	ps->_capacity = 0;
	ps->_top = 0; //可以直接插入,指向下一个
	
}
// 销毁栈
void StackDestroy(Stack* ps) {
	assert(ps);
	free(ps->_a);
	ps->_a = NULL;
	ps->_capacity = ps->_top = 0;

}
// 入栈
void StackPush(Stack* ps, STDataType data) {
	assert(ps);
	if (ps->_capacity == ps->_top) {

		int newcapacity = ps->_capacity == 0 ? 4 : 2 * ps->_capacity;
		Stack* temp = (Stack*)realloc(ps->_a, sizeof(Stack) * newcapacity);
		if (!temp) {
			perror("realloc fail or malloc fail");
			exit(-1);
		}

		ps->_a = temp;
		ps->_capacity = newcapacity;
	}
	
	ps->_a[ps->_top] = data;
	ps->_top++;

}
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
int StackEmpty(Stack* ps) {
	assert(ps);
	return ps->_top == 0;
}

//检查栈是否已满
int StackFull(Stack* ps) {
	assert(ps);
	return ps->_capacity < ps->_top - 1 ? 0 : 1;
}

// 出栈
void StackPop(Stack* ps) {
	assert(ps);
	assert(!StackEmpty(ps));
	ps->_top--;
}

// 获取栈顶元素
STDataType StackTop(Stack* ps) {
	assert(ps);
	assert(!StackEmpty(ps));
	return ps->_a[ps->_top - 1];
}

// 获取栈中有效元素个数
int StackSize(Stack* ps) {
	assert(ps);
	return ps->_top;
}

二、队列

2.1队列的概念

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有 先进先出 FIFO(First In First Out) 入队列:进行插入操作的一端称为 队尾 出队列:进行删除操作的一端称为 队头
数据结构(初阶)——栈和队列_第3张图片

2.2队列的实现

 

//Queue.h
#pragma once
#include
#include
#include
#include
// 链式结构:表示队列 
typedef int QDataType;
typedef struct QListNode
{
	struct QListNode* _next;
	QDataType _data;
}QNode;

// 队列的结构 
typedef struct Queue
{
	QNode* _front;
	QNode* _rear;
}Queue;

// 初始化队列 
void QueueInit(Queue* q);
// 队尾入队列 
void QueuePush(Queue* q, QDataType data);
// 队头出队列 
void QueuePop(Queue* q);
// 获取队列头部元素 
QDataType QueueFront(Queue* q);
// 获取队列队尾元素 
QDataType QueueBack(Queue* q);
// 获取队列中有效元素个数 
int QueueSize(Queue* q);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
int QueueEmpty(Queue* q);
// 销毁队列 
void QueueDestroy(Queue* q);
//Queue.c
#define _CRT_SECURE_NO_WARNINGS 
#include"Queue.h"
// 初始化队列 
void QueueInit(Queue* q) {

	assert(q);
	q->_front = NULL;
	q->_rear = NULL;


}
// 队尾入队列 
void QueuePush(Queue* q, QDataType data) {
	assert(q);

	QNode* newcode = (QNode*)malloc(sizeof(QNode));
	if (newcode == NULL) {
		perror("malloc fail");
		exit(-1);
	}
	else {
		newcode->_data = data;
		newcode->_next = NULL;
	}

	if (q->_rear == NULL) {
		q->_front = q->_rear = newcode;
	}
	else {
		q->_rear->_next = newcode;
		q->_rear = newcode;
	}
	/*if (q->_rear == NULL) 
	{
		QNode* newcode = (QNode*)malloc(sizeof(QNode));
		if (newcode == NULL) {
			perror("malloc fail");
			exit(-1);
		}
		q->_rear = q->_front = newcode;
		newcode->_data = data;
		newcode->_next = NULL;
	}
	else 
	{

		QNode* newcode = (QNode*)malloc(sizeof(QNode));
		if (newcode == NULL) {
			perror("malloc fail");
			exit(-1);
		}

		q->_rear->_next = newcode;
		q->_rear = newcode;
		newcode->_data = data;
		newcode->_next = NULL;

	}*/
	

}
// 队头出队列 
void QueuePop(Queue* q) {
	assert(q);
	assert(!QueueEmpty(q));
	if (q->_front->_next==NULL) {
		q->_front = q->_rear = NULL;
	}
	else {
		QNode* del = q->_front;
		q->_front = q->_front->_next;

		free(del);
		del = NULL;
	}
	
}
// 获取队列头部元素 
QDataType QueueFront(Queue* q) {
	assert(q);
	assert(!QueueEmpty(q));
	return q->_front->_data;
}

// 销毁队列 
void QueueDestroy(Queue* q) {
	assert(q);

	QNode* cur = q->_front;
	while (cur) {

		QNode* del = cur;
		cur = cur->_next;
		free(del);

	}
	q->_front = q->_rear = NULL;
}
// 获取队列队尾元素 
QDataType QueueBack(Queue* q) {
	assert(q);
	assert(!QueueEmpty(q));
	return q->_rear->_data;
}
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
int QueueEmpty(Queue* q) {
	assert(q);
	return q->_rear == NULL && q->_front == NULL;

}
// 获取队列中有效元素个数 
int QueueSize(Queue* q) {
	assert(q);
	QNode* cur = q->_front;
	int sum = 0;
	while (cur) {
		sum++;
		cur = cur->_next;
	}
	return sum;
}

三、循环队列

3.1循环队列

实际中我们有时还会使用一种队列叫循环队列。如操作系统课程讲解生产者消费者模型

时可以就会使用循环队列。环形队列可以使用数组实现,也可以使用循环链表实现。

数据结构(初阶)——栈和队列_第4张图片

 注意:Q.rear指的是最后一个元素的下一个

当我们判断循环队列是否为空或者是否满时,发现Q.rear和Q.front相等,而且不能区分,所以,我们可以多开一个空间!

如果Q.front和Q.rear相等,就是空。如果Q.rear的下一个是Q.front就是满

3.2循环队列的实现 

 622. 设计循环队列 - 力扣(LeetCode)

#define _CRT_SECURE_NO_WARNINGS 

typedef struct {
    int* a;
    int front;
    int rear;
    int N;
} MyCircularQueue;



MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    obj->a = (int*)malloc(sizeof(int) * (k + 1));
    obj->rear = obj->front = 0;
    obj->N = k + 1;


    return obj;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {

    if ((obj->rear + 1) % obj->N == obj->front) {
        return true;
    }
    return false;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    if (obj->front == obj->rear) {
        return true;
    }
    return false;
}


bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if (myCircularQueueIsFull(obj)) {
        return false;
    }
    obj->a[obj->rear] = value;
    obj->rear++;
    obj->rear %= obj->N;
    return true;
}


bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if (myCircularQueueIsEmpty(obj)) {
        return false;
    }
    obj->front++;
    obj->front %= obj->N;
    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;
    }
    if (obj->rear == 0) {
        return obj->a[obj->N - 1];
    }
    return obj->a[obj->rear - 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.1两栈实现队232. 用栈实现队列 - 力扣(LeetCode)

 数据结构(初阶)——栈和队列_第5张图片

数据结构(初阶)——栈和队列_第6张图片

思路分析:

先 push 1 2 3 4 再 pop 

pop的时候,要将所有的pushST栈全部导入popST 

如果再push时再存到pushST

#define _CRT_SECURE_NO_WARNINGS 

#include
#include
#include
#include
#include
// 支持动态增长的栈
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);
// 初始化栈
void StackInit(Stack* ps) {
	assert(ps);
	ps->_a = NULL;
	ps->_capacity = 0;
	ps->_top = 0; //可以直接插入,指向下一个

}
// 销毁栈
void StackDestroy(Stack* ps) {
	assert(ps);
	free(ps->_a);
	ps->_a = NULL;
	ps->_capacity = ps->_top = 0;

}
// 入栈
void StackPush(Stack* ps, STDataType data) {
	assert(ps);
	if (ps->_capacity == ps->_top) {

		int newcapacity = ps->_capacity == 0 ? 4 : 2 * ps->_capacity;
		Stack* temp = (Stack*)realloc(ps->_a, sizeof(Stack) * newcapacity);
		if (!temp) {
			perror("realloc fail or malloc fail");
			exit(-1);
		}

		ps->_a = temp;
		ps->_capacity = newcapacity;
	}

	ps->_a[ps->_top] = data;
	ps->_top++;

}
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
int StackEmpty(Stack* ps) {
	assert(ps);
	return ps->_top == 0;
}

//检查栈是否已满
int StackFull(Stack* ps) {
	assert(ps);
	return ps->_capacity < ps->_top - 1 ? 0 : 1;
}

// 出栈
void StackPop(Stack* ps) {
	assert(ps);
	assert(!StackEmpty(ps));
	ps->_top--;
}

// 获取栈顶元素
STDataType StackTop(Stack* ps) {
	assert(ps);
	assert(!StackEmpty(ps));
	return ps->_a[ps->_top - 1];
}

// 获取栈中有效元素个数
int StackSize(Stack* ps) {
	assert(ps);
	return ps->_top;
}


typedef struct {
	Stack pushST;
	Stack popST;
} MyQueue;


MyQueue* myQueueCreate() {
	MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
	StackInit(&obj->pushST);
	StackInit(&obj->popST);
	return obj;
}

void myQueuePush(MyQueue* obj, int x) {

	StackPush(&obj->pushST, x);

}
void pushSTtopopST(Stack* popST, Stack* pushST) {
	while (StackSize(pushST)) {
		StackPush(popST, StackTop(pushST));
		StackPop(pushST);
	}
}

int myQueuePop(MyQueue* obj) {
	int top;
	if (!StackEmpty(&obj->popST)) {
		top = StackTop(&obj->popST);
		StackPop(&obj->popST);
	}
	else {
		pushSTtopopST(&obj->popST, &obj->pushST);
		top = StackTop(&obj->popST);
		StackPop(&obj->popST);
	}
	return top;
}

int myQueuePeek(MyQueue* obj) {
	if (!StackEmpty(&obj->popST)) {
		return StackTop(&obj->popST);
	}
	else {
		pushSTtopopST(&obj->popST, &obj->pushST);
		return StackTop(&obj->popST);
	}
}

bool myQueueEmpty(MyQueue* obj) {
	if (StackEmpty(&obj->popST) && StackEmpty(&obj->pushST)) {
		return true;
	}
	return false;
}

void myQueueFree(MyQueue* obj) {
	StackDestroy(&obj->popST);
	StackDestroy(&obj->pushST);
	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);
*/

4.1两队列实现栈225. 用队列实现栈 - 力扣(LeetCode)

 数据结构(初阶)——栈和队列_第7张图片

 思路分析:

两个队列倒数据,当push时,push到有数据的队列,pop时,把有数据的队列倒入无数据的队列,只留下最后一个,这时候再pop一次就可以了。

#define _CRT_SECURE_NO_WARNINGS 
#include
#include
#include
#include
#include
// 链式结构:表示队列 
typedef int QDataType;
typedef struct QListNode
{
    struct QListNode* _next;
    QDataType _data;
}QNode;

// 队列的结构 
typedef struct Queue
{
    QNode* _front;
    QNode* _rear;
}Queue;

// 初始化队列 
void QueueInit(Queue* q);
// 队尾入队列 
void QueuePush(Queue* q, QDataType data);
// 队头出队列 
void QueuePop(Queue* q);
// 获取队列头部元素 
QDataType QueueFront(Queue* q);
// 获取队列队尾元素 
QDataType QueueBack(Queue* q);
// 获取队列中有效元素个数 
int QueueSize(Queue* q);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
int QueueEmpty(Queue* q);
// 销毁队列 
void QueueDestroy(Queue* q);

// 初始化队列 
void QueueInit(Queue* q) {

    assert(q);
    q->_front = NULL;
    q->_rear = NULL;


}
// 队尾入队列 
void QueuePush(Queue* q, QDataType data) {
    assert(q);

    QNode* newcode = (QNode*)malloc(sizeof(QNode));
    if (newcode == NULL) {
        perror("malloc fail");
        exit(-1);
    }
    else {
        newcode->_data = data;
        newcode->_next = NULL;
    }

    if (q->_rear == NULL) {
        q->_front = q->_rear = newcode;
    }
    else {
        q->_rear->_next = newcode;
        q->_rear = newcode;
    }

}
// 队头出队列 
void QueuePop(Queue* q) {
    assert(q);
    assert(!QueueEmpty(q));
    if (q->_front->_next == NULL) {
        q->_front = q->_rear = NULL;
    }
    else {
        QNode* del = q->_front;
        q->_front = q->_front->_next;

        free(del);
        del = NULL;
    }

}
// 获取队列头部元素 
QDataType QueueFront(Queue* q) {
    assert(q);
    assert(!QueueEmpty(q));
    return q->_front->_data;
}

// 销毁队列 
void QueueDestroy(Queue* q) {
    assert(q);

    QNode* cur = q->_front;
    while (cur) {

        QNode* del = cur;
        cur = cur->_next;
        free(del);

    }
    q->_front = q->_rear = NULL;
}
// 获取队列队尾元素 
QDataType QueueBack(Queue* q) {
    assert(q);
    assert(!QueueEmpty(q));
    return q->_rear->_data;
}
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
int QueueEmpty(Queue* q) {
    assert(q);
    return q->_rear == NULL && q->_front == NULL;

}
// 获取队列中有效元素个数 
int QueueSize(Queue* q) {
    assert(q);
    QNode* cur = q->_front;
    int sum = 0;
    while (cur) {
        sum++;
        cur = cur->_next;
    }
    return sum;
}
typedef struct {
    Queue p1;
    Queue p2;
} MyStack;


MyStack* myStackCreate() {
    MyStack* obj = (MyStack*)malloc(sizeof(MyStack));
    QueueInit(&obj->p1);
    QueueInit(&obj->p2);
    return obj;
}

void myStackPush(MyStack* obj, int x) {
    if (!QueueEmpty(&obj->p1))
    {
        QueuePush(&obj->p1, x);

    }
    else
    {
        QueuePush(&obj->p2, x);
    }

}

int myStackPop(MyStack* obj) {
    int top;
    /*
    Queue* empty = &obj->p1;
    Queue* UNempty = &obj->p2;
    if(!QueueEmpty(&obj->p1)){
        empty = &obj->p2;
        UNempty = &obj->p1;
    }
    while(QueueSize(UNempty)>1){
        QueuePush(empty,QueueFront(UNempty));
        QueuePop(UNempty);
    }
    top = QueueFront(UNempty);
    QueuePop(UNempty);
    */
    if (!QueueEmpty(&obj->p1)) {
        while (QueueSize(&obj->p1) > 1)
        {
            QueuePush(&obj->p2, QueueFront(&obj->p1));
            QueuePop(&obj->p1);
        }
        top = QueueFront(&obj->p1);
        QueuePop(&obj->p1);
    }
    else {
        while (QueueSize(&obj->p2) > 1)
        {
            QueuePush(&obj->p1, QueueFront(&obj->p2));
            QueuePop(&obj->p2);
        }
        top = QueueFront(&obj->p2);
        QueuePop(&obj->p2);

    }
    return top;
}

int myStackTop(MyStack* obj) {
    if (!QueueEmpty(&obj->p1))
    {
        return QueueBack(&obj->p1);

    }
    else
    {
        return QueueBack(&obj->p2);

    }
}

bool myStackEmpty(MyStack* obj) {
    if (QueueEmpty(&obj->p1) && QueueEmpty(&obj->p2)) {
        return true;
    }

    return false;
}

void myStackFree(MyStack* obj) {
    QueueDestroy(&obj->p1);
    QueueDestroy(&obj->p2);
    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);
*/

五、栈和队列小题

1. 括号匹配问题。 力扣
2. 用队列实现栈。 力扣
3. 用栈实现队列。 力扣
4. 设计循环队列。 力扣

你可能感兴趣的:(数据结构)