栈和队列实现

栈是一种特殊的线性数据结构,只能在一端进行数据的插入和删除操作。数据插入和删除的一端称为栈顶,另一端称为栈底。数据插入的操作称为入栈,数据删除的操作称为出栈。栈中的元素有后进先出的特性。

顺序栈的实现

定义一个栈的结构,声明数据的类型,栈结构中定义存储元素的数组。栈的初始容量,当前栈中元素的个数。

typedef int Datatype;
typedef struct Stack {
	Datatype* array;//数组
	int capacity;//容量
	int Size;//栈中的元素个数
}Stack;

栈初始化
对定义好的栈结构进行初始化,首先要给它开辟连续空间,让栈中字段附上初始值。

void StackInit(Stack* ps) {
	//初始化
	assert(ps);
	ps->array = (Datatype*)malloc(sizeof(Datatype) * 3);
	if (NULL == ps->array) {
		assert(0);
		return;
	}
	ps->capacity = 3;
	ps->Size = 0;
}

判断栈是否为空,

int StackEmpty(Stack* ps) {
	assert(ps);
	return 0 == ps->Size;
}

元素的插入
如果栈中当前容量足够,将待插入的元素放到栈中存储元素数组的下标为Size的位置。然后给Size的值加1。如果容量不够需要进行扩容。

void StackPush(Stack* ps, Datatype data) {
	assert(ps);
	Checkcapacity(ps);
	ps->array[ps->Size++] = data;
}

扩容
如果栈中元素个数与栈的容量相等了,说明没有空间了,用realloc将数组容量从原有值扩大2倍。

void Checkcapacity(Stack* ps) {
	assert(ps);
	if (ps->Size == ps->capacity) {
		ps->array = (Datatype*)realloc(ps->array, sizeof(Datatype) * ps->capacity * 2);
		if (ps->array == NULL) {
			assert(0);
			return;
		}
		ps->capacity *= 2;
	}
}

元素出栈
如果栈不为空,将栈中表示元素个数的size值减1,访问不到了

void StackPop(Stack* ps) {
	assert(ps);
	if (StackEmpty(ps)) {
		return;
	}
	ps->Size--;
}

获取栈顶元素
栈的数据插入和删除只能在栈顶进行,直接访问数组下标为size-1的元素,将它作为返回值取到。

Datatype StackTop(Stack* ps) {
	assert(ps && !StackEmpty(ps));	
	return ps->array[ps->Size - 1];
}

栈的销毁
直接将保存元素的数组array释放掉。

void StackDestroy(Stack* ps) {
	assert(ps);
	if (ps->array) {
		free(ps->array);
		ps->array = NULL;
		ps->capacity = 0;
		ps->Size = 0;
	}
}

栈后进先出的特性可以用来改变元素序列,比如链表逆置,括号匹配问题逆波兰表达式求值等问题。函数递归调用也是层层压栈的过程,可以用栈将递归转化为循环。

队列

同时一种特殊的线性数据结构,队列只能在一端进行数据的插入,在另一端进行数据删除,插入数据的一端称为队尾,删除数据的一端称为队头。队列中的元素具有先进先出的特性。

带头单链表实现队列

定义队列的结构,队列结构中有两个字段,一个指针指向队头,一个指向队尾

typedef int Datatype;
//队列中的一个节点
typedef struct QNode {
	Datatype data;
	struct QNode* next;
}QNode;

//队列的结构
typedef struct Queue {
	struct QNode* front;
	struct QNode* Tail;
}Queue;

队列初始化
往队列中中种一个头结点,头结点不作为数据计入队列,队头和队尾都指向它。

void QueueInit(Queue* pq){
	pq->front = pq->Tail = BuyQueueNode(0) ;
}
QNode* BuyQueueNode(Datatype data) {
	//开辟一块空间,存着一个链表节点的两个字段,
	QNode* node = (QNode*)malloc(sizeof(QNode));
	if (NULL == node) {
		assert(0);
		return NULL;
	}
	node->data = data;
	node->next = NULL;
	return node;
}

数据插入 入队列

插入一个元素是从队尾进行的,类似于单链表的尾插,那就让单链表中最后一个节点的next指针指向它,队列尾指针指向的就是最后一个节点。然后改变队尾只针的指向,指向新插入的节点,就是先满足链表的结构,再满足队列的结构。

void QueuePush(Queue* pq, Datatype data) {
	assert(pq);
	pq->Tail->next = BuyQueueNode(data);
	pq->Tail = pq->Tail->next;
}

数据的删除 出队列
定义一个指针,将队列中第一个元素的节点保存起来,因为等会它要被释放掉,释放掉之后就破坏了链表的结构,找不到下一个元素了,第一个元素的节点就是头结点的下一个节点。然后改变队头的指向,再将要删除的节点释放掉。

void QueuePop(Queue* pq) {
	//删除操作判空
	//定义一个链表节点类型的指针
	QNode* delNode = NULL;
	if (QueueEmpty(pq)) {
		return;
	}
	delNode = pq->front->next;
	pq->front->next  = delNode->next;
	//如果链表中只有一个元素。
	if (delNode == NULL) {
		pq->Tail = pq->front;
	}
	free(delNode);
}

获取队头队尾的元素

Datatype Queuefront(Queue* pq) {
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->front->next->data;
}
Datatype QueueTail(Queue* pq) {
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->Tail->data;
}

获取队列中元素总个数

int QueueSize(Queue* pq) {
	assert(pq);
	int count = 0;
	QNode* cur = pq->front->next;
	while (cur) {
		count++;
		cur = cur->next;
	}
	return count;
}

判断队列是否为空

int QueueEmpty(Queue* pq) {
	assert(pq);
	return NULL == pq->front->next;
}

队列销毁
从头节点开始,找到一个节点释放一个,释放之前要先改变头节点的指向

void QueueDestroy(Queue* pq) {
	assert(pq);
	QNode* delNode = NULL;
	delNode = pq->front;
	while (delNode) {
		pq->front = delNode->next;
		free(delNode);
		delNode = pq->front;
	}
	pq->front = NULL;
	pq->Tail = NULL;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值