顺序栈和链队列的基本操作

一、栈和队列的定义

1.栈

         栈又名堆栈(stack),它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。

2.队列

        队列是一种特殊的线性表,它的特点是只能在前端(也称为队尾)进行插入操作,后端(也称为队头)进行删除操作。这种数据结构的实现使用了链表的方式,因此被称为链队列。链队列的管理通常由两个指针来实现,分别是队头指针和队尾指针。这些指针用于唯一确定每一个队列元素的位置。

二.栈的数据存储结构及基本操作。

1.栈的存储结构

typedef int DataType;
typedef struct Stack {
	DataType* value;//元素
	int capacity;//大小
	int top;//栈顶
}ST;

2.栈的初始化

void StackInit(ST* s) {
	assert(s);
	s->value = NULL;
	s->top = 0;
	s->capacity = 0;
}

3.入栈

void StackPush(ST* s, DataType data) {
	assert(s);//检查指针s是否为NULL的断言
	if (s->top == s->capacity) {//检查当前顶部索引是否等于堆栈的容量
		int newcapacity = s->capacity == 0 ? 4 : s->capacity * 2;//计算堆栈的新容量。如果当前容量为0,则将新容量初始化为4;否则,它会使当前容量翻倍。
		int* newnode = (int*)realloc(s->value, sizeof(int) * newcapacity);
		if (newnode == NULL) {//这使用realloc函数来调整s->值所指向的内存块的大小。它试图为新容量分配内存。如果分配失败,它将打印一条错误消息并从函数返回。
			perror("realloc fail");
			return;
		}
		s->value = newnode;//更新ST结构的值成员以指向新分配的内存
		s->capacity = newcapacity;//更新ST结构的容量成员以反映新的容量
	}
	s->value[s->top] = data;//将数据参数指定给当前顶部索引处的元素
	s->top++;//增顶部索引以指向堆栈中的下一个可用位置
}

4.出栈

void StackPop(ST* s) {
	assert(s);//检查指针s是否为NULL的断言
	assert(s->top >= 0);//此断言检查堆栈的顶部索引是否大于或等于0。如果top小于0,则表示存在下溢情况,程序将终止并显示错误消息。
	s->top--;//这一行减少堆栈的顶部索引,有效地删除了顶部元素
}

5.取栈顶元素

DataType StackTop(ST* s) {
	assert(s);//检查指针s是否为NULL的断言
	assert(s->top >= 0);//此断言检查堆栈的顶部索引是否大于或等于0
	return s->value[s->top-1];//此行返回堆栈顶部的元素。它访问索引s->top-1处的元素数组(值)
}

6.判栈空

int StackEmpty(ST* s) {
	assert(s);
	return s->top == 0;//此行返回比较的结果s->top==0。如果顶部索引等于0,则表示堆栈为空,并且函数返回1(true)
}

7.栈的大小

int StackSize(ST* s) {
	assert(s);//检查指针s是否为NULL的断言
	return s->top;//返回栈的当前大小
}

8.栈的销毁

void StackDestroy(ST* s) {
	assert(s);
	free(s->value);//此行使用free函数来解除分配ST结构的值成员所指向的内存块
	s->value = NULL;//将设置为NUL
	s->capacity = s->top = 0;//这些行将ST结构的容量和顶部成员设置为0,有效地将堆栈重置为空状态。
}

 二.队列的数据存储结构及基本操作。

 1.队列的数据存储结构

typedef int DataType;//将int定义为DataType
typedef struct QueueNode {
	DataType val;//元素域
	struct QueueNode* next;//指针域
}Qnode;
typedef struct Queue {
	Qnode * front;//队列前部节点
	Qnode * rear;//队列后部节点
	int size;//队列中元素数量大小
}Queue;

2.队列的初始化操作

void QueueInit(Queue* q) {
	assert(q);//检查指针q是否为NULL的断言
	q->front = NULL;//将队列的队头指针设置为NULL
	q->rear = NULL;//将队列的队尾指针设置为NULL
	q->size = 0;//将队列的大小变量设置为0,表示队列不包含任何元素
}

 3.队列的入队操作

void QueuePush(Queue* q, DataType x) {
	assert(q);//检查指针q是否为NULL的断言
	Qnode * newnode = (Qnode*)malloc(sizeof(Qnode));//使用malloc为新节点动态分配内存
	if (newnode == NULL) {
		perror("malloc fail"); 
		return;
	}
	newnode->val = x;//将x赋给新节点
	newnode->next = NULL;//将新节点的下一个指针设置为NULL
	if (q->rear == NULL) {//检查队列当前是否为空。如果是,新节点将同时成为队列的前面和后面。否则,新节点将添加到现有队列的后面。
		q->rear = q->front = newnode;
	}
	else {
		q->rear->next = newnode;
		q->rear = newnode;
	}
	q->size++;//增加队列的大小变量
}

4.队列的出队操作

void QueuePop(Queue* q) {
	assert(q);//检查指针q是否为NULL
	Qnode* temp = q->front->next;//创建一个临时指针temp,该指针指向队列前一个节点之后的下一个节点
	free(q->front);
	q->front = temp;//将队列的前队头指针更新到下一个节点,有效地删除了前端节点
	if (q->front == NULL) {//检查队头指针现在是否为NULL,表示队列为空。如果删除后队列为空,则前指针和后指针都设置为NULL。
		q->rear = NULL;
	}
	q->size--;//此行减少队列的大小变量,表示元素已被删除
}

5.取队头元素

DataType QueueFront(Queue* q) {
	assert(q);
	assert(q->size >= 0);
	return q->front->val;//返回队头元素
}

6.取队尾元素

DataType QueueRear(Queue* q) {
	assert(q);
	assert(q->size >= 0);
	return q->rear->val;//返回队尾的大小
}

7.队列的大小

int QueueSize(Queue* q) {
	assert(q);
	return q->size;//返回队列大小
}

8.判队空

bool QueueEmpty(Queue*q) {
	assert(q);
	return q->front == NULL;//如果队列为空返回true,不为空返回1
}

9.队列的销毁

void QueueDestroy(Queue* q) {
	assert(q);
	Qnode* temp = q->front;//创建一个临时指针temp,该指针最初指向队头
	while (temp != NULL) {
		Qnode* cur = temp->next;//创建一个临时指针cur,该指针指向队列中的下一个节点,然后再释放当前节点
		free(temp);//释放为当前节点分配的内存
		temp = cur;//更新临时指针以指向队列中的下一个节点,用于循环的下一次迭代
	}
	q->front = q->rear = NULL;//将队列的前指针和后指针都设置为NULL
	q->size=0;//将队列的大小设置为0
}

 

 三.总结

     队列和栈是两种常见的数据结构,它们各自有一些优点和缺点。 队列遵循先进先出的原则,保证了元素的顺序性,先入队的元素先出队。很适合模拟现实生活中的排队行为,如任务调度、打印队列等。但是只支持在两端进行操作,限制了数据的插入和删除方式 ,且不能直接访问队列中间的元素,需要依次出队才能访问。栈遵循后进先出的原则,使得最近进入的元素最先被访问。 栈结构在递归算法的实现中具有重要作用,可以方便地保存和恢复函数调用的状态,但是栈只允许在栈顶进行插入和删除操作,限制了数据的操作方式。有些问题可能需要在数据的中间进行操作,而栈的特性使其在这些情况下不够灵活。

       总体而言,选择使用队列还是栈取决于具体的应用场景和问题要求。在需要按顺序处理数据的情况下,队列可能更适合;而在需要后进先出的情况下,栈可能更合适。在某些情况下,也可以将队列和栈结合使用,以满足特定的需求。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值