数据结构—单向链表(详解)

一、链表基础

链表是一种常见的数据结构,其中运用到了结构体指针,链表可以实现动态存储分配,换而言之,链表是一个功能强大的数组,可以在某个节点定义多种数据类型,可以实现任意的添加,删除,插入节点等。链表分为两类,一种是有头节点的链表,另一种是无头节点的链表。头节点没有数据域的,其他每个节点都有两部分,一是数据域,二是指针域。下面对单向链表进行详细介绍。
操作包括:链表的创建、修改、删除、插入等。最后以一个在嵌入式的应用结束。

1、有头结点的单向链表

1、链表定义
typedef struct node_st
{
    datatype data;
    struct node_st *next;
}list;
2、链表创建
/**
  * @brief  链表的创建
  * @param  无
  * @retval 返回创建成功的链表首地址
  */
list* list_creat()
{
    /*创建一个带头节点的单链表*/
    list *me;
    /*分配内存空间*/
    me = malloc(sizeof(*me));
    if (me == NULL)
        return NULL;
    /*数据域不管,指针域设置为空指针*/
    me->next = NULL;
    return me;
}

3、链表插入

链表插入是找到待插入节点位置的前驱结点

/**
  * @brief  链表的位置插入
  * @param  链表名称,插入位置,插入数据
  * @retval 返回0表示插入成功
  */
int list_insert_at(list *me,int i,datatype *data)
{
    int j = 0;
    /*创建一个链表,存放me*/
    list *node = me,*newnode;
    /*如果插入位置小于0,返回错误*/
    if (i<0)return -1;
    /*node指针一个个向后找,直到找到了某一个节点*/
    while (j<i&& node != NULL)
    {
        node = node->next;
        j++;
    }
    /*如果node指针不为空,表示找到一个有效位置作为插入,获得的是待插入位置的前驱节点*/
    /*单向链表只能单向移动,找不到后继节点的前驱指针*/
    if (node)
    {
        newnode = malloc(sizeof(*newnode));
        if (newnode == NULL)
            return -2;
        /*使用新的newnode存放需要插入的数据*/
        newnode->data = *data;
        /*首先设置指针为空*/
        newnode->next = NULL;
        /*新节点的next指针等于旧节点的next指针(旧节点的后继节点)*/
        newnode->next = node->next;
        /*旧节点的next指向新节点的本身*/
        node->next = newnode;
        return 0;   
    }
    /*表示第i个位置是不合法的*/
    else
        return -3;
} 

4、链表遍历
/**
  * @brief  链表的遍历
  * @param  链表指针
  * @retval 返回为空
  */
void list_display(list*me)
{
    list *node = me->next;
    /*如果链表为空,返回*/
    if(list_isempty(me) == 0)
    {
        return;
    }
    /*链表不为空,打印链表数据*/
    while (node!=NULL)
    {
        printf("%d ",node->data);
        node = node->next;
    }
    printf("\n");
    return ;
}
5、链表顺序插入

链表插入是找到待插入节点位置的前驱结点

/**
  * @brief  链表的顺序插入
  * @param  链表指针,待插入数据
  * @retval 返回插入状态
  */
int list_order_insert(list *me,datatype *data)
{
    list *p = me,*q;
    /*p插入节点的前驱位置*/
    while (p->next && p->next->data<*data)
    		/*继续向后移动*/
        p = p->next;
        /*申请内存空间*/
        q = malloc(sizeof(*q));
        if (q == NULL)
            return -1;
        /*存放数据*/
        q->data = *data;
        /*插入数据*/
        q->next = p->next;
        /*插入成功*/
        p->next = q;
        return 0;
}
6、链表指定位置删除

指定位置删除是找到待删除节点位置的前驱结点

/**
  * @brief  链表的位置删除
  * @param  链表指针,待删除位置,待删除数据
  * @retval 返回删除状态
  */
int list_delete_at(list*me,int i,datatype *data)
{
   int j = 0;
   list *p = me,*q;
   /*初始化设置数据为-1,观察返回值的状态*/
    *data = -1;
   /*删除位置错误*/
   if (i<0)
   {
       return -1;
   }
  /*当j<i,并且p不为空,一直向后找*/ 
   while (j<i&&p)
   {
       p = p->next;
       j++;
   }
   /*当指针p不为空,表示找到了*/
   if (p)
   {
   		/* q指向p的后继节点 */
       q = p->next;
       /* p的后继节点指向q的后继节点 */
       p->next = q->next;
       *data = q->data;
       /*释放指针q*/
       free(q);
       q = NULL;
       return 0;
   }
   /*表示没有找到*/
   else
   {
       return -2;
   }
}
7、链表的数据删除

删除是找到待删除节点位置的前驱结点

/**
  * @brief  链表的数据删除
  * @param  链表指针,待删除数据
  * @retval 返回删除状态
  */
int list_delete(list *me,datatype *data)
{
    list *p = me,*q;
    /*一直寻找需要删除的数据,知道找到为止*/
    while (p->next && p->next->data != *data)
    {
        p=p->next;
    }
    if (p->next == NULL )
        return -1;
    else
    {
    		/*保存p的后继节点*/
        q = p->next;
        /*p的后继节点保存q的后继节点*/
        p->next = q->next;
        /*释放q*/
        free(q);
        q = NULL;
    }

}
8、判断链表是否为空
/**
  * @brief  判断链表释放为空
  * @param  链表指针
  * @retval 返回删除状态,0为空,1非空
  */
int list_isempty(list *me)
{
    if (me->next == NULL)    
        return 0;
    return 1;
}

9、链表的销毁
/**
  * @brief  链表的销毁
  * @param  链表指针
  * @retval 空
  */
void list_destory(list *me)
{
    list *node,*next;
    /* node 指向 me的后继节点,逐个释放node */
    for(node = me->next;node!=NULL;node = next)
    {
        next = node->next;
        free(node);
    }
    free(me);
    return;
} 
10、初始化有头链表示例
/*链表的创建*/
    list *l;
    int i,err;
    datatype arr[] = {12,9,23,2,34,6,45};
    l = list_creat();
    if (l == NULL)
    {
        exit(1);
    }
    /*链表的初始化*/
    for (i = 0; i < sizeof(arr)/sizeof(*arr); i++)
    {
       if(list_order_insert(l,&arr[i]))
       //if(list_insert_at(l,0,&arr[i]))
           exit(1);
    }

2、无头结点的单向链表

1、链表插入
/**
  * @brief  链表插入
  * @param  待插入数据
  * @retval 插入状态
  */
/*二级指针传参*/
int list_insert(struct node_st **list,struct score_st *data)
{
    struct node_st *new;
    /* 开辟内存空间并且判断*/
    new = malloc(sizeof(*new));
    if (new == NULL)
        return -1;
    /*新节点的数据保存*/
    new->data = *data;
    new->next = NULL;
	 /*找到并且保存list的指针*/
    new->next = *list;
    /* list 就是新节点 */
    *list = new;
    return 0;
}
2、链表删除
/**
  * @brief  链表删除第一个有效节点
  * @param  链表指针
  * @retval 删除状态
  */
int list_delete(struct node_st **list)
{
    struct node_st *cur;
    if (*list == NULL)
        return -1;
    /*保存当前节点*/
    cur = *list;
    /*当前节点指向下一个节点*/
    *list = (*list)->next;   
    free(cur);
    return 0;
}
3、链表查找
/**
  * @brief  链表查找
  * @param  链表,位置
  * @retval 链表指针
  */
struct score_st *list_find(struct node_st*list,int id)
{
    struct node_st *cur;
    /*循环查找,查看是否找到*/
    for (cur  = list; cur != NULL;cur = cur->next)
    {
         /*如果找到id*/
        if(cur->data.id == id)
                return &cur->data;
    }
    /*没有找到id,返回NULL*/
    return NULL;
}
4、链表销毁
/**
  * @brief  链表销毁
  * @param  链表指针
  * @retval 无
  */
void list_destory(struct node_st* list)
{
    struct node_st *cur;
    if (list == NULL)
       return;
    /*逐个释放*/
    for (cur = list;cur!= NULL;cur = list)
    {
        list = cur->next;
        free(cur);
    }
}
5、初始化无头链表示例
/*定义数据结构*/
struct score_st
{
    int id;
    char name[NAMESIZE];
    int math;
    int chinese;
};

struct  node_st
{
    struct score_st data;
    struct node_st *next;
};


/*初始化无头链表*/
    for ( i = 0; i < 7; i++)
    {
        tmp.id = i;
        snprintf(tmp.name,NAMESIZE,"std %d",i);
        tmp.math = rand()%100;
        tmp.chinese = rand()%100;
        ret = list_insert(&list,&tmp);  
        if (ret != 0)
           exit(1);
    }
  • 24
    点赞
  • 123
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值