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号元素

相关推荐
KpLn_HJL28 分钟前
leetcode - 2139. Minimum Moves to Reach Target Score
java·数据结构·leetcode
AC使者6 小时前
5820 丰富的周日生活
数据结构·算法
无 证明7 小时前
new 分配空间;引用
数据结构·c++
别NULL11 小时前
机试题——疯长的草
数据结构·c++·算法
ZSYP-S12 小时前
Day 15:Spring 框架基础
java·开发语言·数据结构·后端·spring
唐叔在学习13 小时前
【唐叔学算法】第21天:超越比较-计数排序、桶排序与基数排序的Java实践及性能剖析
数据结构·算法·排序算法
ALISHENGYA13 小时前
全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之分支结构(switch语句)
数据结构·算法
武昌库里写JAVA16 小时前
浅谈怎样系统的准备前端面试
数据结构·vue.js·spring boot·算法·课程设计
S-X-S16 小时前
代码随想录刷题-数组
数据结构·算法
l1384942745116 小时前
每日一题(4)
java·数据结构·算法