循环链表C语言实现(非伪代码)

循环链表建议自己一定要下去实现一遍,你会发现和普通的单链表还是有很大区别的,尤其是遍历的时候循环的条件!!

一、创建一个链表

// 创建一个链表
void Creat_LinkedList(LinkedList* list) 
{
    list->head = NULL;
    list->len = 0;
}

二、销毁一个循环链表

2.1、核心代码实现:

注意:

1、 因为在循环链表中,我们不能移动头指针的位置,所以相较于普通链表的销毁,我们还多需要一个结点来进行缓存的操作

2、使用do--while是因为current的初始值就是list->head,所以需要使用do--while先跳过一轮,防止直接退出

// 销毁一个链表
void Destroy_LinkList(LinkedList* list) 
{
    //因为在循环链表中,我们不能移动头指针的位置,
    //所以相较于普通链表的销毁,我们还多需要一个结点来进行缓存的操作

    if (list->head == NULL) return; // 空链表

    ListNode* current = list->head; //定义一个迭代器指向头节点
    ListNode* temp;  //用来暂存结点 来释放结点

    //使用do--while是因为current的初始值就是list->head
    //所以需要使用do--while先跳过一轮,防止直接退出
    do {
        temp = current; // 定义一个值指向
        current = current->next; // 移动到下一个节点
        free(temp); // 释放当前节点
    } while (current != list->head); // 检查是否回到头节点

    list->head = NULL;
    list->len = 0;
}

2.2、代码图解:

1、用一个temp指向current

2、current往下移一位

3、释放free

三、插入元素

3.1、核心代码实现:

// 在链表中插入一个元素,在第i个位置插入value值
void Insert_LinkList(LinkedList* list, int i, int value) 
{
    if (i < 0 || i > list->len) //越界
    {
        printf("插入失败\n");
        return;
    }

    ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
    newNode->data = value;

    if (list->len == 0) // 如果链表为空
    { 
        newNode->next = newNode; // 指向自身
        list->head = newNode; // 新节点为头节点
    }
    else if (i == 0) // 插入到头部,头插法
    { 
        ListNode* tail = list->head;
        while (tail->next != list->head) // 找到尾节点
        { 
            tail = tail->next;
        }
        newNode->next = list->head; // 新节点指向头
        tail->next = newNode; // 尾节点指向新节点
        list->head = newNode; // 更新头节点
    }
    else //尾插法
    {
        ListNode* current = list->head;

        for (int j = 0; j < i - 1; j++) 
        {
            current = current->next;
        }
        newNode->next = current->next;
        current->next = newNode;
    }
    list->len++;
}

3.2、代码图解

3.2.1:当链表为空时

下一个结点指向自身

头节点指向当前结点

 3.2.2、当链表不为空,且需要插入元素到头部时

1、定义一个tail指针,指向头节点

2、遍历到尾结点

3、同普通链表一致,修改指针指向即可

 3.2.3:当链表不为空,且需要插入元素到链表中时

1、定义一个迭代器cur指向头节点,

2、遍历到第i-1个下标

3、改变指针指向

 四、删除元素

4.1、核心代码实现

// 删除节点,把第i个元素删除
void Delete_LinkList(LinkedList* list, int i) 
{
    if (i < 0 || i >= list->len) //下标越界
    {
        printf("删除失败\n");
        return;
    }
    ListNode* toDelete = list->head;

    if (i == 0) // 删除头节点
    { 
        ListNode* tail = list->head;    //定义一个迭代器指向 头节点
        while (tail->next != list->head) //移动tail到 尾节点
        {
            tail = tail->next;
        }
        if (list->len == 1) // 只有一个节点 
        { 
            free(list->head);
            list->head = NULL;
        }
        else //不只有一个头节点
        {
            tail->next = toDelete->next; // 更新尾节点指向
            list->head = toDelete->next; // 更新头节点
            free(toDelete);
        }
    }
    else //删除的结点不是头结点
    {
        ListNode* current = list->head; 
  
        for (int j = 0; j < i - 1; j++) //找到要删除的结点的前一个结点
        {
            current = current->next;
        }
        toDelete = current->next;   //把toDelete指向cur->next
        current->next = toDelete->next; //把cur->next指向toDelete的next
        free(toDelete);
    }
    list->len--;
}

 4.2、代码图解:

4.2.1、删除头节点,且只有一个元素

释放头节点,置空即可。

4.2.2、删除头节点,但不只有一个元素

0、定义一个toDelete结点,指向头节点,表示要删除头节点,用来最后的释放

1、定义一个迭代器tail指向头节点

2、把tail移动到尾结点

3、更新尾结点的指向

4、更新头节点

5、删除要删除的结点

4.2.3、删除的结点不是头节点:

0、定义一个toDelete,指向头结点

1、定义一个迭代器current,指向头节点

2、把current移动到要删除结点的前一个结点

3、把toDelete指向current的下一个结点,即指向要删除的结点。

4、把cur->next指向toDelete的next.

5、释放要删除的结点toDelete

 五、通过元素来查找链表节点

5.1核心代码实现: 

// 通过元素来查找链表节点
ListNode* Find_element_Linked(LinkedList* list, int value) 
{
    if (list->head == NULL) return NULL; // 空链表
    ListNode* current = list->head;

    do 
    {
        if (current->data == value) //简单!!和单链表一致
        {
            return current;
        }
        current = current->next;
    } while (current != list->head);

    return NULL; // 没有找到
}

5.2、代码图解:

 六、通过下标来查找链表节点:

// 通过下标来寻找链表的节点,寻找第i个元素
ListNode* Find_Index_Linked(LinkedList* list, int i) 
{
    if (i < 0 || i >= list->len)
    {
        printf("寻找错误\n");
        return NULL;
    }

    ListNode* current = list->head;

    for (int j = 0; j < i; j++) //因为链表的下标默认从0开始 
    {
        current = current->next;
    }
    return current;
}

七、更新链表元素

// 更新链表的元素
void Update_LInked(LinkedList* list, int i, int value) 
{
    ListNode* temp = Find_Index_Linked(list, i);    //调用寻找元素下标的函数,直接获取要更新的元素的结点指针
    
    if (temp) 
    {
        temp->data = value;
    }
    //可以不用加Ddeque语句,因为Find_Index_Linked程序中已经有了
}

八、遍历打印链表的元素

//打印链表的元素
void Print_Linked(LinkedList* list) 
{
    if (list->head == NULL) 
    {
        printf("链表为空\n");
        return;
    }

    ListNode* current = list->head;

    do 
    {
        printf("%d -> ", current->data);
        current = current->next;
    } while (current != list->head);

    printf("(回到头节点)\n");
}

总结:完整代码的实现:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>

typedef struct ListNode { // 创建循环链表单独节点
    int data; // 数值域
    struct ListNode* next; // 下一个节点的指针域
} ListNode;

typedef struct LinkedList { // 完整的链表
    ListNode* head; // 头节点
    int len; // 长度
} LinkedList;


// 创建一个链表
void Creat_LinkedList(LinkedList* list) 
{
    list->head = NULL;
    list->len = 0;
}


// 销毁一个链表
void Destroy_LinkList(LinkedList* list) 
{
    //因为在循环链表中,我们不能移动头指针的位置,
    //所以相较于普通链表的销毁,我们还多需要一个结点来进行缓存的操作

    if (list->head == NULL) return; // 空链表

    ListNode* current = list->head; //定义一个迭代器指向头节点
    ListNode* temp;  //用来暂存结点 来释放结点

    //使用do--while是因为current的初始值就是list->head
    //所以需要使用do--while先跳过一轮,防止直接退出
    do {
        temp = current; // 定义一个值指向
        current = current->next; // 移动到下一个节点
        free(temp); // 释放当前节点
    } while (current != list->head); // 检查是否回到头节点

    list->head = NULL;
    list->len = 0;
}


// 在链表中插入一个元素,在第i个位置插入value值
void Insert_LinkList(LinkedList* list, int i, int value) 
{
    if (i < 0 || i > list->len) //越界
    {
        printf("插入失败\n");
        return;
    }

    ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
    newNode->data = value;

    if (list->len == 0) // 如果链表为空
    { 
        newNode->next = newNode; // 指向自身
        list->head = newNode; // 新节点为头节点
    }
    else if (i == 0) // 插入到头部,头插法
    { 
        ListNode* tail = list->head;
        while (tail->next != list->head) // 找到尾节点
        { 
            tail = tail->next;
        }
        newNode->next = list->head; // 新节点指向头
        tail->next = newNode; // 尾节点指向新节点
        list->head = newNode; // 更新头节点
    }
    else //尾插法
    {
        ListNode* current = list->head;

        for (int j = 0; j < i - 1; j++) 
        {
            current = current->next;
        }
        newNode->next = current->next;
        current->next = newNode;
    }
    list->len++;
}

// 删除节点,把第i个元素删除
void Delete_LinkList(LinkedList* list, int i) 
{
    if (i < 0 || i >= list->len) //下标越界
    {
        printf("删除失败\n");
        return;
    }
    ListNode* toDelete = list->head;

    if (i == 0) // 删除头节点
    { 
        ListNode* tail = list->head;    //定义一个迭代器指向 头节点
        while (tail->next != list->head) //移动tail到 尾节点
        {
            tail = tail->next;
        }
        if (list->len == 1) // 只有一个节点 
        { 
            free(list->head);
            list->head = NULL;
        }
        else //不只有一个头节点
        {
            tail->next = toDelete->next; // 更新尾节点指向
            list->head = toDelete->next; // 更新头节点
            free(toDelete);
        }
    }
    else //删除的结点不是头结点
    {
        ListNode* current = list->head; 
  
        for (int j = 0; j < i - 1; j++) //找到要删除的结点的前一个结点
        {
            current = current->next;
        }
        toDelete = current->next;   //把toDelete指向cur->next
        current->next = toDelete->next; //把cur->next指向toDelete的next
        free(toDelete);
    }
    list->len--;
}

// 通过元素来查找链表节点
ListNode* Find_element_Linked(LinkedList* list, int value) 
{
    if (list->head == NULL) return NULL; // 空链表
    ListNode* current = list->head;

    do 
    {
        if (current->data == value) //简单!!和单链表一致
        {
            return current;
        }
        current = current->next;
    } while (current != list->head);

    return NULL; // 没有找到
}


// 通过下标来寻找链表的节点,寻找第i个元素
ListNode* Find_Index_Linked(LinkedList* list, int i) 
{
    if (i < 0 || i >= list->len)
    {
        printf("寻找错误\n");
        return NULL;
    }

    ListNode* current = list->head;

    for (int j = 0; j < i; j++) //因为链表的下标默认从0开始 
    {
        current = current->next;
    }
    return current;
}

// 更新链表的元素
void Update_LInked(LinkedList* list, int i, int value) 
{
    ListNode* temp = Find_Index_Linked(list, i);    //调用寻找元素下标的函数,直接获取要更新的元素的结点指针
    
    if (temp) 
    {
        temp->data = value;
    }
    //可以不用加Ddeque语句,因为Find_Index_Linked程序中已经有了
}

//打印链表的元素
void Print_Linked(LinkedList* list) 
{
    if (list->head == NULL) 
    {
        printf("链表为空\n");
        return;
    }

    ListNode* current = list->head;

    do 
    {
        printf("%d -> ", current->data);
        current = current->next;
    } while (current != list->head);

    printf("(回到头节点)\n");
}

int main() 
{
    LinkedList list; //定义一个链表
    Creat_LinkedList(&list);    //创建链表

    Insert_LinkList(&list, 0, 10);
    Insert_LinkList(&list, 1, 20);
    Insert_LinkList(&list, 2, 30);
    Insert_LinkList(&list, 3, 40);

    printf("Original List:\n");
    Print_Linked(&list);

    Delete_LinkList(&list, 2);
    Update_LInked(&list, 1, 100);
    printf("Change1 List:\n");
    Print_Linked(&list);

    ListNode* found = Find_element_Linked(&list, 30); //通过元素寻找元素

    if (!found) 
    {
        printf("此节点不存在\n");
    }

    Destroy_LinkList(&list); // 销毁链表
    system("pause");
    return 0;
}

 纯私人撰写,欢迎大家私信勘误!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值