C++11 数据结构7 队列的链式存储,实现,测试

前期考虑

队列是两边都有开口,那么在链式情况下,线性表的链式那一边作为对头好呢?

从线性表的核心的插入和删除算法来看,如果在线性表链表的头部插入,每次循环都不会走,但是删除的时候,要删除线性表的尾部,要遍历整个 线性表。

都差不多。

我们考虑到在插入的时候,可能是批量插入,删除只是在某些条件成立的情况下才会删除,因此会将 线性表的头部做为 队列的头部,将线性表的尾部做为队列的尾部

 插入算法 核心代码

	//正式插入数据,
	int i = 0;
	LinkListNode *curSeqListNode = &(tempseqlist->head);//让curSeqListNode 指向 链表的头部
	for (int i = 0; i < pos; ++i) {
		curSeqListNode = curSeqListNode->next;
	}
	node->next = curSeqListNode->next;
	curSeqListNode->next = node;
	tempseqlist->length++;
	return ret;

删除算法 核心代码

	//辅助指针变量curSeqListNode,指向的位置是链表的头部
	LinkListNode *curSeqListNode = &(tempseqlist->head);//让curSeqListNode 指向 链表的头部
	
    int i = 0;
	for (i = 0; i < pos; ++i) {
		curSeqListNode = curSeqListNode->next;
	}
	retSeqListNode = curSeqListNode->next;	//先将要删除的节点缓存出来
	curSeqListNode->next = retSeqListNode->next;// 删除的节点的next中保存着 “要删除元素的下一个元素”,让curseqlistnode->next 指向
	tempseqlist->length--;
	return retSeqListNode;

代码实现

#ifndef __007LINKQUEUE_H__
#define __007LINKQUEUE_H__


//这两个是要给 所有人公开的
typedef void LinkQueue;

typedef struct LinkQueueNode {  //链表节点
	struct LinkQueueNode *next;
}LinkQueueNode;

//对外提供的方法

//初始化队列,要动态的创建LinkQueue
//创建失败返回NULL
LinkQueue* createLinkQueue();

//入队列 ,给队列的头部插入一个元素,插入点是在数组的尾部
//参数queue 表示要插入的栈
//参数 seqQueueNode 表示要插入的 节点
//成功 返回 1
//失败 返回<0
int push_LinkQueue(LinkQueue* queue, LinkQueueNode * seqQueueNode);

//出队列 将队列的头部的第一个元素删除,删除点是在数组的头部
//参数stack 表示要删除第一个元素的栈
//成功 返回 1
//失败 返回<0
//说明,最开始的时候,让删除栈顶元素,返回int,但是这个设计是不合理的。
//因为假设上层是Teacher,这个Teacher里的元素有 char *,char**,且这两个空间也是malloc的,那么上层需要释放这两个malloc出来的元素。
//这意味着我们需要将 pop_SeqStack中的元素返回上去,上层才有机会释放,底层怎么知道上层搞的是个啥存的?因此一定要给上层,让上层去释放。

//出队列 将队列的头部的第一个元素删除,删除点是在数组的头部
//参数linkqueue 表示要删除第一个元素的队列
//成功 返回 删除的第一个元素
//失败 返回 NULL
LinkQueueNode* pop_LinkQueue(LinkQueue* linkqueue);

//返回队列元素,将队列头部的第一个元素返回
//失败返回NULL
//成功返回节点
LinkQueueNode* top_LinkQueue(LinkQueue* linkqueue);

//返回队列大小
//成功 返回 队列的大小
//失败 返回<0
int size_LinkQueue(LinkQueue* linkqueue);


//判断队列是否为空
//成功 返回1 表示队列为空 
//成功 返回0 表示队列不为空
//失败 返回-1 表示该函数执行的时候有问题
int isEmpty_LinkQueue(LinkQueue* linkqueue);

//销毁队列
//成功 返回1 表示成功销毁队列 
//失败 返回-1 表示该函数执行的时候有问题
int Destory_LinkQueue(LinkQueue* linkqueue);

#endif

#include "007linkqueue.h"
#include "stdlib.h"
#include "stdio.h"
#include "string.h"

typedef struct LinkQueue {
	LinkQueueNode head;
	int length;// 该链表的大小
}TLinkQueue;

//初始化队列,要动态的创建LinkQueue
//创建失败返回NULL
LinkQueue* createLinkQueue() {
	TLinkQueue * tq = malloc(sizeof(TLinkQueue));
	if (tq == NULL) {
		printf("createLinkQueue error because malloc error\n");
		return NULL;
	}
	memset(tq,0,sizeof(TLinkQueue));
	tq->head.next = NULL;
	tq->length = 0;
	return tq;
}

//入队列 ,给队列的尾部插入一个元素,插入点也是在线性表的头部
//参数queue 表示要插入的栈
//参数 seqQueueNode 表示要插入的 节点
//成功 返回 1
//失败 返回<0
int push_LinkQueue(LinkQueue* queue, LinkQueueNode * seqQueueNode) {
	int ret = 1;
	if (queue == NULL) {
		ret = -1;
		printf("push_LinkQueue error because queue == NULL \n");
		return ret;
	}
	if (seqQueueNode == NULL) {
		ret = -2;
		printf("push_LinkQueue error because seqQueueNode == NULL \n");
		return ret;
	}
	TLinkQueue *tq = (TLinkQueue *)queue;
	LinkQueueNode* current = &(tq->head);//辅助指针变量,指向线性表的头结点
	seqQueueNode->next = current->next;
	current->next = seqQueueNode;
	tq->length++;
	return ret;
	
}

//出队列 将队列的头部的第一个元素删除,删除点是在线性表链接的最后一个元素
//参数linkqueue 表示要删除第一个元素的队列
//成功 返回 1
//失败 返回<0
//说明,最开始的时候,让删除栈顶元素,返回int,但是这个设计是不合理的。
//因为假设上层是Teacher,这个Teacher里的元素有 char *,char**,且这两个空间也是malloc的,那么上层需要释放这两个malloc出来的元素。
//这意味着我们需要将 pop_SeqStack中的元素返回上去,上层才有机会释放,底层怎么知道上层搞的是个啥存的?因此一定要给上层,让上层去释放。

//出队列 将队列的头部的第一个元素删除,删除点是在数组的尾部,
//参数linkqueue 表示要删除第一个元素的队列
//成功 返回 删除的第一个元素
//失败 返回 NULL
LinkQueueNode* pop_LinkQueue(LinkQueue* linkqueue) {
	LinkQueueNode* ret = NULL;
	if (linkqueue == NULL) {
		ret = NULL;
		printf("pop_LinkQueue error because queue == NULL \n");
		return ret;
	}
	TLinkQueue *tq = (TLinkQueue *)linkqueue;
	if (tq->length==0) {
		ret = NULL;
		printf("pop_LinkQueue error because tq->length==0 \n");
		return ret;
	}
	LinkQueueNode* current = &(tq->head);//辅助指针变量,指向线性表的头结点
	int pos = tq->length -1;
	for (int i = 0; i < pos; i++)
	{
		current = current->next;
	}
	LinkQueueNode* delnode = current->next;
	current->next = delnode->next;
	tq->length--;
	return delnode;

}

//返回队列元素,将队列头部的第一个元素返回
//失败返回NULL
//成功返回节点
LinkQueueNode* top_LinkQueue(LinkQueue* linkqueue) {
	LinkQueueNode* ret = NULL;
	if (linkqueue == NULL) {
		ret = NULL;
		printf("top_LinkQueue error because queue == NULL \n");
		return ret;
	}
	TLinkQueue *tq = (TLinkQueue *)linkqueue;
	if (tq->length == 0) {
		ret = NULL;
		printf("top_LinkQueue error because tq->length==0 \n");
		return ret;
	}
	LinkQueueNode* current = &(tq->head);//辅助指针变量,指向线性表的头结点
	int pos = tq->length -1;
	for (int i = 0; i < pos; i++)
	{
		current = current->next;
	}
	LinkQueueNode* getnode = current->next;
	return getnode;
}

//返回队列大小
//成功 返回 队列的大小
//失败 返回<0
int size_LinkQueue(LinkQueue* linkqueue) {
	int ret = 0;
	if (linkqueue == NULL) {
		ret = -1;
		printf("size_LinkQueue error because queue == NULL \n");
		return ret;
	}
	TLinkQueue *tq = (TLinkQueue *)linkqueue;
	return tq->length;
}


//判断队列是否为空
//成功 返回1 表示队列为空 
//成功 返回0 表示队列不为空
//失败 返回-1 表示该函数执行的时候有问题
int isEmpty_LinkQueue(LinkQueue* linkqueue) {
	int ret = 0;
	if (linkqueue == NULL) {
		ret = -1;
		printf("isEmpty_LinkQueue error because queue == NULL \n");
		return ret;
	}
	TLinkQueue *tq = (TLinkQueue *)linkqueue;
	int length =  tq->length;
	if (length==0) {
		ret = 1;
		return ret;
	}else{
		ret = 0;
		return ret;
	}
}

//销毁队列
//成功 返回1 表示成功销毁队列 
//失败 返回-1 表示该函数执行的时候有问题
int Destory_LinkQueue(LinkQueue* linkqueue) {
	int ret = 1;
	if (linkqueue == NULL) {
		ret = -1;
		printf("Destory_LinkQueue error because queue == NULL \n");
		return ret;
	}
	free(linkqueue);
	linkqueue = NULL;
	return ret;
}

#define _CRT_SECURE_NO_WARNINGS
#define _CRTDBG_MAP_ALLOC
#include "iostream"
#include <stdio.h>
#include <stdlib.h>

extern "C" {
#include "007linkqueue.h"
}

typedef struct Teacher {
	LinkQueueNode  linkqueuenode;
	int age;
	char name[128];
	char *othername;
	char **stuname; //一个老师下面有5个学生
}Teacher;

int main() {
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);//程序退出时检测内存泄漏并显示到“输出”窗口

	int ret = 0;

	//初始化队列,要动态的创建LinkQueue
//创建失败返回NULL
	LinkQueue* linkqueue = createLinkQueue();
	if (linkqueue==NULL) {
		ret = -1;
		printf("func createLinkQueue error because linkqueue=NULL");
		return ret;
	}

	ret = isEmpty_LinkQueue(linkqueue);
	printf("isEmpty_LinkQueue = ret %d\n", ret);

	ret = size_LinkQueue(linkqueue);
	printf("size_LinkQueue = ret %d\n", ret);

	Teacher tea1;
	tea1.age = 20;
	strcpy(tea1.name, (const char*)"tea1");

	tea1.othername = (char *)malloc(sizeof(char) * 128);
	memset(tea1.othername, 0, sizeof(char) * 128);
	strcpy(tea1.othername, (const char*)"tea1othername");

	tea1.stuname = (char **)malloc(sizeof(char *) * 5);
	memset(tea1.stuname, 0, sizeof(char *) * 5);
	for (size_t i = 0; i < 5; i++)
	{
		tea1.stuname[i] = (char *)malloc(sizeof(char) * 128);//每个学生名字也有128个字符
		memset(tea1.stuname[i], 0, sizeof(char) * 128);
		sprintf(tea1.stuname[i], "tea1stuname%d", i + 1);
	}



	Teacher tea2;
	tea2.age = 22;

	strcpy(tea2.name, (const char*)"tea2");

	tea2.othername = (char *)malloc(sizeof(char) * 128);
	memset(tea2.othername, 0, sizeof(char) * 128);
	strcpy(tea2.othername, (const char*)"tea2othername");

	tea2.stuname = (char **)malloc(sizeof(char *) * 5);
	memset(tea2.stuname, 0, sizeof(char *) * 5);
	for (size_t i = 0; i < 5; i++)
	{
		tea2.stuname[i] = (char *)malloc(sizeof(char) * 128);//每个学生名字也有128个字符
		memset(tea2.stuname[i], 0, sizeof(char) * 128);
		sprintf(tea2.stuname[i], "tea2stuname%d", i + 1);
	}



	Teacher tea3;
	tea3.age = 33;
	strcpy(tea3.name, (const char*)"tea3");

	tea3.othername = (char *)malloc(sizeof(char) * 128);
	memset(tea3.othername, 0, sizeof(char) * 128);
	strcpy(tea3.othername, (const char*)"tea3othername");

	tea3.stuname = (char **)malloc(sizeof(char *) * 5);
	memset(tea3.stuname, 0, sizeof(char *) * 5);
	for (size_t i = 0; i < 5; i++)
	{
		tea3.stuname[i] = (char *)malloc(sizeof(char) * 128);//每个学生名字也有128个字符
		memset(tea3.stuname[i], 0, sizeof(char) * 128);
		sprintf(tea3.stuname[i], "tea3stuname%d", i + 1);
	}

	ret = push_LinkQueue(linkqueue, (LinkQueueNode *)&tea1);
	if (ret < 0) {
		printf("push_LinkQueue(linkqueue, (LinkQueueNode * )&tea1) func error ret =%d \n", ret);
		return ret;
	}

	ret = push_LinkQueue(linkqueue, (LinkQueueNode *)&tea2);
	if (ret < 0) {
		printf("push_LinkQueue(linkqueue, (LinkQueueNode * )&tea2) func error ret =%d \n", ret);
		return ret;
	}

	ret = push_LinkQueue(linkqueue, (LinkQueueNode *)&tea3);
	if (ret < 0) {
		printf("push_LinkQueue(linkqueue, (LinkQueueNode * )&tea3) func error ret =%d \n", ret);
		return ret;
	}

	printf("-after-\n");
	ret = isEmpty_LinkQueue(linkqueue);
	printf("isEmpty_LinkQueue = ret %d\n", ret);

	ret = size_LinkQueue(linkqueue);
	printf("size_LinkQueue = ret %d\n", ret);



	while (size_LinkQueue(linkqueue) > 0) {
		Teacher * temptea = (Teacher *)top_LinkQueue(linkqueue);
		if (temptea == NULL) {
			printf("can not get find teacher\n");
		}
		printf("temptea->age = %d,temptea->name = %s,temptea->othername=%s\n",
			temptea->age,
			temptea->name,
			temptea->othername);
		for (size_t j = 0; j < 5; j++)
		{
			printf("temptea->stuname[%d] = %s,  ",
				j, temptea->stuname[j]);
		}
		Teacher * deltea = (Teacher *)pop_LinkQueue(linkqueue);
		if (deltea == NULL) {
			printf("pop_LinkQueue seqstack error\n");
		}
		if (deltea->othername != NULL) {
			free(deltea->othername);

		}
		if (deltea->stuname != NULL) {
			for (size_t i = 0; i < 5; i++)
			{
				if (deltea->stuname[i] != NULL) {
					free(deltea->stuname[i]);
				}
			}
			free(deltea->stuname);
			deltea->stuname = NULL;
		}

		printf("\n");
	}
	printf("sss\n");

	//销毁栈
	//成功 返回1 表示成功销毁栈 
	//失败 返回-1 表示该函数执行的时候有问题
	ret = Destory_LinkQueue(linkqueue);

	return 0;

}

注意的点:

在代码中,我们从队尾删除元素的时候,或者从队尾拿到元素的时候,注意pos的值是length-1的,这是因为:我们在设计的时候,头部元素并不算真正的元素,真正的元素是从有值的第一个元素开始算的,且认为是0号元素

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是实现链式存储的泛型队列的示例代码(使用C++语言): ``` template <typename T> class QueueNode { public: T data; QueueNode<T>* next; QueueNode(T data) { this->data = data; next = nullptr; } }; template <typename T> class Queue { private: QueueNode<T>* front; QueueNode<T>* rear; int size; public: Queue() { front = nullptr; rear = nullptr; size = 0; } ~Queue() { while (front != nullptr) { QueueNode<T>* temp = front; front = front->next; delete temp; } } void enqueue(T data) { QueueNode<T>* newNode = new QueueNode<T>(data); if (rear == nullptr) { front = newNode; } else { rear->next = newNode; } rear = newNode; size++; } T dequeue() { if (front == nullptr) { throw std::out_of_range("Queue is empty"); } QueueNode<T>* temp = front; front = front->next; T data = temp->data; delete temp; size--; if (front == nullptr) { rear = nullptr; } return data; } T peek() { if (front == nullptr) { throw std::out_of_range("Queue is empty"); } return front->data; } bool isEmpty() { return (front == nullptr); } int getSize() { return size; } }; ``` 该队列使用泛型类型 T 来表示队列中的元素,可以存储任意类型的数据。队列内部使用链式存储结构来实现,每个节点包含一个元素和指向下一个节点的指针。队列的基本操作包括入队、出队、查看队首元素、判断队列是否为空、获取队列的大小。在入队时,如果队列为空,则新节点成为队列的首节点;否则,将新节点添加到队列尾部。在出队时,如果队列不为空,则返回队列的首节点元素,并删除该节点;否则,抛出队列为空的异常。在查看队首元素时,如果队列不为空,则返回队列的首节点元素;否则,抛出队列为空的异常。在判断队列是否为空时,如果队列为空,则返回 true;否则,返回 false。在获取队列的大小时,返回队列中元素的个数。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值