单向链表设计与实现
链式存储的基本介绍
链式存储定义: 为了表示每个数据元素与其直接后继元素之间的逻辑关系,每个元素除了存储本身信息外,还需要存储指示其直接后继的信息。
- 表头结点: 链表中第一个结点,包含指向第一个数据匀速的指针,以及链表自身的一些信息。
- 数据结点: 链表中代表数据元素的结点,包含指向下一个数据元素的指针和信息。
- 尾结点 : 链表中最后一个数据结点,其下一个元素指针为空表表示无后继结点。
链表的种类
- 传统链表
- 非传统链表(linux内核链表)
单链表的设计
定义一个结构体指针用来存储指针与指针之间的关系:
typedef struct _tag_LinkListNode
{
struct _tag_LinkListNode *next;
}LinkListNode;
定义一个头结点用来存储链表:
typedef struct _tag_LinkList
{
LinkListNode *header;
int length;
}TLinkList;
数据元素定义实例:
struct Value
{
LinkListNode node;
int v;
};
单向链表的重要算法
- 单向链表的插入算法
- 插入前
- 插入后
- 插入前
- 单向链表的删除算法
- 删除前
- 删除后
- 删除前
单向链表的优缺点
- 优点:
- 无需一次性定制链表的容量
- 插入和删除操作无需移动数据
- 缺点:
- 数据元素必须保存后继元素的位置信息
- 获取指定数据元素操作需要访问之间的元素
单向链表的实现
LinkList.h
#ifndef _LINKLIST_H_
#define _LINKLIST_H_
typedef void LinkList;
typedef struct _tag_LinkListNode
{
struct _tag_LinkListNode *next;
}LinkListNode;
//创建链表
LinkList *LinkList_Create();
//销毁链表
void LinkList_Destroy(LinkList *list);
//清空链表
void LinkList_Clear(LinkList *list);
//获取链表的长度
int LinkList_Length(LinkList *list);
//向链表中第pos个位置插入node节点
int LinkList_Insert(LinkList *list, int pos, LinkListNode *node);
//获取链表第pos个位置节点
LinkListNode *LinkList_Get(LinkList *list, int pos);
//删除链表第pos个位置节点
LinkListNode *LinkList_Delete(LinkList *list, int pos);
#endif //LinkList
- LinkList.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "LinkList.h"
typedef struct _tag_LinkList
{
LinkListNode *header;
int length;
}TLinkList;
//创建链表
LinkList *LinkList_Create()
{
TLinkList *ret = NULL;
ret = (TLinkList *)malloc(sizeof(TLinkList));
if (ret == NULL)
{
printf("func LinkList_Create() err\n");
return ret;
}
memset(ret, 0, sizeof(ret));
ret->length = 0;
ret->header = NULL;
return ret;
}
//销毁链表
void LinkList_Destroy(LinkList *list)
{
if (list != NULL)
{
free(list);
return ;
}
return ;
}
//清空链表
void LinkList_Clear(LinkList *list)
{
TLinkList *tlist = NULL;
if (list == NULL)
{
return;
}
tlist = (TLinkList *)list;
tlist->length = 0;
tlist->header= NULL;
return ;
}
//获取链表的长度
int LinkList_Length(LinkList *list)
{
int ret;
TLinkList *tlist = NULL;
if (list == NULL)
{
ret = -1;
printf("func LinkList_Length() err: %d\n", ret);
return ret;
}
tlist = (TLinkList *)list;
return tlist->length;
}
//向链表中第pos个位置插入node节点
int LinkList_Insert(LinkList *list, int pos, LinkListNode *node)
{
int ret = 0, i = 0;
TLinkList *tlist = NULL;
LinkListNode *Current = NULL;
//①判断线性表是否合法
if (list == NULL || pos < 0 || node == NULL)
{
ret = -1;
printf("func LinkList_Insert() (list == NULL || pos < 0 || node == NULL) err:%d\n", ret);
return ret;
}
tlist = (TLinkList *)list;
//②判断插入位置是否合法
if (pos > tlist->length)
{
ret = -2;
printf("func LinList_Insert() (pos > tlist->length) err: %d\n", ret);
return ret;
}
//③插入节点
Current = &(tlist->header);
for (i = 0; i < pos&&(Current->next!=NULL); i++) //找到pos位置的前一个节点
{
Current = Current->next;
}
node->next = Current->next; //用node节点连接pos位置的后一个节点
Current->next = node; //用pos位置前一个节点连接node的节点
//④线性表长度加一
tlist->length++;
return ret;
}
//获取链表第pos个位置节点
LinkListNode *LinkList_Get(LinkList *list, int pos)
{
int i = 0, ret = 0;
TLinkList *tlist = NULL;
LinkListNode *Current = NULL;
//①判断线性表是否合法
if (list == NULL || pos < 0)
{
ret = -1;
printf("func LinkList_Get() (list == NULL || pos < 0) err: %d\n", ret);
return NULL;
}
tlist = (LinkList *)list;
//②判断插入位置是否合法
if (pos > tlist->length)
{
ret = -2;
printf("func LinkList_Get() (pos > tlist->length) err: %d\n",ret);
return NULL;
}
//③找到第pos位的节点
Current = &(tlist->header);
for (i = 0; i < pos && (Current->next != NULL); i++)
{
Current = Current->next;
}
return Current->next;
}
//删除链表第pos个位置节点
LinkListNode *LinkList_Delete(LinkList *list, int pos)
{
int i = 0, ret = 0;
TLinkList *tlist = NULL;
LinkListNode *Current = NULL, *tmp = NULL;
//线性表是否合法
if (list == NULL || pos < 0)
{
ret = -1;
printf("func LinkList_Get() (list == NULL || pos < 0) err: %d\n",ret);
return NULL;
}
tlist = (TLinkList *)list;
//②判断插入位置是否合法
if (pos > tlist->length)
{
ret = -2;
printf("func LinkList_Get() (pos > tlist->length) err:%d\n",ret);
return NULL;
}
//③删除节点
Current = &(tlist->header);
for (i = 0; i < pos && (Current->next != NULL); i++)//找到pos位置的前一个节点
{
Current = Current->next;
}
tmp = Current->next; //保存pos位置节点
Current->next = tmp->next; //pos位置的前一个节点连接pos位置的后一个节点
//④线性表长度减一
tlist->length--;
return tmp;
}
- LinkList集成测试框架
#define _CRT_SECURE_NO_WARNINGS
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include "LinkList.h"
typedef struct Teacher
{
LinkListNode node;//(用于与其他节点产生联系)
int age;
char name[64];
}Teacher;
void main()
{
int len = 0, ret = 0, i = 0;
LinkList *list = NULL;
Teacher t1, t2, t3, t4, t5;
t1.age = 11;
strcpy(t1.name, "t1");
t2.age = 22;
strcpy(t2.name, "t2");
t3.age = 33;
strcpy(t3.name, "t3");
t4.age = 44;
strcpy(t4.name, "t4");
t5.age = 55;
strcpy(t5.name, "t5");
list = LinkList_Create(); //创建链表
if (list == NULL) //判断链表是创建成功
{
printf("func LinkList_Create() err:\n");
return;
}
ret = LinkList_Insert(list, 0, (LinkListNode *)&t1); //在插入节点
if (ret != 0) //判断节点是否成功插入
{
printf("func LinkList_Insert() err: %d\n",ret);
return;
}
ret = LinkList_Insert(list, 1, (LinkListNode *)&t2); //在插入节点
if (ret != 0) //判断节点是否成功插入
{
printf("func LinkList_Insert() err: %d\n",ret);
return;
}
ret = LinkList_Insert(list, 2, (LinkListNode *)&t3); //在插入节点
if (ret != 0) //判断节点是否成功插入
{
printf("func LinkList_Insert() err: %d\n",ret);
return;
}
ret = LinkList_Insert(list, 3, (LinkListNode *)&t4); //在插入节点
if (ret != 0) //判断节点是否成功插入
{
printf("func LinkList_Insert() err: %d\n",ret);
return;
}
ret = LinkList_Insert(list, 4, (LinkListNode *)&t5); //在插入节点
if (ret != 0) //判断节点是否成功插入
{
printf("func LinkList_Insert() err: %d\n",ret);
return;
}
len = LinkList_Length(list); //获取链表长度
printf("The length of list is:%d\n", len);
for(i=0;i<LinkList_Length(list);i++) //获取链表中的所有元素
{
Teacher *tmp = NULL;
tmp = (Teacher *)LinkList_Get(list, i); //获取链表第i个位置的节点
if (tmp == NULL) //判断获取节点是否成功
{
printf("func LinkList_Get() err\n");
return;
}
printf("tmp->name:%s,tmp->age:%d\n", tmp->name, tmp->age);
}
while (LinkList_Length(list)) //删除链表中的所有元素
{
Teacher *tmp = NULL;
tmp = (Teacher *)LinkList_Delete(list, 0); //删除链表第一个位置节点
if (tmp == NULL) //判断删除节点是否成功
{
printf("func LinkList_Delete() err\n");
return;
}
printf("tmp->name:%s,tmp->age:%d\n", tmp->name, tmp->age);
}
len = LinkList_Length(list); //获取链表长度
printf("The length of list is:%d\n", len);
LinkList_Clear(list); //清空链表
LinkList_Destroy(list); //销毁链表
return;
}