C语言实现单向链表

单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。

所谓单链表,是指数据接点是单向排列的。一个单链表结点,其结构类型分为两部分: 1、数据域:用来存储本身数据 2、链域或称为指针域:用来存储下一个结点地址或者说指向其直接后继的指针。

代码实现如下:

注意:

以下代码的实现包含了链表的头指针,而链表本身并没有首部节点,也就是头指针直接指向了第一个真正有数据的节点。如下图所示:

所谓头指针,就是指向第一个节点指针的指针,如果第一个节点是ListNode* list,那么实际应用中可以用&list的方式来标识头指针,说起来有点绕,看代码:

1.头文件 list.h

#include <stdio.h>  
#include <assert.h>  
#include <windows.h>  
#include <malloc.h>  

//定义数据类型,假设为int
typedef int DataType;  
//定义自引用结构体(结点)
typedef struct ListNode  
{  
    DataType data;  
    struct ListNode* next;  
}ListNode;  

ListNode* CreatNode(DataType x);//创建一个节点  
void PrintList(ListNode* plist);//遍历并打印链表  
void InsertNodeTail(ListNode** head,DataType x);//在链表最后的位置插入一个节点  
void DeleteNodeTail(ListNode** head);//删除链表最后一个节点  
void InsertNodeHead(ListNode** head,DataType x);//在链表最前面插入一个节点 
void DeleteNodeHead(ListNode** head);//删除链表最前面的一个节点  
ListNode* FindNode(ListNode* plist,DataType x);//查找一个节点  
void InsertNodePos(ListNode** head,ListNode* pos,DataType x);//在pos的前面插入一个节点  
void DeleteNodePos(ListNode** head,ListNode* pos);//删除指定的pos节点

2.函数实现 list.c

#include "list.h"

/**
 * 创建一个节点,注意不是创建链表
 * @DataType x 节点的数据
 * @return ListNode 返回该节点的指针
 */
ListNode* CreatNode(DataType x)//创建一个节点
{
    ListNode* Node = (ListNode *)malloc(sizeof(ListNode)) ;
    Node->data = x ;
    Node->next = NULL ;
    return Node;
}
/**
 * 遍历链表并打印输出数据
 * @ListNode *plist 需要遍历的链表的表头节点(第一个节点),注意不是头指针
 */
void PrintList(ListNode* plist)
{
    ListNode* cur = plist ;
    while(cur)
    {
        printf("%d->",cur->data);
        cur = cur->next ;
    }
    printf("NULL\n");
}
/**
 * 在链表最后的位置插入一个节点(尾插)
 * @ListNode ** head 需要遍历的链表的头指针,头指针指向了第一个节点
 * @DataType x 要插入的该节点的数据
 */
void InsertNodeTail(ListNode** head,DataType x)
{
    // 1 2 3 4
    //1.链表为空
    //2.一个
    //3.多个
    if(*head == NULL)
    {
        *head = CreatNode(x) ;
    }
    else if((*head)->next == NULL)
    {
        (*head)->next = CreatNode(x);
    }
    else
    {
        ListNode* cur = *head ;
        while( cur->next )
        {
            cur = cur->next ;
        }
        cur->next = CreatNode(x);
    }
}
/**
 * 删除链表最后一个节点
 * @ListNode ** head 需要遍历的链表的头指针
 */
void DeleteNodeTail(ListNode** head)
{
    //1.空链表
    //2.一个节点
    //3.多个节点
    if(*head == NULL)
    {
        return;
    }
    else if((*head)->next == NULL)
    {
        free(*head);
        *head = NULL;
    }
    else
    {
        ListNode* cur = *head;
        ListNode* pos = *head;
        while(cur->next)
        {
            pos = cur;
            cur = cur->next ;
        }
        free(cur);
        cur = NULL;
        pos->next = NULL;
    }
}
/**
 * 在链表最前面的位置插入一个节点(头插)
 * @ListNode ** head 需要遍历的链表的头指针
 * @DataType x 要插入的该节点的数据
 */
void InsertNodeHead(ListNode** head,DataType x)
{/*
    1.空链表
    2.非空*/
    if(*head == NULL)
    {
        *head = CreatNode(x);
    }
    else
    {
        ListNode* tmp = CreatNode(x);
        tmp->next = *head;
        *head = tmp;
    }
}
/**
 * 删除链表最前面一个节点
 * @ListNode ** head 需要遍历的链表的头指针
 */
void DeleteNodeHead(ListNode** head)
{
    /*1.空链表
    2.一个节点
    3.多个节点*/
    if(*head == NULL)
    {
        return;
    }
    else if((*head)->next == NULL )
    {
        DeleteNodeTail(head);
    }
    else
    {
        ListNode* next = (*head)->next ;
        free(*head);
        *head = next;
    }
}
/**
 * 查找一个数据为x的节点
 * @ListNode * plist 需要遍历的链表的第一个节点
 * @DataType x 要查找的该节点的数据
 * @return ListNode* 返回该节点的指针
 */
ListNode* FindNode(ListNode* plist,DataType x)//查找一个节点0 1 2 3 4 
{
    while(plist)
    {
        if(plist->data == x)
        {
            return plist;
        }
        plist = plist->next ;
    }
    return NULL;
}
                                                                         /**
 * 在pos节点的前面插入一个节点
 * @ListNode ** head 需要遍历的链表的头指针
 * ListNode* 某一个已存在的节点
 * @DataType x 要查找的该节点的数据
 */
void InsertNodePos(ListNode** head,ListNode* pos,DataType x)
{
    assert(head&&pos);
    /*1.如果pos是头结点,则是头插
    2.pos是其他节点*/
    if(pos == *head)
    {
        InsertNodeHead(head,x);
    }
    else
    {
        ListNode* tmp = NULL;
        ListNode* prev = *head;
        while(prev->next != pos)
        {
            prev = prev->next ;
        }
        tmp = CreatNode(x);
        prev->next = tmp;
        tmp->next = pos;
    }
}
/**
 * 删除某一个pos节点
 * @ListNode ** head 需要遍历的链表的头指针
 * ListNode* 某一个已存在的节点
 */
void DeleteNodePos(ListNode** head,ListNode* pos)//删除pos节点 
{
    assert(head&&pos);
    /*1.头删
    2.尾删
    3.中间删1 2 3 4  删除3*/
    if(pos == *head)
    {
        DeleteNodeHead(head);
    }
    else if(pos->next == NULL)
    {
        DeleteNodeTail(head);
    }
    else
    {
        ListNode* prev = *head ;
        while(prev->next != pos)
        {
            prev = prev->next ;
        }
        prev->next = pos->next ;
        free(pos);
        pos = NULL;
    }

}

3.测试函数 test.c

#include "list.h"

void test1()
{
    //声明链表的第一个节点,指向NULL,相当于创建了一个空链表
    ListNode* list = NULL;
//测试尾插
    InsertNodeTail(&list,0);
    InsertNodeTail(&list,1);
    InsertNodeTail(&list,2);
    InsertNodeTail(&list,3);
    InsertNodeTail(&list,4);
    PrintList(list);

//测试尾删
    DeleteNodeTail(&list);
    PrintList(list);
    DeleteNodeTail(&list);
    DeleteNodeTail(&list);
    DeleteNodeTail(&list);
    DeleteNodeTail(&list);
    DeleteNodeTail(&list);
    PrintList(list);
}

void test2()
{
    //声明链表的第一个节点,指向NULL,相当于创建了一个空链表
    ListNode* list = NULL;
//测试头插
    InsertNodeHead(&list,1);
    InsertNodeHead(&list,2);
    InsertNodeHead(&list,4);
    PrintList(list);
//测试头删
    DeleteNodeHead(&list);
    PrintList(list);     
    DeleteNodeHead(&list);
    DeleteNodeHead(&list);
    DeleteNodeHead(&list);
    DeleteNodeHead(&list);
    DeleteNodeHead(&list);     
    PrintList(list);
}

void test3()
{
    //声明链表的第一个节点,指向NULL,相当于创建了一个空链表
    ListNode* list = NULL;
    //声明链表的某个位置节点
    ListNode* pos;
    InsertNodeHead(&list,0);
    InsertNodeHead(&list,1);
    InsertNodeHead(&list,2);
    InsertNodeHead(&list,4);
    PrintList(list);
//测试查找函数
    pos = FindNode(list,2);
//测试在pos位置前面插入x
    Insert(&list,pos,3);
    PrintList(list);
//测试删除pos位置的节点
    pos = FindNode(list,4);
    DeleteNodePos(&list,pos);
    PrintList(list);//头删

    pos = FindNode(list,0);
    DeleteNodePos(&list,pos);
    PrintList(list);//尾删

    pos = FindNode(list,2);
    DeleteNodePos(&list,pos);
    PrintList(list);//中间删除
}

int main()
{
    test3();
    return 0;
}