循环链表c语言

1,循环链表的定义

循环链表是一种链表数据结构,它与普通链表(单向链表或双向链表)不同之处在于,循环链表的尾部节点指向头部节点,形成一个闭环。这使得在循环链表中可以无限循环遍历节点,因为没有"末尾"节点,而是以头节点为起点。

循环链表的定义通常包括以下要素:

1.节点:循环链表由节点构成。每个节点包含两部分,一部分是数据元素,用来存储有关的信息,另一部分是指向下一个节点的指针。

2.头指针:头指针是指向循环链表的第一个节点的指针。

3.尾节点:尾节点是指向循环链表的最后一个节点的指针。不同于普通链表,尾节点的下一个指针指向头节点,创建了循环结构。

4.基本操作:通常,循环链表支持常见的链表操作,如插入节点、删除节点、查找节点、遍历节点等操作。
 

2.循环链表的有点

循环链表相对于普通线性链表具有以下优点:

无限遍历:可以无限遍历循环链表,适用于需要循环处理一组元素的场景。

简化操作:插入和删除操作相对简单,无需处理尾部特殊情况。

节省内存:不需要额外的尾节点指针,有助于节省内存。

特定问题的有效数据结构:适用于表示周期性特性的问题,如环形缓冲区和循环队列。

简单迭代:遍历通常使用一个循环,简化迭代实现。

双向遍历:在双向循环链表中,前进和后退操作都高效。

需要谨慎使用,以避免无限循环或复杂化代码。选择链表类型应根据具体需求决定。

3.循环链表的基本运算

1.初始化链表

/*1. 初始化*/
int init(SingleLinkList** Head)
{
    if (1)
    {
        /*申请内存*/
        (*Head) = (SingleLinkList*)malloc(sizeof(SingleLinkList));
        /*判断内存申请是否成功*/
        if (*Head == NULL)
        {
            printf("申请内存错误, 初始化失败![100001]\n");
            return 100001;
        }
        (*Head)->next = NULL;

        (*Head)->next = *Head;

        return 0;
    }
    else
    {
        printf("该链表已经初始化!请删除后再执行此操作![100002]\n");
        return 100002;
    }
}

2.插入元素


/*2. 插入元素,头插法*/
int insert_head(SingleLinkNode** Head, DataType x) {
    if (*Head == NULL) {
        return 0; // 未初始化链表
    }
    SingleLinkNode* new_node = (SingleLinkNode*)malloc(sizeof(SingleLinkNode));
    if (new_node == NULL) {
        return 0; // 内存分配失败
    }
    new_node->data = x;
    new_node->next = (*Head)->next; // 新节点指向原头节点的下一个节点
    (*Head)->next = new_node; // 头节点指向新节点
    return 1;
}


/*2. 插入元素, 尾插法*/
int insert_tail(SingleLinkNode** Head, DataType x) {
    if (*Head == NULL) {
        return 0; // 未初始化链表
    }
    SingleLinkNode* new_node = (SingleLinkNode*)malloc(sizeof(SingleLinkNode));
    if (new_node == NULL) {
        return 0; // 内存分配失败
    }
    new_node->data = x;
    new_node->next = *Head; // 新节点应该指向头节点

    // 查找最后一个节点
    SingleLinkNode* current = *Head;
    while (current->next != *Head) {
        current = current->next;
    }

    current->next = new_node; // 更新前面最后一个节点的next指向新节点
    return 1;
}
/*2. 插入元素,在位置i处插入元素x */
int insert(SingleLinkNode** Head, int i, DataType x) {
    if (*Head == NULL) {
        return 0; // 未初始化链表
    }
    if (i < 1) {
        return 0; // 位置不合法
    }
    SingleLinkNode* new_node = (SingleLinkNode*)malloc(sizeof(SingleLinkNode));
    if (new_node == NULL) {
        return 0; // 内存分配失败
    }
    new_node->data = x;
    SingleLinkNode* current = *Head;
    int count = 1;
    while (current->next != *Head && count < i) {
        current = current->next;
        count++;
    }
    if (count < i) {
        return 0; // 位置超出链表长度
    }
    new_node->next = current->next;
    current->next = new_node;
    return 1;
}

3.删除元素

/*3. 删除元素, 删除值为x的元素*/
int deleteNode(SingleLinkNode** Head, DataType x) {
    if (*Head == NULL) {
        return 0; // 未初始化链表
    }
    SingleLinkNode* current = *Head;
    while (current->next != *Head) {
        if (current->next->data == x) {
            SingleLinkNode* temp = current->next;
            current->next = temp->next;
            free(temp);
            return 1; // 删除成功
        }
        current = current->next;
    }
    return 0; // 未找到要删除的元素
}

4.查找元素

/*4. 查找值为x的元素,返回位置i */
int find(SingleLinkNode* Head, DataType x) {
    if (Head == NULL) {
        return 0; // 未初始化链表
    }
    SingleLinkNode* current = Head->next;
    int position = 1;
    while (current != Head) {
        if (current->data == x) {
            return position;
        }
        current = current->next;
        position++;
    }
    return 0; // 未找到

5.链表长度

/*5. 链表长度*/
int length(SingleLinkNode* Head) {
    if (Head == NULL) {
        return 0; // 未初始化链表
    }
    SingleLinkNode* current = Head->next;
    int len = 0;
    while (current != Head) {
        len++;
        current = current->next;
    }
    return len;
}

6.输出链表

/*6.输出链表*/
void print(SingleLinkNode* Head) {
    if (Head == NULL) {
        printf("链表未初始化\n");
        return;
    }
    SingleLinkNode* current = Head->next;
    int first = 1; // 用于控制第一个元素
    while (current != Head) {
        if (!first) {
            printf(" -> "); // 如果不是第一个元素,打印箭头
        }
        else {
            first = 0;
        }
        printf("%d", current->data);
        current = current->next;
    }
    printf("\n");
}


完整代码

#include "SingleLinkList.h"
#include <stdlib.h>
#include <stdio.h>

/*1. 初始化*/
int init(SingleLinkList** Head)
{
    if (1)
    {
        /*申请内存*/
        (*Head) = (SingleLinkList*)malloc(sizeof(SingleLinkList));
        /*判断内存申请是否成功*/
        if (*Head == NULL)
        {
            printf("申请内存错误, 初始化失败![100001]\n");
            return 100001;
        }
        (*Head)->next = NULL;

        (*Head)->next = *Head;

        return 0;
    }
    else
    {
        printf("该链表已经初始化!请删除后再执行此操作![100002]\n");
        return 100002;
    }
}


/*2. 插入元素,头插法*/
int insert_head(SingleLinkNode** Head, DataType x) {
    if (*Head == NULL) {
        return 0; // 未初始化链表
    }
    SingleLinkNode* new_node = (SingleLinkNode*)malloc(sizeof(SingleLinkNode));
    if (new_node == NULL) {
        return 0; // 内存分配失败
    }
    new_node->data = x;
    new_node->next = (*Head)->next; // 新节点指向原头节点的下一个节点
    (*Head)->next = new_node; // 头节点指向新节点
    return 1;
}


/*2. 插入元素, 尾插法*/
int insert_tail(SingleLinkNode** Head, DataType x) {
    if (*Head == NULL) {
        return 0; // 未初始化链表
    }
    SingleLinkNode* new_node = (SingleLinkNode*)malloc(sizeof(SingleLinkNode));
    if (new_node == NULL) {
        return 0; // 内存分配失败
    }
    new_node->data = x;
    new_node->next = *Head; // 新节点应该指向头节点

    // 查找最后一个节点
    SingleLinkNode* current = *Head;
    while (current->next != *Head) {
        current = current->next;
    }

    current->next = new_node; // 更新前面最后一个节点的next指向新节点
    return 1;
}
/*2. 插入元素,在位置i处插入元素x */
int insert(SingleLinkNode** Head, int i, DataType x) {
    if (*Head == NULL) {
        return 0; // 未初始化链表
    }
    if (i < 1) {
        return 0; // 位置不合法
    }
    SingleLinkNode* new_node = (SingleLinkNode*)malloc(sizeof(SingleLinkNode));
    if (new_node == NULL) {
        return 0; // 内存分配失败
    }
    new_node->data = x;
    SingleLinkNode* current = *Head;
    int count = 1;
    while (current->next != *Head && count < i) {
        current = current->next;
        count++;
    }
    if (count < i) {
        return 0; // 位置超出链表长度
    }
    new_node->next = current->next;
    current->next = new_node;
    return 1;
}

/*3. 删除元素, 删除值为x的元素*/
int deleteNode(SingleLinkNode** Head, DataType x) {
    if (*Head == NULL) {
        return 0; // 未初始化链表
    }
    SingleLinkNode* current = *Head;
    while (current->next != *Head) {
        if (current->next->data == x) {
            SingleLinkNode* temp = current->next;
            current->next = temp->next;
            free(temp);
            return 1; // 删除成功
        }
        current = current->next;
    }
    return 0; // 未找到要删除的元素
}


/*4. 查找值为x的元素,返回位置i */
int find(SingleLinkNode* Head, DataType x) {
    if (Head == NULL) {
        return 0; // 未初始化链表
    }
    SingleLinkNode* current = Head->next;
    int position = 1;
    while (current != Head) {
        if (current->data == x) {
            return position;
        }
        current = current->next;
        position++;
    }
    return 0; // 未找到
}

/*5. 链表长度*/
int length(SingleLinkNode* Head) {
    if (Head == NULL) {
        return 0; // 未初始化链表
    }
    SingleLinkNode* current = Head->next;
    int len = 0;
    while (current != Head) {
        len++;
        current = current->next;
    }
    return len;
}

/*6.输出链表*/
void print(SingleLinkNode* Head) {
    if (Head == NULL) {
        printf("链表未初始化\n");
        return;
    }
    SingleLinkNode* current = Head->next;
    int first = 1; // 用于控制第一个元素
    while (current != Head) {
        if (!first) {
            printf(" -> "); // 如果不是第一个元素,打印箭头
        }
        else {
            first = 0;
        }
        printf("%d", current->data);
        current = current->next;
    }
    printf("\n");
}

运行截图

小结

循环链表是一种链表数据结构,具有一些特定的特点,如链表的尾部节点指向头部节点,形成了一个循环。以下是循环链表的小结:

  1. 结构特点:

    • 循环链表由节点组成,每个节点包含数据和指向下一个节点的指针。
    • 循环链表的最后一个节点指向第一个节点,从而形成循环结构。
  2. 优点:

    • 无限遍历:循环链表可以无限遍历,因为没有明确定义的尾部,从头节点开始可以一直循环下去。
    • 简化操作:插入和删除操作相对较为简单,不需要特别处理边界条件,因为头节点和尾节点在逻辑上连接在一起。
    • 节省内存:不需要额外的指向 NULL 的尾节点指针,可以节省内存。
    • 实现特定问题的有效数据结构:在某些问题领域,循环链表可以更自然地表示问题的周期性特性,如环形缓冲区、游戏动画循环、循环队列等。
    • 简单的迭代实现:遍历循环链表通常使用一个循环,简化了迭代的实现。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值