线性表(List)---链式存储结构(单向链表)

单向链表设计与实现


链式存储的基本介绍

链式存储定义: 为了表示每个数据元素与其直接后继元素之间的逻辑关系,每个元素除了存储本身信息外,还需要存储指示其直接后继的信息。

链式存储结构定义

  • 表头结点: 链表中第一个结点,包含指向第一个数据匀速的指针,以及链表自身的一些信息。
  • 数据结点: 链表中代表数据元素的结点,包含指向下一个数据元素的指针和信息。
  • 尾结点 : 链表中最后一个数据结点,其下一个元素指针为空表表示无后继结点。

链表的种类

  • 传统链表
    传统链表
  • 非传统链表(linux内核链表)
    非传统链表(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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值