数据结构笔记(二)循环单链表

本文详细介绍了循环单链表的概念、初始化、插入、删除、遍历方法,以及它在栈、队列、树遍历和图搜索中的应用。同时探讨了其优点和复杂性,提供了相关示例代码。
摘要由CSDN通过智能技术生成

循环单链表是一种特殊的单向链表,其最后一个节点的指针不是指向空(NULL),而是指向链表的头节点,形成一个环状结构,如下图所示。这样一来,从任何节点出发都可以遍历整个链表。
在这里插入图片描述

在循环单链表中,需要特别注意以下几点:

  1. 初始化:创建循环单链表时,需要确保头节点的指针指向自身,即头节点的next指针指向头节点本身。
  2. 插入节点:插入节点时,要确保新节点被正确插入到链表中,并更新相邻节点的指针。
  3. 删除节点:删除节点时,也需要更新相邻节点的指针,确保链表结构仍然保持完整。
  4. 遍历链表:遍历循环单链表时,需要设置一个终止条件,以免陷入无限循环。

循环单链表的应用:

  • 在栈和队列的实现中,可以使用循环单链表进行存储和管理

  • 在树形结构的遍历中,可以使用其进行层级遍历

  • 在图的遍历中,可以使用其进行深度优先搜索或广度优先搜索

循环单链表的优缺点:

  • 可以解决单链表无法解决的问题,例如寻找倒数第i个节点等

  • 缺点是实现相对复杂,需注意循环边界条件和指针的维护

  • 其插入和删除的操作时间复杂度为O(n),比单链表高

示例代码如下:

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

// 定义循环单链表的节点结构
typedef struct Node {
    int data;             // 数据域
    struct Node* next;    // 指针域
} Node;

// 初始化循环单链表
void initList(Node** head) {
    *head = (Node*)malloc(sizeof(Node));
    (*head)->next = *head;
}

// 插入元素到循环单链表
void insertNode(Node* head, int value) {
    Node* newNode = (Node*)malloc(sizeof(Node));
    newNode->data = value;
    newNode->next = head->next;
    head->next = newNode;
}

// 删除指定元素的节点
void deleteNode(Node* head, int value) {
    Node* p = head;
    while (p->next != head) {
        if (p->next->data == value) {
            Node* temp = p->next;
            p->next = temp->next;
            free(temp);
            return;
        }
        p = p->next;
    }
}

// 遍历循环单链表
void traverseList(Node* head) {
    Node* p = head->next;
    while (p != head) {
        printf("%d ", p->data);
        p = p->next;
    }
    printf("\n");
}

//根据值查找节点位置
int findNodePosition(Node* head, int target) {
    // 检查链表是否为空
    if (head == NULL) {
        return -1;
    }

    // 定义一个指向链表头节点的指针
    Node* current = head;
    int position = 0;

    // 遍历链表
    do {
        // 检查当前节点的数据是否等于目标数据
        if (current->data == target) {
            return position ;  // 找到目标数据,返回当前节点的位置
        }

        // 移动到下一个节点
        current = current->next;
        position++;
    } while (current != head);  // 当回到头节点时停止循环

    return -1;  // 链表中无目标数据,返回-1
}

// 查找循环单链表第i个节点的数值
int findNodeValue(Node *head, int i) {
    Node *current = head;
    int position = 0;

    do {
        if (position == i) {
            return current->data;
        }

        current = current->next;
        position++;
    } while (current != head);

    // 未找到第i个节点
   return -1;
}

/*   查找循环单链表中倒数第i个节点的数据
 *
 * 要查找循环单链表中倒数第i个节点的数据,可以使用"快慢指针"的方法来实现。具体步骤如下:
 * a.定义两个指针,分别命名为fast和slow,初始时均指向链表的头节点。
 * b.让fast指针先向前移动i步,然后让fast和slow指针一起向前移动,直到fast指针到达链表末尾(即指向头节点时停止)。
 * c.此时slow指针所指向的节点即为倒数第i个节点。
 */
int findReverseNodeValue(Node *head, int i) {
    Node *fast = head;
    Node *slow = head;
    int count = 0;
    i -= 1;

    // 让fast指针先向前移动i步
    while (count < i && fast->next != head) {
        fast = fast->next;
        count++;
    }

    // 处理i超出链表长度的情况
    if (count < i) {
        return -1;
    }

    // 让fast和slow指针一起向前移动
    while (fast->next != head) {
        fast = fast->next;
        slow = slow->next;
    }

    // 返回slow指针所指向的节点数据
    return slow->data;
}

/* 删除循环单链表
 * 要删除循环单链表,可以按照以下步骤进行操作:
 * a.从头节点开始遍历整个循环单链表,依次释放每个节点的内存空间。
 * b.最后将头节点指针置为NULL,表示链表已经被删除。
*/
void deleteCircularLinkedList(Node **head) {
    Node *current = *head;
    Node *next;

    // 遍历链表,释放每个节点的内存空间
    do {
        next = current->next;
        free(current);
        current = next;
    } while (current != *head);

    // 将头节点指针置为NULL
    *head = NULL;
}


int main() {
    Node* head;
    initList(&head);

    // 插入元素
    insertNode(head, 12);
    insertNode(head, 13);
    insertNode(head, 23);
    insertNode(head, 43);

    // 遍历链表
    traverseList(head);

    // 在循环单链表中查找数据对应的位置
    int target = 13;
    int position= findNodePosition(head, target);
    if (position != -1) {
        printf("节点值为 %d 的节点在链表中的位置为: %d\r\n", target, position);
    } else {
        printf("Target data not found.\n");
    }

    // 删除元素
    deleteNode(head, 13);

    printf("删除后遍历值:\r\n");
    // 遍历链表
    traverseList(head);

    //根据位置查找对应节点的数据
    int index = 2;
    int value = findNodeValue(head, index );
    if (value != -1) {
        printf("第%d个节点的数值为: %d\n", index, value);
    } else {
        printf("未找到第%d个节点\n", index);
    }

    //查找循环单链表中倒数第i个节点的数据
    int value2 = findReverseNodeValue(head, index);
    if (value2 != -1) {
        printf("倒数第%d个节点的数据为: %d\n", index, value2);
    } else {
        printf("未找到倒数第%d个节点\n", index);
    }

     // 删除循环单链表
    deleteCircularLinkedList(&head);

    // 检查链表是否已删除
    if (head == NULL) {
        printf("循环单链表已成功删除\n");
    } else {
        printf("循环单链表删除失败\n");
    }


    return 0;
}

该程序输出为:
在这里插入图片描述
如有错误,欢迎指出,共同学习共同进步~

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

落淼喵_G

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值