通用单向链表的实现(附使用例子)

当我打开csdn,发现我有第一个粉丝了,激动得差点大喊“Hello World”,整晚都很开心,哈哈,为了保住我唯一的粉丝,我决定,以后勤快一点。今天就先出一篇通用链表实现的博客,只包含了一个头文件(.h)和一个源文件(.c),可以很方便地添加到你们的项目中。

list.h:

#ifndef __LIST_H__
#define __LIST_H__

#define LIST_NO_MEM  -2
#define LIST_ERROR   -1
#define LIST_SUCCESS  0

typedef struct _node node_t;
/*node*/
struct _node{
    node_t *next;       //next node
    void *element;      //pointer of elt
};

/*list*/
typedef struct _list{
    int nb_elt;        //number of element of list
    node_t *node;      //head pointer
}list_t;

/*initialise the list,the list shouldn't be null*/
int list_init(list_t *list);

/*get the size of a list of element*/
int list_size(const list_t *list);

/*add a element to list*/
int list_add(list_t *list,void *element,int pos);

/*get an element from a list*/
void *list_get(const list_t *list,int pos);

/*remove an element from a list*/
int list_remove(list_t *list,int pos);

#endif

 

list.c

#include "list.h"
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
int list_init(list_t *list)
{
    if(list == NULL)
        return LIST_ERROR;
    memset(list,0,sizeof(list_t));
    return LIST_SUCCESS;
}

int list_size(const list_t *list)
{
    if(list == NULL)
        return LIST_ERROR;
    return list->nb_elt;
}

/*index start from 0*/
int list_add(list_t *list,void *element,int pos)
{
    int i = 0;
    node_t *new_node = NULL;
    node_t *node = NULL;
    if(list == NULL)
        return LIST_ERROR;
    
    new_node = (node_t*)malloc(sizeof(node_t));
    if(new_node == NULL)
        return LIST_NO_MEM;
    memset(new_node,0,sizeof(node_t));
    new_node->element = element;

    if(list->nb_elt == 0)
    {
        new_node->next = NULL;
        list->node = new_node;
        list->nb_elt++;
        return list->nb_elt;
    }
    if(pos < 0 || pos >= list->nb_elt)
        pos = list->nb_elt;

    node = list->node;
    
    if(pos == 0)
    {
        new_node->next = list->node;
        list->node = new_node;
        list->nb_elt++;
        return list->nb_elt;
    }

    while(i + 1 < pos)
    {
        i++;
        node = node->next;
    }
    if(pos == list->nb_elt)
    {
        new_node->next = NULL;
        node->next = new_node;
        list->nb_elt++;
        return list->nb_elt;
    }
    new_node->next = node->next;
    node->next->next = new_node;
    list->nb_elt++;
    
    return list->nb_elt;
}

void *list_get(const list_t *list,int pos)
{
    int i = 0;
    node_t *node = NULL;
    if(list == NULL)
        return NULL;
    if(pos < 0 || pos >= list->nb_elt)
        return NULL;
    node = list->node;
    while(i < pos)
    {
        i++;
        node = node->next;
    }
    
    return node->element;
}

int list_remove(list_t *list,int pos)
{
    int i = 0;
    node_t *node = NULL;
    node_t *del_node = NULL;
    if(list == NULL)
        return LIST_ERROR;
    if(pos < 0 || pos >= list->nb_elt)
        return LIST_ERROR;
    node = list->node;
    /*special case*/
    if(pos == 0)
    {
        list->node = node->next;
        list->nb_elt--;
        free(node);
        return LIST_SUCCESS;
    }

    while(pos > i + 1)
    {
        i++;
        node = node->next;
    }
    del_node = node->next;
    node->next = node->next->next;
    list->nb_elt--;

    free(del_node);
    return LIST_SUCCESS;
    
}
#include <stdlib.h>
#include <stdio.h>
#include "list.h"


int main()
{
	int size = 0;
	int i = 0;
	list_t list;
	char *elt;
	list_init(&list);
	char arr1[5] = "hello";
	char arr2[5] = "world";
	char arr3[32] = "i'm pumpkin monkey";
	list_add(&list,(void*)arr1,-1);
	list_add(&list,(void*)arr2,-1);
	list_add(&list,(void*)arr3,-1);
	printf("list size:%d\n",list_size(&list));
	list_remove(&list,1);
	size = list_size(&list);
	printf("list size:%d\n",size);
	for(i = 0;i<size;i++)
	{
		elt = (char*)list_get(&list,i);
		if(elt == NULL)
		{
			printf("get null node\n");
		}
		printf("elment :%s\n",elt);
	}
	return 0;
}

以上就是最基本的通用单向链表的实现,包含了创建、添加、删除、长度、获取等最常用的基本功能。还可以包含克隆,下个元素、等其他功能,可根据需要自己添加

实际上链表并不复杂,但是很多人还是没法写好,主要还是特殊情况(边界条件)考虑得不够充分。不仅是在链表,在任何一个函数的实现里,都必须要考虑特殊场景。对于链表来说,其实需要注意的也就那几个点,目标节点(pos)是否存在、链表长度为0和pos刚好等于链表长度、输入链表是否有效、循环条件。

大家可以考虑加个头结点:

数据结构中,在单链表的开始结点之前附设一个类型相同的结点,称之为头结点。头结点的数据域可以不存储任何信息,头结点的指针域存储指向开始结点的指针(即第一个元素结点的存储位置)。

头结点作用:

1、防止单链表是空的而设的.当链表为空的时候,带头结点的头指针就指向头结点.如果当链表为空的时候,单链表没有带头结点,那么它的头指针就为NULL.

2、是为了方便单链表的特殊操作,插入在表头或者删除第一个结点.这样就保持了单链表操作的统一性!

3、单链表加上头结点之后,无论单链表是否为空,头指针始终指向头结点,因此空表和非空表的处理也统一了,方便了单链表的操作,也减少了程序的复杂性和出现bug的机会。

4、对单链表的多数操作应明确对哪个结点以及该结点的前驱。不带头结点的链表对首元结点、中间结点分别处理等;而带头结点的链表因为有头结点,首元结点、中间结点的操作相同 ,从而减少分支,使算法变得简单 ,流程清晰。对单链表进行插入、删除操作时,如果在首元结点之前插入或删除的是首元结点,不带头结点的单链表需改变头指针的值,在C 算法的函数形参表中头指针一般使用指针的指针(在C+ +中使用引用 &);而带头结点的单链表不需改变头指针的值,函数参数表中头结点使用指针变量即可。

 

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值