单向链表、单向循环链表的基本操作

本文详细介绍了如何在C语言中实现单向链表和单向循环链表的基本操作,包括定义节点结构体、创建节点、头插法、尾插法、遍历、检索指定数据节点、删除节点、任意位置添加和移动节点以及销毁链表的函数。每个操作都针对两种链表类型进行了区分和实现。
摘要由CSDN通过智能技术生成

(1)定义结点的结构体 

(2)创建的节点的函数

(3)头插法

(4)尾插法

(5)遍历单项向(循环)链表

(6)检索指定的数据节点

(7)删除指定的节点数据

(8)任意位置添加

(9)移动指定数据节点

(10)销毁链表


所有函数如下图所示:

 

(1)定义结点的结构体

有一个数据域和一个指针域,分别用来存放节点的数据,以及下一个的节点。单向链表和单向循坏链表的节点结构体式一样。

typedef struct list_link
{
    int data;
    struct list_link *next;

} list_node, *list_link;

 (2)创建的节点的函数

单向链表

list_link Create_List_Node();

list_link Create_List_Node()
{

    list_link node = (list_link)malloc(sizeof(list_node));
    if (node == (list_link)NULL)
    {
        perror("malloc list node ...");
        return (list_link)-1;
    }

    memset(node, 0, sizeof(list_node));

    node->next = NULL;

    return node;
}

单向循环链表

list_link Create_List_Node()
{
    list_link new_node = (list_link) malloc (sizeof(list_node));
    if (node == (list_link)NULL)
    {
        perror("malloc list node ...");
        return (list_link)-1;
    }
    
    // 内存清空
    memset(new_node, 0, sizeof(list_node));

    // 单向循环链表和单向链表的区别
    // 单向循坏链表的next的是指向自己的
    new_node->next = new_node;

    return new_node;
}

(3)头插法

单向链表和单向循环链表的头插法是一样。

int Head_Add_Node(list_link head)
{

    if (head == (list_link)NULL)
    {
        printf("头节点异常!\n");
        return -1;
    }

    // 创建新的节点
    list_link new_node = Create_List_Node();
    if (new_node == (list_link)-1)
    {
        printf("创建新的节点失败!\n");
        return -1;
    }

    // 输入数据
    printf("请输入数据:");
    scanf("%d", &(new_node->data));

    // 头插法
    new_node->next = head->next;
    head->next = new_node;

    return 0;
}

(4)尾插法

单向链表

int Tail_Add_Node(list_link head)
{

    if (head == NULL)
    {
        printf("头结点异常!\n");
        return -1;
    }

    // 获取尾节点
    list_link tmp_node = NULL;
    for (tmp_node = head->next; tmp_node->next != NULL; tmp_node = tmp_node->next);

    // 创建新结点
    list_link new_node = Create_List_Node();
    if (new_node == (list_link)-1)
    {
        printf("创建新节点失败!\n");
        return -1;
    }

    printf("输入数据:");
    scanf("%d", &(new_node->data));

    tmp_node->next = new_node;

    return 0;
}

单向循环链表

int Tail_List_Node(list_link head)
{
    if (head == NULL)
    {
        printf("头结点异常,无法尾插!\n");
        return -1;
    }

    // 获取尾结点
    list_link tmp_node = NULL;
    for (tmp_node=head->next; tmp_node->next != head; tmp_node=tmp_node->next);

    // 创建新的节点
    list_link new_node = Create_List_Node();
    if (new_node == (list_link)-1)
    {
        printf("创建新节点失败!\n");
        return -1;
    }

    tmp_node->next = new_node;
    new_node->next = head;

    return 0;
}

(4)遍历单项向(循环)链表

单向链表

int Show_List_Data(list_link head)
{

    if (head == NULL)
    {
        printf("头结点异常!\n");
        return -1;
    }
    else if (head->next == NULL)
    {
        printf("空链表,不需要遍历!\n");
        return 0;
    }
    else
    {
        for (list_link tmp_node = head->next; tmp_node != NULL; tmp_node = tmp_node->next)
        {
            printf("%d\n", tmp_node->data);
        }
    }

    return 0;
}

单向循环链表

int Show_List_Node(list_link head)
{
    if (head == NULL)
    {
        printf("头节点异常,无法遍历!\n");
        return -1;
    }

    if (head->next == head)
    {
        printf("空链表,无需遍历!\n");
        return 0;
    }

    for (list_link tmp_node=head->next; tmp_node != head; tmp_node = tmp_node->next)
    {
        printf("%d\n",tmp_node->data);
    }
    return 0;
}

(5)检索指定的数据节点

单向链表

list_link Find_List_Node(list_link head, int search_mode)
{

    if (head == NULL)
    {
        printf("头结点异常!\n");
        return (list_link)-1;
    }
    else if (head->next == NULL)
    {
        printf("空链表,无需检索!\n");
        return (list_link)0;
    }
    else
    {
        int obj_data;
        printf("请输入要指定的数据:");
        scanf("%d", &obj_data);

        for (list_link obj_node = head; obj_node->next != NULL; obj_node = obj_node->next)
        {
            if (obj_data == obj_node->next->data)
            {
                printf("击中目标节点!\n");
                if (search_mode == SEARCH_PRESENT_NODE)
                {
                    return obj_node->next;
                }
                if (search_mode == SEARCH_BEFORE_NODE)
                {
                    return obj_node;
                }

            }
        }
    }

    printf("链表中没有该数据!\n");

    return (list_link)-2;
}

单向循环链表

list_link Find_List_Node(list_link head, int search_mode)
{
    if (head == NULL)
    {
        printf("头节点异常,无法检索!\n");
        return (list_link)-1;
    }

    if (head->next == head)
    {
        printf("空链表,无需检索!\n");
        return (list_link)0;
    }

    int obj_data;
    printf("请输入要指定的数据:");
    scanf("%d",&obj_data);

    for (list_link obj_node=head; obj_node != head; obj_node = obj_node->next)
    {
        if (obj_data == obj_node->next->data)
        {
            printf("击中目标节点!\n");
            if (search_mode == SERACH_PRESENT_NODE)
            {
                return obj_node->next;
            }
            
            if (search_mode == SERACH_BEFORE_NODE)
            {
                return obj_node;
            }
        }
    }
    printf("链表中没有该数据!\n");
    return (list_link)-2;
}

(6)删除指定的节点数据

单向链表

int Del_List_Node(list_link head)
{

    if (head == NULL)
    {
        printf("头结点异常,无法删除!\n");
        return -1;
    }
    else if (head->next == NULL)
    {
        printf("空链表,无需删除!\n");
        return -1;
    }
    else
    {
        // 链表里面存在数据,需要先输入要删除的节点,然后判断是否存在,存在则进行删除
        // 这里需要使用Find_List_Node 去寻找到当前节点的上一个节点
        list_link before_del_node = Find_List_Node(head, SEARCH_BEFORE_NODE);
        if (before_del_node == (list_link)-2)
        {
            printf("没有该数据节点,删除操作失败!\n");
            return -1;
        }

        // 备份一下要删除的节点
        list_link del_node = before_del_node->next;

        before_del_node->next = before_del_node->next->next;
        
        del_node->next = NULL;
        free(del_node);

    }

    return 0;
}

单向循坏链表

int Del_List_Node(list_link head)
{

    if (head == NULL)
    {
        printf("头结点异常,无法删除!\n");
        return -1;
    }
    else if (head->next == head)
    {
        printf("空链表,无需删除!\n");
        return -1;
    }
    else
    {
        // 链表里面存在数据,需要先输入要删除的节点,然后判断是否存在,存在则进行删除
        // 这里需要使用Find_List_Node 去寻找到当前节点的上一个节点
        list_link before_del_node = Find_List_Node(head, SEARCH_BEFORE_NODE);
        if (before_del_node == (list_link)-2)
        {
            printf("没有该数据节点,删除操作失败!\n");
            return -1;
        }

        // 备份一下要删除的节点
        list_link del_node = before_del_node->next;

        before_del_node->next = before_del_node->next->next;
        
        del_node->next = NULL;
        free(del_node);

    }

    return 0;
}

(6)任意位置添加

单向链表

int Anywhere_Add_Node(list_link head)
{
    if (head == NULL)
    {
        printf("头结点异常!\n");
        return -1;
    }
    else if (head->next == NULL)
    {
        printf("空链表,无法指定位置添加,默认进行头插法!\n");

        if (Head_Add_Node(head) == -1)
        {
            printf("头插法添加新结点失败!\n");
            return -1;
        }
    }
    else
    {
        // 链表中存在数据 先键入要指定的位置,再检索有没有这个位置
        list_link obj_node = Find_List_Node(head, SEARCH_PRESENT_NODE);
        if (obj_node == (list_link)-2)
        {
            printf("没有该数据结点,指定位置添加失败!\n");
            return -1;
        }

        list_link new_node = Create_List_Node();
        if (new_node == (list_link)-1)
        {
            printf("新结点创建失败!指定位置添加数据失败!\n");
            return -1;
        }

        printf("请输入要添加的新数据:");
        scanf("%d", &new_node->data);

        new_node->next = obj_node->next;
        obj_node->next = new_node;
    }

    return 0;
}

单向循坏链表

int Anywhere_Add_Node(list_link head)
{
    if (head == NULL)
    {
        printf("头结点异常!\n");
        return -1;
    }
    else if (head->next == head)
    {
        printf("空链表,无法指定位置添加,默认进行头插法!\n");

        if (Head_Add_Node(head) == -1)
        {
            printf("头插法添加新结点失败!\n");
            return -1;
        }
    }
    else
    {
        // 链表中存在数据 先键入要指定的位置,再检索有没有这个位置
        list_link obj_node = Find_List_Node(head, SEARCH_PRESENT_NODE);
        if (obj_node == (list_link)-2)
        {
            printf("没有该数据结点,指定位置添加失败!\n");
            return -1;
        }

        list_link new_node = Create_List_Node();
        if (new_node == (list_link)-1)
        {
            printf("新结点创建失败!指定位置添加数据失败!\n");
            return -1;
        }

        printf("请输入要添加的新数据:");
        scanf("%d", &new_node->data);

        new_node->next = obj_node->next;
        obj_node->next = new_node;
    }

    return 0;
}

(7)移动指定数据节点

单向链表

int Move_List_Node(list_link head)
{
    if (head == NULL)
    {
        printf("头节点异常!\n");
        return -1;
    }
    else if (head->next == NULL)
    {
        printf("空链表, 无需移动!\n");
        return 0;
    }
    else if (head->next->next == NULL)
    {
        printf("只有一个数据,无需移动!\n");
        return 0;
    }
    else
    {
        list_link before_obj_node = Find_List_Node(head, SEARCH_BEFORE_NODE);
        if (before_obj_node == (list_link)-2)
        {
            printf("没有该数据节点,无法移动!\n");
            return -1;
        }

        list_link select_node = Find_List_Node(head, SEARCH_PRESENT_NODE);
        if (select_node == (list_link)-2)
        {
            printf("没有该数据节点,无法移动!\n");
            return -1;
        }

        if (before_obj_node->next == select_node)
        {
            printf("同一个节点,无需操作!\n");
            return 0;
        }

        // 先断开那个目标节点
        list_link obj_node = before_obj_node->next;
        before_obj_node->next = obj_node->next;
        obj_node->next = NULL;
        // 再将目标节点接到某个节点之后
        obj_node->next = select_node->next;
        select_node->next = obj_node;
    }

    return 0;
}

单向循坏链表

int Move_List_Node(list_link head)
{
    if (head == NULL)
    {
        printf("头结点异常,无法移动!\n");
        return -1;
    }

    if (head->next == head)
    {
        printf("空链表,无需移动!\n");
        return 0;
    }

    if (head->next->next == head)
    {
        printf("只有一个数据,无需移动!\n");
        return 0;
    }

    list_link before_obj_node = Find_List_Node(head, SERACH_BEFORE_NODE);
    if (before_obj_node == (list_link)-2)
    {
        printf("没有该数据节点,无法移动!\n");
        return -1;
    }

    list_link select_node = Find_List_Node(head, SERACH_PRESENT_NODE);
    if (select_node == (list_link)-2)
    {
        printf("没有该数据节点,无法移动!\n");
        return -1;
    }

    if (before_obj_node->next == select_node)
    {
        printf("同一个节点,无需操作!\n");
        return 0;
    }

    // 断开目标节点
    list_link obj_node = before_obj_node->next;
    before_obj_node->next = obj_node->next;
    obj_node->next = NULL;
    // 再将目标节点接到某个节点之后
    obj_node->next = select_node->next;
    select_node->next = obj_node;

    return 0;
}

(8)销毁链表

单向链表

int Destory_List(list_link head)
{
    if (head == NULL)
    {
        printf("头结点异常,无法摧毁!\n");
        return -1;
    }
    else if (head->next == NULL)
    {
        printf("空链表,直接释放头结点!\n");
        free(head);
        return 0;
    }
    else 
    {
        list_link tmp_node = head->next;
        list_link free_node = head->next;
        
        while (tmp_node != NULL)
        {
            tmp_node = free_node->next;
            head->next = free_node->next;
            free_node->next = NULL;
            free(free_node);

            free_node = tmp_node;
            printf("-----\n");
        }
        
        free(head);
    }

    return 0;
}

单向循坏链表

int Destory_List(list_link head)
{
    if (head == NULL)
    {
        printf("头节点异常,无法销毁!\n");
        return -1;
    }

    if (head->next == head)
    {
        printf("空链表,直接释放头结点!\n");
        free(head);
        return 0;
    }

    list_link tmp_node = head->next;
    list_link free_node = head->next;
    
    while (tmp_node != head)
    {
        tmp_node = free_node->next;
        head->next = free_node->next;
        free_node->next = NULL;
        free(free_node);

        free_node = tmp_node;
        printf("----\n");
    }

    free(head);

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值