c语言——栈和队列

1.栈

1.1栈的概念及结构

1.1.1概念

:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(LastInFirstOut)的则。
压栈 :栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据也在栈顶。

1.1.2结构

数组栈


链式栈

如果用尾做栈顶,尾插尾删,要设计成双向链表,否则删除数据效率低

如果用头做栈顶,头插头删,就可以设计成单链表

两种都可以,非要选一种,数组栈结构稍微好一点。

1.2接口函数

cpp 复制代码
//要改变结构体的内容
//传结构体的指针
void StackInit(ST* ps);
void StackDestory(ST* ps);
void StackPush(ST* ps,STDataType x);
void StackPop(ST* ps);
STDataType StackTop(ST* ps);
//取栈顶的数据
int StackSize(ST* ps);
//栈中元素个数
bool StackEmpty(ST* ps);
//判断栈是否为空

1.3详细代码

cpp 复制代码
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

typedef int STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;//栈顶
	int capacity;
}ST;

void StackInit(ST* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->top = 0;
	//初始化时,top给的是0,
	// 意味着top指向栈顶数据的下一个
	// ps->top=-1;
	//初始化时,top给的是 - 1,
	// 意味着top指向栈顶数据
	ps->capacity = 0;
}

void StackDestory(ST* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->top = 0;
	ps->capacity = 0;
}

void StackPush(ST* ps, STDataType x)
{
	assert(ps);
	if (ps->top == ps->capacity)
	{
		int newCapacity = ps->capacity ==\
         0 ? 4 : ps->capacity * 2;
		STDataType* tmp = (STDataType*)\
        realloc(ps->a, sizeof(STDataType) * newCapacity);
		if (tmp == NULL)
		{
			printf("realloc fail\n");
			exit(-1);
		}
		ps->a = tmp;
		ps->capacity = newCapacity;
	}
	ps->a[ps->top] = x;
	ps->top++;
}

void StackPop(ST* ps)
{
	assert(ps);
	assert(ps->top > 0);
	//栈不为空才能删
	ps->top--;
}

STDataType StackTop(ST* ps)
{
	assert(ps);
	assert(ps->top > 0);
	//栈不为空才能取栈顶元素
	return ps->a[ps->top - 1];
}

int StackSize(ST* ps)
{
	assert(ps);
	return ps->top;
}

bool StackEmpty(ST* ps)
{
	assert(ps);
	/*
	if (ps->top == 0)
		return true;
	else
		return false;
	*/
	return ps->top == 0;
}

void TestStack()
{
	ST st;
	StackInit(&st);
	StackPush(&st, 1);
	StackPush(&st, 2);
	StackPush(&st, 3);
	StackPush(&st, 4);
	
	//遍历栈中的数据
	while (!StackEmpty(&st))
	{
		printf("%d ", StackTop(&st));
		StackPop(&st);
	}

	StackDestory(&st);
}

int main()
{
	TestStack();
	return 0;
}

1.4例题:有效括号

给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。
cpp 复制代码
bool isValid(char* s) 
{
    struct Stack st;
    Init(&st);
    while(*s)
    {
        //左括号入栈
        if(*s=='(' || *s=='[' || *s=='{')
        {
            Push(&st,*s);
            s++;
        }
        //剩下的都是右括号
        else
        {
            //如果没有左括号和剩下的右括号匹配
            //就不是有效括号
            if(isEmpty(&st))
                return false;
            //取出栈顶的左括号
            char top=GetTop(&st);
            Pop(&st);
            //如果左括号和右括号不匹配
            //就不是有效括号
            if((top=='(' && *s!=')')||
                (top=='[' && *s!=']')||
                (top=='{' && *s!='}'))
            {
                Destory(&st);
                return false;
            }
            //匹配了就往后继续判断
            else
                s++;
        }
    }
    //如果列表的左括号和右括号都能匹配上
    //则执行完while循环后,栈为空
    if(isEmpty(&st))
        return true;
    Destory(&st);
    return false;
}

2.队列

2.1队列的概念及结构

队列: 只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)
入队列: 进行插入操作的一端称为队尾
**出队列:**进行删除操作的一端称为队头

2.2队列的实现

队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。

2.2.1接口函数

cpp 复制代码
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);
2.2.1.1定义队列
cpp 复制代码
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

typedef int QDataType;

//这是单链表,要有节点
typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType data;
}QueueNode;

//为了方便尾插,除了有一个头指针,
//还要有一个尾指针
//所以定义一个结构体出来
typedef struct Queue
{
	QueueNode* head;
	QueueNode* tail;
}Queue;
2.2.1.2初始化队列
cpp 复制代码
//传结构体的指针,无需二级指针
void QueueInit(Queue* pq)
{
	assert(pq);
	pq->head = NULL;
	pq->tail = NULL;
}
2.2.1.3销毁队列
cpp 复制代码
void QueueDestory(Queue* pq)
{
	assert(pq);
	QueueNode* cur = pq->head;
	while (cur != NULL)
	{
		QueueNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = NULL;
	pq->head = NULL;
}
2.2.1.4队尾入
cpp 复制代码
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 == NULL)
	{
		pq->head = newnode;
		pq->tail = newnode;
	}
	//有节点就直接插入、链接
	else
	{
		//head		tail	newnode
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
}
2.2.1.5队头出
cpp 复制代码
void QueuePop(Queue* pq)
{
	assert(pq);
	//队列不能为空
	assert(pq->head);

	//如果只有一个节点
	if (pq->head->next == NULL)
	{
		free(pq->head);
		pq->head = NULL;
		pq->tail = NULL;
	}

	//先保存下一个
	QNode* next = pq->head->next;
	free(pq->head);
	pq->head = next;
}
2.2.1.6判断队列是否为空
cpp 复制代码
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->head == NULL;
}
2.2.1.7获取队头的数据
cpp 复制代码
QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(pq->head);
	return pq->head->data;
}
2.2.1.8获取队尾的数据
cpp 复制代码
QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(pq->head);
	return pq->tail->data;
}
2.2.1.9获取队列大小
cpp 复制代码
int QueueSize(Queue* pq)
{
	assert(pq);
	int size = 0;
	QNode* cur = pq->head;
	while (cur)
	{
		size++;
		cur = cur->next;
	}
	return size;
}
2.2.1.10销毁队列
cpp 复制代码
void QueueDestory(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->head;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = NULL;
	pq->tail = NULL;
}
2.2.1.11测试
cpp 复制代码
void Test()
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q, 1);
	QueuePush(&q, 2);
	QueuePush(&q, 3);
	QueuePush(&q, 4);
	QueuePop(&q);
	QueuePush(&q, 5);

	printf("size=%d\n", QueueSize(&q));
	printf("head=%d\n", QueueFront(&q));
	printf("tail=%d\n", QueueBack(&q));
	while (!QueueEmpty(&q))
	{
		printf("%d ", QueueFront(&q));
		QueuePop(&q);
	}

	QueueDestroy(&q);
}

3.测试

3.1用栈实现队列

cpp 复制代码
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int Type;
struct Stack
{
	int top;
	int capacity;
	Type* a;
};

void Init(struct Stack* st)
{
	assert(st);
	st->a = NULL;
	st->top = 0;
	st->capacity = 0;
}

void Push(struct Stack* st,Type x)
{
	int newCapacity = 4;
	if (st->top == st->capacity)
	{
		if (st->top != 0)
			newCapacity = st->capacity * 2;
		Type* tmp = (Type*)realloc(st->a,sizeof(Type)*newCapacity);
		if (tmp == NULL)
		{
			printf("realloc fail.\n");
			exit(-1);
		}
		st->a = tmp;
		st->capacity = newCapacity;
	}
	st->a[st->top] = x;
	st->top++;
}

void Pop(struct Stack* st)
{
	assert(st);
	assert(st->top > 0);
	st->top--;
}

Type Top(struct Stack* st)
{
	assert(st);
	assert(st->top > 0);
	return st->a[st->top - 1];
}

Type Peek(struct Stack* st)
{
	assert(st);
	assert(st->top > 0);
	return st->a[0];
}

bool isEmpty(struct Stack* st)
{
	assert(st);
	return st->top == 0;
}

int Size(struct  Stack* st)
{
	assert(st);
	return st->top;
}

void Destory(struct Stack* st)
{
	assert(st);
	free(st->a);
	st->capacity = 0;
	st->top = 0;
}

void Print(struct Stack* st)
{
	int i = 0;
	for (i = 0;i < st->top;i++)
		printf("%d ", st->a[i]);
	printf("\n");
}


typedef struct 
{
    struct Stack st1;
    struct Stack st2;
} MyQueue;


MyQueue* myQueueCreate() 
{
    MyQueue* q=(MyQueue*)malloc(sizeof(MyQueue));
    Init(&q->st1);
    Init(&q->st2);
    return q;
}

void myQueuePush(MyQueue* obj, int x) 
{
    Push(&obj->st1,x);
}

int myQueuePop(MyQueue* obj) 
{
    int top=0;
    int ret=Peek(&obj->st1);
    while(Size(&obj->st1)>1)
    {
        top=Top(&obj->st1);
        Push(&obj->st2,top);
        Pop(&obj->st1);
    }
    Pop(&obj->st1);
    while(Size(&obj->st2))
    {
        top=Top(&obj->st2);
        Push(&obj->st1,top);
        Pop(&obj->st2);
    }
    return ret;
}

int myQueuePeek(MyQueue* obj) 
{
    return Peek(&obj->st1);    
}

bool myQueueEmpty(MyQueue* obj) 
{
    return isEmpty(&obj->st1);
}

void myQueueFree(MyQueue* obj) 
{
    Destory(&obj->st1);
    Destory(&obj->st2);
}

3.2用队列实现栈

cpp 复制代码
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int Type;
struct QueueNode
{
	Type val;
	struct QueueNode* next;
};
struct Queue
{
	struct QueueNode* head;
	struct QueueNode* tail;
};

void Init(struct Queue* pq)
{
	assert(pq);
	pq->head = NULL;
	pq->tail = NULL;
}

void Push(struct Queue* pq, Type x)
{
	struct QueueNode* newnode = (struct QueueNode*)malloc(sizeof(struct QueueNode));
	if (newnode == NULL)
	{
		printf("malloc fail.\n");
		exit(-1);
	}
	newnode->val = x;
	newnode->next = NULL;
	if (pq->head == NULL)
	{
		pq->head = newnode;
		pq->tail = newnode;
		return;
	}
	pq->tail->next = newnode;
	pq->tail = newnode;
}

void Pop(struct Queue* pq)
{
	assert(pq);
	assert(pq->head);
	if (pq->head->next == NULL)
	{
		free(pq->head);
		pq->head = NULL;
		return;
	}
	struct QueueNode* nxt = pq->head->next;
	free(pq->head);
	pq->head = nxt;
}

Type Front(struct Queue* pq)
{
	assert(pq);
	assert(pq->head);
	return pq->head->val;
}

Type Back(struct Queue* pq)
{
	assert(pq);
	assert(pq->head);
	return pq->tail->val;
}

int Size(struct Queue* pq)
{
	assert(pq);
	struct QueueNode* cur = pq->head;
	int size = 0;
	while (cur)
	{
		size++;
		cur = cur->next;
	}
	return size;
}

bool isEmpty(struct Queue* pq)
{
	assert(pq);
	return pq->head == NULL;
}

void Destory(struct Queue* pq)
{
	assert(pq);
	struct QueueNode* cur = pq->head;
	while (cur)
	{
		struct QueueNode* nxt = cur->next;
		free(cur);
		cur = nxt;
	}
	pq->head = NULL;
	pq->tail = NULL;
}


typedef struct
{
	struct Queue q1;
	struct Queue q2;
} MyStack;


MyStack* myStackCreate()
{
	MyStack* st = (MyStack*)malloc(sizeof(MyStack));
	Init(&st->q1);
	Init(&st->q2);
	return st;
}

void myStackPush(MyStack* obj, int x)
{
	if (!isEmpty(&obj->q1))
		Push(&obj->q1,x);
	else
		Push(&obj->q2,x);
}

int myStackTop(MyStack* obj)
{
	if (!isEmpty(&obj->q1))
		return Back(&obj->q1);
	return Back(&obj->q2);
}

bool myStackEmpty(MyStack* obj)
{
	if (isEmpty(&obj->q1) && isEmpty(&obj->q2))
		return true;
	return false;
}

int myStackPop(MyStack* obj)
{
	if (myStackEmpty(obj))
		return -1;
	int top = 0;
    int ret=myStackTop(obj);
	if (!isEmpty(&obj->q1))
	{
		while (Size(&obj->q1)>1)
		{
            top =Front(&obj->q1);
			Pop(&obj->q1);
			Push(&obj->q2, top);
		}
		Pop(&obj->q1);
	}
	else if (!isEmpty(&obj->q2))
	{
		while (Size(&obj->q2)>1)
		{
            top = Front(&obj->q2);
			Pop(&obj->q2);
			Push(&obj->q1, top);
		}
		Pop(&obj->q2);
	}
	return ret;
}

void myStackFree(MyStack* obj)
{
	Destory(&obj->q1);
	Destory(&obj->q2);
    obj=NULL;
}

3.3设计循环队列

无论使用数组实现还是链表实现,都要多开一个空间。如果设计存k个数据的循环队列,就要开k+1个空间。否则无法实现判空和判满。

①数组实现

cpp 复制代码
typedef struct 
{
    int* a;
    int size;
    int head;
    int tail;
} MyCircularQueue;


MyCircularQueue* myCircularQueueCreate(int k) 
{
    MyCircularQueue* cq=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    cq->a=(int*)malloc(sizeof(int)*(k+1));
    cq->head=0;
    cq->tail=0;
    cq->size=k;
    return cq;
}

bool myCircularQueueIsEmpty(MyCircularQueue* obj) 
{
    return (obj->head==obj->tail);
}

bool myCircularQueueIsFull(MyCircularQueue* obj) 
{
    if(obj->head==0 && obj->tail+obj->head==obj->size)
        return true;
    if(obj->tail<obj->head && obj->tail+1==obj->head)
        return true;
    return false;
}

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

bool myCircularQueueDeQueue(MyCircularQueue* obj) 
{
    if(myCircularQueueIsEmpty(obj))
        return false;
    obj->head++;
    obj->head=obj->head%(obj->size+1);
    return true;
}

int myCircularQueueFront(MyCircularQueue* obj) 
{
    if(myCircularQueueIsEmpty(obj))
        return -1;
    int index=(obj->head+1);
    if(index>obj->size)
        index=0;
    return obj->a[index];
}

int myCircularQueueRear(MyCircularQueue* obj) 
{
    if(myCircularQueueIsEmpty(obj))
        return -1;
    int index=obj->tail;
    return obj->a[index];
}

void myCircularQueueFree(MyCircularQueue* obj) 
{
    free(obj->a);
    free(obj);
}

②链表实现

cpp 复制代码
struct QueueNode
{
    int val;
    struct QueueNode* next;
};

typedef struct
{
    struct QueueNode* head;
    struct QueueNode* tail;
} MyCircularQueue;

struct QueueNode* BuyNode(int x)
{
    struct QueueNode* newnode = (struct QueueNode*)malloc(sizeof(struct QueueNode));
    if (newnode == NULL)
    {
        printf("malloc fail\n");
        exit(-1);
    }
    newnode->val = x;
    newnode->next = NULL;
    return newnode;
}

//构造器,设置队列长度为 k 
MyCircularQueue* myCircularQueueCreate(int k)
{
    MyCircularQueue* cq = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    int i = 0;
    cq->head = BuyNode(0);
    cq->tail = cq->head;
    struct QueueNode* cur = cq->head;
    for (i = 0;i < k;i++)
    {
        struct QueueNode* newnode = BuyNode(0);
        cur->next = newnode;
        cur = cur->next;
    }
    cur->next = cq->head;
    return cq;
}

//检查循环队列是否为空。
bool myCircularQueueIsEmpty(MyCircularQueue* obj)
{
    return obj->head==obj->tail;
}

// 检查循环队列是否已满。
bool myCircularQueueIsFull(MyCircularQueue* obj)
{
    return ((obj->tail)->next == obj->head);
}

//向循环队列插入一个元素。如果成功插入则返回真。
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
{
    if (myCircularQueueIsFull(obj))
        return false;
    //尾插
    obj->tail = obj->tail->next;
    (obj->tail)->val = value;
    return true;
}

//从循环队列中删除一个元素。如果成功删除则返回真。
bool myCircularQueueDeQueue(MyCircularQueue* obj)
{
    if (myCircularQueueIsEmpty(obj))
        return false;
    //头删
    obj->head = obj->head->next;
    return true;
}

//从队首获取元素。如果队列为空,返回 -1 
int myCircularQueueFront(MyCircularQueue* obj)
{
    if (myCircularQueueIsEmpty(obj))
        return -1;
    return (obj->head->next)->val;
}

//获取队尾元素。如果队列为空,返回 -1 。
int myCircularQueueRear(MyCircularQueue* obj)
{
    if (myCircularQueueIsEmpty(obj))
        return -1;
    return (obj->tail)->val;
}

//释放队列内存
void myCircularQueueFree(MyCircularQueue* obj)
{
    struct QueueNode* cur = obj->head;
    cur = cur->next;
    while (cur != obj->head)
    {
        struct QueueNode* nxt = cur->next;
        free(cur);
        cur = nxt;
    }
}
相关推荐
feeday2 小时前
Python 删除重复图片 优化版
开发语言·python
本地运行没问题2 小时前
基于Java注解、反射与动态代理:打造简易ORM框架
java
.格子衫.2 小时前
JS原型链总结
开发语言·javascript·原型模式
ss2732 小时前
Java线程池全解:工作原理、参数调优
java·linux·python
麦麦鸡腿堡2 小时前
Java_MySQL介绍
java·开发语言·mysql
于是我说2 小时前
一份Python 面试常见问题清单 覆盖从初级到高级
开发语言·python·面试
shoubepatien2 小时前
JavaWeb_Web基础
java·开发语言·前端·数据库·intellij-idea
北里闻箫2 小时前
Java spinrg 4.x 及 jsp 简单心得(PHP转JAVA视角)
java·php·jsp
Charlie_Byte2 小时前
Netty + Sa-Token 实现 WebSocket 握手认证
java·后端