前期考虑
队列是两边都有开口,那么在链式情况下,线性表的链式那一边作为对头好呢?
从线性表的核心的插入和删除算法来看,如果在线性表链表的头部插入,每次循环都不会走,但是删除的时候,要删除线性表的尾部,要遍历整个 线性表。
都差不多。
我们考虑到在插入的时候,可能是批量插入,删除只是在某些条件成立的情况下才会删除,因此会将 线性表的头部做为 队列的头部,将线性表的尾部做为队列的尾部。
插入算法 核心代码
//正式插入数据,
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号元素