zl程序教程

您现在的位置是:首页 >  其他

当前栏目

【数据结构初阶】一文详解顺序栈和链队列的基本操作

2023-02-25 18:20:13 时间

目录

1.栈的概念

 2.栈的结构

 3.实现栈的基本操作

3.1栈的初始化

3.2压栈

3.3出栈

3.4 取栈顶元素

3.5 计算栈内元素个数

3.6栈的判空

3.7栈的销毁

4.源代码

4.1stack.c

4.2stack.h

4.3test.c

 4.4效果

1.队列的概念

 2.队列的结构

 3.实现队列的基本操作

3-1结构体定义

3-2队列的初始化

3-3入队列

3-4出队列

3-5取队头元素

3-6取队尾元素

3-7队列判空

3-8队列长度

3-9队列销毁

4.源代码

4-1queue.c

4.2queue.h

4.3test.c

4.4效果图


1.栈的概念

栈,一种特殊的线性表,特殊在于只允许在固定的一端进行插入删除数据,插入和删除数据的一端是栈顶,另一端是栈底,已经在栈中的数据满足Fist In  Last Out的原则。

压栈:栈顶插入数据 出栈:栈顶弹出数据

 2.栈的结构

总体而言,用顺序表和链表实现都可以,但是由于栈只支持在栈顶插入删除数据,且要满足后进先出,而顺序表尾插尾删的效率比链表高,(顺序表唯一的缺点在这就是扩容有性能和空间的消耗)同时也满足后进先出的原则,所以选择顺序表实现好!

有人可能会说用链表,然后定义一个尾指针,这样尾插效率不是也很高吗?

答:定义一个尾指针,链表的插入时很方便,但是尾删呐??

其实顺序表,双向循环链表,头上操作单链表都行,但是由于顺序表命中率高的优点,还是选择顺序表。

 3.实现栈的基本操作

3.1栈的初始化

  1.  选择哪一个方式初始化top都可以,但是记得做到和后面的push等做到统一。
  2.  建议再主函数内判空操作不直接自己if(ps->top==0)等,因为这个内部怎么实现的不一定是初始化为ps->top=0,而是建议调用函数去判空if(StackEmpty(&ST))
void StackInit(Stack* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->top = ps->capacity = 0;
}

3.2压栈

void StackPush(Stack* ps, STDateType x)
{
	assert(ps);

	if(ps->top == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity*2;
		STDateType* temp = (STDateType*)realloc(ps->a, sizeof(STDateType)*newcapacity);
		if (temp == NULL)
		{
			perror("malloc fail.\n");
			exit(-1);
		}
		ps->capacity = newcapacity;
		ps->a = temp;
	}
	ps->a[ps->top] = x;
	ps->top++;
}

3.3出栈

void StackPop(Stack* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));
	ps->top--;
}

3.4 取栈顶元素

STDateType StackTop(Stack* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));
	return ps->a[ps->top - 1];
}

3.5 计算栈内元素个数

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

3.6栈的判空

bool StackEmpty(Stack* ps)
{
	assert(ps);
	return ps->top == 0;
}

3.7栈的销毁

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

4.源代码

4.1stack.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"stack.h"
void StackInit(Stack* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->top = ps->capacity = 0;
}

void StackPush(Stack* ps, STDateType x)
{
	assert(ps);

	if(ps->top == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity*2;
		STDateType* temp = (STDateType*)realloc(ps->a, sizeof(STDateType)*newcapacity);
		if (temp == NULL)
		{
			perror("malloc fail.\n");
			exit(-1);
		}
		ps->capacity = newcapacity;
		ps->a = temp;
	}
	ps->a[ps->top] = x;
	ps->top++;
}

void StackPop(Stack* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));
	ps->top--;
}

STDateType StackTop(Stack* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));
	return ps->a[ps->top - 1];
}

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

bool StackEmpty(Stack* ps)
{
	assert(ps);
	return ps->top == 0;
}


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

4.2stack.h

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>

typedef int STDateType;
typedef struct Stack
{
	STDateType* a;
	int top;
	int capacity;
}Stack;

void StackInit(Stack* ps);

void StackPush(Stack* ps,STDateType x);

void StackPop(Stack* ps);

STDateType StackTop(Stack* ps);

bool StackEmpty(Stack* ps);

int StackSize(Stack* ps);

void StackDestory(Stack* ps);

4.3test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"stack.h"


int main()
{
	Stack ST;
	StackInit(&ST);
	StackPush(&ST, 1);
	StackPush(&ST, 2);
	StackPush(&ST, 3);
	StackPush(&ST, 4);
	STDateType top = StackTop(&ST);
	printf("top:%d\n", top);
	StackPop(&ST);
	top = StackTop(&ST);
	printf("top:%d\n", top);
	int size = StackSize(&ST);
	printf("size:%d\n", size);
	StackDestory(&ST);
	return 0;
}

 4.4效果图


1.队列的概念

队列是一种特殊的线性表,特殊在只能从一端进行插入操作,另一端进行删除操作,队列具有Fist  In First Out的原则。 队尾:进行插入操作的一端,这个过程叫做入队列 队头:进行删除操作的一端,这个过程叫做出队列

抽号机:先来先服务,先给号码排队 (涉及嵌入式)

 2.队列的结构

队列我们采用链表实现:顺序表在满了要扩容,删完了后再入队列的时候还得扩容 链表的话,入队列就是尾插,定义一个尾指针。出队列就是头删,定义一个头指针

 3.实现队列的基本操作

3-1结构体定义

typedef int QDateType;
typedef struct QueueNode
{
	struct QueueNode* next;
	QDateType val;
}QueueNode;

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

3-2队列的初始化

这里的链表队列我并没有带头,没有带头就要在入队列和出队列时有一点特殊情况的考虑

void QueueInit(Queue* ps)
{
	assert(ps);
	ps->head = ps->tail = NULL;
}

3-3入队列

相当于尾插,考虑特殊情况:队列为空的情况

//入队列:尾插
void QueuePush(Queue* ps,QDateType x)
{
	assert(ps);
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	newnode->next = NULL;
	newnode->val = x;
	if (newnode == NULL)
	{
		perror("malloc fail.");
		exit(-1);
	}
	if (ps->tail == NULL)
	{
		ps->head = ps->tail = newnode;
	}
	else
	{
		ps->tail->next = newnode;
		ps->tail = ps->tail->next;
	}
}

3-4出队列

相当于头删,考虑特殊情况:只有一个结点的情况,出队列后要改变ps->tail

void QueuePop(Queue* ps)
{
	assert(ps);
	assert(!QueueEmpty(ps));
	if (ps->head->next == NULL)
	{
		free(ps->head);
		ps->head = ps->tail = NULL;
	}
	else
	{
		QueueNode* next = ps->head->next;
		free(ps->head);
		ps->head = next;

	} 
}

3-5取队头元素

QDateType QueueFront(Queue* ps)
{
	assert(ps);
	assert(!QueueEmpty(ps));
	return ps->head->val;
}

3-6取队尾元素

QDateType QueueBack(Queue* ps)
{
	assert(ps);
	assert(!QueueEmpty(ps));
	return ps->tail->val;
}

3-7队列判空

bool QueueEmpty(Queue* ps)
{
	assert(ps);
	return ps->tail == NULL;
}

3-8队列长度

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

3-9队列销毁

void QueueDestory(Queue* ps)
{
	assert(ps);
	QueueNode* cur = ps->head;
	while (cur)
	{
		QueueNode* next = cur->next;
		free(cur);
		cur = next;
	}
	ps->head = ps->tail = NULL;
}

4.源代码

4-1queue.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"queue.h"

void QueueInit(Queue* ps)
{
	assert(ps);
	ps->head = ps->tail = NULL;
}

void QueueDestory(Queue* ps)
{
	assert(ps);
	QueueNode* cur = ps->head;
	while (cur)
	{
		QueueNode* next = cur->next;
		free(cur);
		cur = next;
	}
	ps->head = ps->tail = NULL;
}

//入队列:尾插
void QueuePush(Queue* ps,QDateType x)
{
	assert(ps);
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	newnode->next = NULL;
	newnode->val = x;
	if (newnode == NULL)
	{
		perror("malloc fail.");
		exit(-1);
	}
	if (ps->tail == NULL)
	{
		ps->head = ps->tail = newnode;
	}
	else
	{
		ps->tail->next = newnode;
		ps->tail = ps->tail->next;
	}
}

void QueuePop(Queue* ps)
{
	assert(ps);
	assert(!QueueEmpty(ps));
	if (ps->head == ps->tail)
	{
		free(ps->head);
		ps->head = ps->tail = NULL;
	}
	else
	{
		QueueNode* next = ps->head->next;
		free(ps->head);
		ps->head = next;

	} 
}

QDateType QueueFront(Queue* ps)
{
	assert(ps);
	assert(!QueueEmpty(ps));
	return ps->head->val;
}

QDateType QueueBack(Queue* ps)
{
	assert(ps);
	assert(!QueueEmpty(ps));
	return ps->tail->val;
}

bool QueueEmpty(Queue* ps)
{
	assert(ps);
	return ps->tail == NULL;
}

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

4.2queue.h

#define _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>

typedef int QDateType;
typedef struct QueueNode
{
	struct QueueNode* next;
	QDateType val;
}QueueNode;

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

void QueueInit(Queue* ps);

void QueuePush(Queue* ps, QDateType x);

void QueuePop(Queue* ps);

QDateType QueueFront(Queue* ps);

QDateType QueueBack(Queue* ps);

bool QueueEmpty(Queue* ps);

int QueueSize(Queue* ps);

void QueueDestory(Queue* ps);

4.3test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"queue.h"


int main()
{
	Queue Q;
	QueueInit(&Q);
	QueuePush(&Q, 1);
	QueuePush(&Q, 2);
	QueuePush(&Q, 3);
	QueuePush(&Q, 4);
	QueuePush(&Q, 5);
	QDateType ret1 = QueueFront(&Q);
	printf("QueueFront:%d\n", ret1);
	QDateType ret2 = QueueBack(&Q);
	printf("QueueBack:%d\n", ret2);
	int size = QueueSize(&Q);
	printf("size:%d\n", size);
	while (!QueueEmpty(&Q))
	{
		printf("%d", QueueFront(&Q));
		QueuePop(&Q);
	}
	QueueDestory(&Q);
	return 0;
}

4.4效果图

 制作不易,敬请三连