【C语言实现简单的数据结构】栈和队列

【C语言实现简单的数据结构】栈和队列

心有所向,日复一日,必有精进



前言

顺序表链表到这里告一段落,在实现栈和队列的时候虽然在逻辑上和顺序变链表不同,但物理结构我们可以使用顺序变或者链表来实现。但是根据结构的逻辑不同,可以根据各自优缺来选择,所以请学好顺序表链表,接下来进入栈和队列。

---

  1. :一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守**后进先出LIFO(Last In First Out)**的原则。
  2. 压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
  3. 出栈:栈的删除操作叫做出栈。出数据也在栈顶。
    在这里插入图片描述
    栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小。
    在这里插入图片描述

栈的接口

//栈的初始化
void StackInit(Stack*ps);
//销毁
void StackDestroy(Stack* ps);
//入栈
void StackPush(Stack* ps,STData x);
//出栈
void StackPop(Stack* ps);

//取栈顶元素
STData StackTop(Stack* ps);
//销毁
bool StackEmpty(Stack* ps);
//栈的长度
int StackSize(Stack* ps);

栈的具体实现

//结构
typedef int STData;
typedef struct STACK{
	STData* arr;
	int top;
	int capacity;
}Stack;
//初始化
void StackInit(Stack* ps){
	assert(ps);
	ps->arr = NULL;
	ps->top = ps->capacity = 0;
}
//销毁
void StackDestroy(Stack*ps){
	assert(ps);
	free(ps->arr);
	ps->arr = NULL;
	ps->capacity = ps->top = 0;
}
//出栈
void StackPush(Stack*ps,STData x){
	assert(ps);
	if (ps->top == ps->capacity){
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		STData* tmp = (STData*)realloc(ps->arr, newcapacity*sizeof(Stack*));
		if (tmp == NULL){
			perror("realloc fail");
			exit(-1);
		}
		ps->arr = tmp;
		ps->capacity = newcapacity;
	}
		ps->arr[ps->top] = x;
		ps->top++;		
}
//出栈
void StackPop(Stack* ps){
	assert(ps);
	assert(!StackEmpty(ps));
	--ps->top;
}
//取栈顶元素
STData StackTop(Stack*ps){
	assert(ps);
	return ps->arr[(ps->top)-1];
}
//判断是否为空
bool StackEmpty(Stack*ps){
	assert(ps);
	return ps->top == 0;
}
//栈的长度
int StackSize(Stack* ps)
{
	assert(ps);

	return ps->top;
}

队列

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

  1. 入队列:进行插入操作的一端称为队尾
  2. 出队列:进行删除操作的一端称为队头
    在这里插入图片描述
    队列就好比生活中的排队,队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。

循环队列

在这里插入图片描述

环形队列可以使用数组实现,也可以使用循环链表实现。
循环队列,重要的是队列的停止,循环队列用数组实现比较好,在下面练习题中会实现循环队列;

队列接口

typedef int QTData;
typedef struct QNode
{
	QTData data;
	struct QNode*next;
}QNode;
typedef struct Queue
{
	QNode* head;
	QNode* tail;
	int size;
}Queue;
//队列初始化
void QueueInit(Queue* phead);
//销毁
void QueueDestroy(Queue* phead);
//入队
void QueuePush(Queue* phead ,int x);
//出队
void QueuePop(Queue* phead);
//队头元素
QTData QueueFront(Queue* phead);
//队尾元素
QTData QueueBack(Queue* phead);
//判空
bool QueueEmpty(Queue* phead);
//队列长度
int QueueSize(Queue* phead);

队列具体实现

void QueueInit(Queue* phead){
	phead->head = phead->tail = NULL;
	phead->size = 0;
}
void QueueDestroy(Queue* phead){
	QNode*cur = phead->head;
	while (cur){
		Queue*next = cur->next;
		free(cur);
		cur = next;
	}
}
void QueuePush(Queue* phead, int x){
	QNode*newnode = (QNode*)malloc(sizeof(QNode));
	newnode->data = x;
	newnode->next = NULL;
	if (phead->head == NULL){
		phead->head = phead->tail = newnode; 
	}
	else{
		phead->tail->next = newnode;
		phead->tail = newnode;
	}
	phead->size++;
}
void QueuePop(Queue* phead){
	Queue*cur =phead->head;
	phead->head = phead->head->next;
	free(cur);
	cur = NULL; 
	phead->size--;
}
QTData QueueFront(Queue* phead){

	return phead->head->data;
}
QTData QueueBack(Queue* phead){
	return phead->tail->data;
}
bool QueueEmpty(Queue* phead){
	return  phead->head == NULL;
}
int QueueSize(Queue* phead){
	return phead->size;
}

栈和队列练习题

1、括号匹配

思路: 遇到左括号入栈,利用先进后出的的性质,遇到右括号出栈匹配,发现是一对括号,就可以匹配成功。

在这里插入图片描述

比较简单直接上代码

题目:有效的括号

typedef char  STData;
typedef struct STACK{
	STData* arr;
	int top;
	int capacity;
}Stack;
bool StackEmpty(Stack*ps);
void StackInit(Stack* ps){
	assert(ps);
	ps->arr = NULL;
	ps->top = 0;
    ps->capacity = 0;
}
void StackDestroy(Stack*ps){
	assert(ps);
	free(ps->arr);
	ps->arr = NULL;
	ps->capacity = ps->top = 0;
}
void StackPush(Stack*ps,STData x){
	assert(ps);
	if (ps->top == ps->capacity){
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		STData* tmp = (STData*)realloc(ps->arr, newcapacity*sizeof(Stack*));
		if (tmp == NULL){
			perror("realloc fail");
			exit(-1);
		}
		ps->arr = tmp;
		ps->capacity = newcapacity;
	}
		ps->arr[ps->top] = x;
		ps->top++;		
}
void StackPop(Stack* ps){
	assert(ps);
	assert(!StackEmpty(ps));
	--ps->top;
}
STData StackTop(Stack*ps){
	assert(ps);
	return ps->arr[(ps->top)-1];
}
bool StackEmpty(Stack*ps){
	assert(ps);
	return ps->top == 0;

}
int StackSize(Stack* ps)
{
	assert(ps);

	return ps->top;
}
bool isValid(char * s){
Stack sl;
StackInit(&sl);

while(*s){
    if(*s=='('||*s=='['||*s=='{'){
        StackPush(&sl,*s);
    }else{
    if(StackEmpty(&sl)){StackDestroy(&sl); return false;}
    char top = StackTop(&sl);
    StackPop(&sl);
     if((*s==')'&&top!='(')
        ||(*s=='}'&&top!='{')
        ||(*s==']'&&top!='[')){
            StackDestroy(&sl);
            return false;
        }
    }
++s;   
}
bool falg = StackEmpty(&sl);
StackDestroy(&sl);
return falg;
}

在c语言中,我们只能先自己实现一个栈,然后实现,在c++或java中实现较为简单。

2、实现循环队列

实现队列有一个关键问题:循环队列真正的问题是如何判空和判满?
back指向队尾元素的下一个的时候,无法判断队列为空还是为满!

back直接指向队尾元素讷?
这样很烦讷,不信你试试?

在这里插入图片描述

循环队列,在为空和满的时候back所指向的和front所指向的相同,如何解决?
增加一个空间,在队列为满时候,总会剩下一个空间

那么实现循环队列是用数组还是链表?

前面队列使用的是链表结构,在链表也存在循环链表,是不是适合实现循环队列呢?
但实际上二者都可以,

(灵幻拷问)但是链表有一个操作如何取队尾元素?
如果是单链表那有点难讷,还是选数组吧

在这里插入图片描述
back的next是front,为满,

两种为满的情况:

在这里插入图片描述

(很巧妙,非常巧妙,简直是米老鼠进了妙妙屋吃妙脆角)

bool myCircularQueueIsFull(MyCircularQueue* obj) {
  return ((obj->Back)+1)%(obj->N)==obj->Front;
}

back==front,为空

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
	return obj->Front==obj->Back;
}

返回队尾元素,这种方式还是喵~

int myCircularQueueRear(MyCircularQueue* obj) {
if(obj->Front==obj->Back){
        return -1;
    }
    return obj->arr[(obj->Back-1+(obj->N))%(obj->N)];
}

题目:设计实现循环队列

typedef struct {
    int *arr;
    int Front;
    int Back;
    int N;
} MyCircularQueue;


MyCircularQueue* myCircularQueueCreate(int k) {
       MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
       int*a = (int*)malloc(sizeof(int)*(k+1));
       obj->arr= a;
       obj->Front = 0;
       obj->Back = 0;
       obj->N = k+1;
       return obj;                 
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if(((obj->Back)+1)%(obj->N)==obj->Front){
        return false;
    }
    if(obj->Back==(obj->N)-1){
        obj->arr[obj->Back] = value; 
         (obj->Back)  = ((obj->Back)+1)%(obj->N) ;
    }else{
      obj->arr[obj->Back] = value; 
    (obj->Back)++;   

    }
    // obj->arr[obj->Back] = value;
    // obj->Back++;
    //  (obj->Back)  %= obj->N;
    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if(obj->Front==obj->Back){
        return false;
    }
if(obj->Front==(obj->N)-1){
    (obj->Front)  = ((obj->Front)+1)%(obj->N) ;
}else{
    obj->Front++;
}
return true;
}

int myCircularQueueFront(MyCircularQueue* obj) {
    if(obj->Front==obj->Back){
        return -1;
    }
return obj->arr[obj->Front];
}

int myCircularQueueRear(MyCircularQueue* obj) {
if(obj->Front==obj->Back){
        return -1;
    }
    return obj->arr[(obj->Back-1+(obj->N))%(obj->N)];
}

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
return obj->Front==obj->Back;
}

bool myCircularQueueIsFull(MyCircularQueue* obj) {
  return ((obj->Back)+1)%(obj->N)==obj->Front;
}

void myCircularQueueFree(MyCircularQueue* obj) {

    free(obj->arr);
    obj->arr==NULL;
    obj->Front = 0;
    obj->Back = 0;
    obj->N = 0;
    free(obj);
}

  • 14
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 12
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值