通用链表LinkList用例-可用demo

本文是一个单向链表的通用demo,可以用在数据结构的使用

一、链表的特性
二、链表的操作类型
三、通用链表的测试用例
四、使用makefile测试

一、链表的特点
单向链表是利用动态内存分布、使用结构体并配合指针来实现的一种数据结构。相比于数组,单向链表进行数据插入和删除的操作更为简单,但是,调取链表中的元素,只能一个个去访问寻找,不能直接通过位置,一步得到。

二、链表的操作类型

  1. 创建链表
    LinkList* LinkList_Create();

  2. 销毁链表
    void LinkLisk_Destroy(LinkList* list);

  3. 清除链表
    void LinkList_Clear(LinkList* list);

  4. 插入节点
    int LinkList_Insert(LinkList* list, int pos, LinkListNode* node);

  5. 删除节点
    int LinkList_Delete(LinkList* list, int pos);

  6. 获取节点
    TLinkListNode* LinkList_Get(LinkList* list, int pos);

  7. 获取链表长度
    int LinkList_Length(LinkList* list);

首先我们定义一下LinkList的类型:

typedef void LinkList;

这里将LinkList定义为void是为了通用性,适合任何数据类型。

另外我们还要定义一下节点类型,同样为了通用性,将其定义为void类型:

typedef void TLinkListNode; //这里是返回给调用者用的,所以调用者不需要关注类型,由链表封装实现

而链表真正使用的节点类型定义为:

typedef struct _tagLinkListNode LinkListNode;

struct _tagLinkListNode
{
	void* value;
	LinkListNode* next;	
};

可以看到链表节点由一个void类型的指针和指向下一个节点的指针构成,value用于存储数据,next指向下一个节点的地址

最后定义一下链表的头部,因为一个链表是由头部开始的:

typedef struct _tagheadernode
{
	int length;
	LinkListNode* header;
}TLinkList;

可以看到链表头部由长度length和指向第一个节点的头部header构成。

接下来我们具体看一下链表每一个操作是如何实现的:

  1. 创建链表
    LinkList* LinkList_Create();
LinkList* LinkList_Create()
{
	TLinkList* mlinklist = (TLinkList*)malloc(sizeof(TLinkList));
	if(mlinklist != NULL)
	{
		mlinklist->length = 0;
		mlinklist->header = (LinkListNode*)(((int*)&(mlinklist->length))+2);
		printf("create link list succeed\n");
	}
	return mlinklist;
}

首先分配内存,如果分配成功,将长度设置为0,并获取header的值

  1. 销毁链表
    void LinkLisk_Destroy(LinkList* list);
void LinkLisk_Destroy(LinkList* list)
{
	TLinkList* mlinklist = (TLinkList*)list;
	if(mlinklist != NULL)
	{
		mlinklist->header = NULL;
		mlinklist = NULL;
		printf("link list destroy succeed\n");	
	}
	return;
}

销毁链表将header设置成NULL,将list设置成NULL

  1. 清除链表
    void LinkList_Clear(LinkList* list);
void LinkList_Clear(LinkList* list)
{
	TLinkList* mlinklist = (TLinkList*)list;
	if(mlinklist != NULL)
	{
		mlinklist->length = 0;
		free(mlinklist);
		printf("link list clear succeed\n");	
	}
	return;
}

清除链表将length设置成0,并释放内存

  1. 插入节点
    int LinkList_Insert(LinkList* list, int pos, LinkListNode* node);
int LinkList_Insert(LinkList* list, int pos, LinkListNode* node)
{
	int insert = 1;
	int i = 0;
	int ret = -1;
	
	TLinkList* mlinklist = (TLinkList*)list;
	insert = insert && (mlinklist != NULL) && (pos <= mlinklist->length) && (node != NULL);
	LinkListNode* mnode = (LinkListNode*)malloc(sizeof(LinkListNode));
	insert = insert && (mnode != NULL);
	
	printf("insert node addr = %x\n", node);
	if(insert)
	{
		if(mlinklist->length == 0)
		{
			mnode->value = (LinkListNode*)node;
			mnode->next = NULL;
			mlinklist->header->next = mnode;
			mlinklist->length++;
		}
		else
		{
			LinkListNode* current = mlinklist->header;
			for(i=0; i<pos && current->next != NULL; i++)
			{
				current = current->next;	
			}
			mnode->value = (LinkListNode*)node;
			mnode->next = current->next;
			current->next = mnode;
			mlinklist->length++;
		}
		ret = 0;
	}
	return ret;
}

插入节点分两种情况,一种是链表长度为0,一种是不为0,为0的时候直接将node传给value,并让头部的next指向该节点,不为0的时候要找到pos的地方,然后将节点插在pos的地方。

  1. 删除节点
    int LinkList_Delete(LinkList* list, int pos);
int LinkList_Delete(LinkList* list, int pos)
{
	//bool delete = true;
	int i = 0;
	int Ret = -1;
	
	TLinkList* mlinklist = (TLinkList*)list;
	//delete = delete && (mlinklist != NULL) && (pos <= mlinklist->length) && (mlinklist->length != 0);
	LinkListNode* ret = NULL;

	if((mlinklist != NULL) && (pos <= mlinklist->length) && (mlinklist->length != 0))
	{
		LinkListNode* current = mlinklist->header;
		for(i=0; i<pos && current->next != NULL; i++)
		{
			current = current->next;	
		}
		if(mlinklist->length == 1)
		{
			free(current->next);
			current->next = NULL;
			mlinklist->length = 0;
		}
		else
		{
			ret = current->next;
			current->next = ret->next;
			free(ret);
			ret = NULL;
			mlinklist->length--;
		}
		Ret = 0;
	}
	return Ret;
}

删除节点同样分为链表长度为1和不为1的情况进行删除

  1. 获取节点
    TLinkListNode* LinkList_Get(LinkList* list, int pos);
TLinkListNode* LinkList_Get(LinkList* list, int pos)
{
	int get = 1;
	int i = 0;
	TLinkList* mlinklist = (TLinkList*)list;
	get = get && (mlinklist != NULL) && (pos <= mlinklist->length) && (mlinklist->length != 0);
	TLinkListNode* ret = NULL;
	if(get)
	{
		LinkListNode* current = mlinklist->header;
		for(i=0; i<pos && current->next != NULL; i++)
		{
			current = current->next;	
		}
		ret = current->next->value;
		printf("get node addr = %x\n", ret);
	}
	return ret;
}

获取节点首先找到pos对应的节点,然后将value返回

  1. 获取链表长度
    int LinkList_Length(LinkList* list);
int LinkList_Length(LinkList* list)
{
	int ret = -1;
	TLinkList* mlinklist = (TLinkList*)list;
	if(mlinklist != NULL)
		ret = mlinklist->length;
	return ret;
}

直接返回length

三、通用链表的测试用例

#include<stdio.h>
#include"LinkList.h"

void main()
{
	int i = 0;
	int array[8] = {1,2,3,4,5,6,7,8};
	
	LinkList* list = LinkList_Create();
	
	for(i=0; i<(sizeof(array)/sizeof(int)); i++)
	{
		LinkList_Insert(list, LinkList_Length(list), (LinkListNode*)&array[i]);
	}
	for(i=0; i<(sizeof(array)/sizeof(int)); i++)
	{
		printf("%d\n", *((int*)LinkList_Get(list, i)));
	}
	while(LinkList_Length(list) > 0)
	{
		LinkList_Delete(list, 0);
	}
	LinkList_Clear(list);
	LinkLisk_Destroy(list);
}

测试用例将数组的值每一个插入链表,然后获取出来,然后删除每一个节点,清除链表,最后销毁链表

四、使用makefile测试

CC = gcc
CFLAGS = -g -Wall -O
main:main.o LinkList.o
	$(CC) $^ -o $@
%.o:%.c
	$(CC) $(CFLAGS) -c $^
clean:
	rm -rf main.o LinkList.o main

测试结果:
在这里插入图片描述

所有代码和测试用例见:https://download.csdn.net/download/yjlyyj/85520754

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值