C语言实例真题讲解数据结构中单向环形链表

yizhihongxing

C语言实例真题讲解数据结构中单向环形链表

1. 单向链表简介

单向链表是数据结构中的一种基础数据类型,是由一系列节点组成的,每个节点都包含了数据和指向下一个节点的指针。链表的优点是可以动态地添加和删除元素,但缺点是访问元素的效率相对较低。

2. 单向链表的扩展性

由于链表的动态性,我们可以对其进行扩展,使得其可以满足更复杂的需求。其中一个扩展便是单向环形链表。单向环形链表与单向链表相比,多了一个特点:最后一个节点的指针指向起始节点。

3. 单向环形链表的实现方法

3.1 链表节点的定义

在单向链表中,每个节点包含了数据和指向下一个节点的指针。而在单向环形链表中,最后一个节点的指针指向起始节点。所以,我们可以在单向链表的基础上进行修改,定义每个节点为:

typedef struct node{
    int data;
    struct node* next;
}Node;

3.2 环形链表的初始化

环形链表的初始化需要设置链表的头节点,并将其指向起始节点。我们可以在链表的定义中添加一个指向头节点的指针,代码如下:

typedef struct list{
    Node* head;
}List;

List* createList(){
    List* list = (List*)malloc(sizeof(List));
    list->head = NULL;
    return list;
}

3.3 插入节点

插入节点的过程与单向链表相同,但需要注意的是,插入操作需要修改最后一个节点的指针,使其指向起始节点。代码如下:

void insertNode(List* list, int data){
    Node* node = (Node*)malloc(sizeof(Node));
    node->data = data;
    node->next = NULL;
    if(list->head == NULL){
        // 链表为空,直接将首节点指向当前节点
        list->head = node;
        // 将尾节点的指针指向首结点
        list->head->next = list->head;
        return;
    }
    Node* tail = list->head;
    while(tail->next != list->head){
        tail = tail->next;
    }
    tail->next = node;
    node->next = list->head;
}

3.4 删除节点

删除节点也需要修改最后一个节点的指针。代码如下:

void deleteNode(List* list, int data){
    if(list->head == NULL){
        return;
    }
    if(list->head->data == data){
        // 删除的是头结点
        Node* p = list->head;
        while(p->next != list->head){
            p = p->next;
        }
        if(p == list->head){
            // 链表中只有一个结点
            list->head = NULL;
            free(p);
            return;
        }
        p->next = list->head->next;
        free(list->head);
        list->head = p->next;
        return;
    }
    Node* p = list->head;
    Node* pre = NULL;
    while(p->next != list->head){
        pre = p;
        p = p->next;
        if(p->data == data){
            break;
        }
    }
    if(p == list->head){
        // 删除的是尾结点
        pre->next = list->head;
    }else{
        pre->next = p->next;
    }
    free(p);
}

4. 示例说明

4.1 插入和删除操作

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

typedef struct node{
    int data;
    struct node* next;
}Node;

typedef struct list{
    Node* head;
}List;

List* createList(){
    List* list = (List*)malloc(sizeof(List));
    list->head = NULL;
    return list;
}

void insertNode(List* list, int data){
    Node* node = (Node*)malloc(sizeof(Node));
    node->data = data;
    node->next = NULL;
    if(list->head == NULL){
        // 链表为空,直接将首节点指向当前节点
        list->head = node;
        // 将尾节点的指针指向首结点
        list->head->next = list->head;
        return;
    }
    Node* tail = list->head;
    while(tail->next != list->head){
        tail = tail->next;
    }
    tail->next = node;
    node->next = list->head;
}

void deleteNode(List* list, int data){
    if(list->head == NULL){
        return;
    }
    if(list->head->data == data){
        // 删除的是头结点
        Node* p = list->head;
        while(p->next != list->head){
            p = p->next;
        }
        if(p == list->head){
            // 链表中只有一个结点
            list->head = NULL;
            free(p);
            return;
        }
        p->next = list->head->next;
        free(list->head);
        list->head = p->next;
        return;
    }
    Node* p = list->head;
    Node* pre = NULL;
    while(p->next != list->head){
        pre = p;
        p = p->next;
        if(p->data == data){
            break;
        }
    }
    if(p == list->head){
        // 删除的是尾结点
        pre->next = list->head;
    }else{
        pre->next = p->next;
    }
    free(p);
}

void printList(List* list){
    if(list->head == NULL){
        printf("链表为空\n");
        return;
    }
    Node* p = list->head;
    do{
        printf("%d ", p->data);
        p = p->next;
    }while(p != list->head);
    printf("\n");
}

int main(){
    List* list = createList();
    insertNode(list, 1);
    insertNode(list, 2);
    insertNode(list, 3);
    insertNode(list, 4);
    insertNode(list, 5);
    printList(list);
    deleteNode(list, 1);
    deleteNode(list, 5);
    printList(list);
    return 0;
}

输出结果为:

1 2 3 4 5
2 3 4

4.2 约瑟夫问题的解决

约瑟夫问题是一个经典的问题:有 n 个人围成一圈,从某个人开始,从 1 开始报数,每次报到 m 的人出圈,然后从下一个人开始报数,直到剩下最后一个人。可以用单向环形链表来解决这个问题。

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

typedef struct node{
    int id;
    struct node* next;
}Node;

typedef struct list{
    Node* head;
}List;

List* createList(){
    List* list = (List*)malloc(sizeof(List));
    list->head = NULL;
    return list;
}

void createCircle(List* list, int n){
    int i;
    Node* pre = NULL;
    for(i = 1; i <= n; i++){
        Node* node = (Node*)malloc(sizeof(Node));
        node->id = i;
        if(pre != NULL){
            pre->next = node;
        }else{
            list->head = node;
        }
        pre = node;
    }
    pre->next = list->head;
}

void solveJosephProblem(List* list, int m){
    Node* p = list->head;
    Node* pre = NULL;
    while(p != p->next){
        int i = 1;
        while(i < m){
            pre = p;
            p = p->next;
            i++;
        }
        printf("%d 出圈\n", p->id);
        pre->next = p->next;
        Node* tmp = p;
        p = p->next;
        free(tmp);
    }
    printf("%d 为最后一位幸存者\n", p->id);
}

int main(){
    List* list = createList();
    createCircle(list, 6);
    solveJosephProblem(list, 3);
    return 0;
}

输出结果为:

3 出圈
6 出圈
1 出圈
5 出圈
2 出圈
4 为最后一位幸存者

总体来说,实现单向环形链表的过程并不复杂,但需要注意细节处理。可以根据实际需求对链表进行扩展,使得其可以满足更复杂的问题。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C语言实例真题讲解数据结构中单向环形链表 - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • 在应用程序级别之外使用注册为allowDefinition=’MachineToApplication’的节是错误的

    这个错误是在ASP.NET应用程序中经常遇到的一个常见问题。它发生在使用Web.config配置文件时,如果将一个只允许在虚拟目录级别下生效的配置元素,添加到两个或多个子应用程序中,则会导致此错误。 解决这个问题的方法有以下几个步骤: 1.概念解释在应用程序级别之外使用注册为allowDefinition=’MachineToApplication’的节是错…

    other 2023年6月25日
    00
  • javascript的indexOf忽略大小写的方法

    JavaScript的indexOf忽略大小写的方法攻略 在JavaScript中,indexOf方法用于查找字符串中某个子字符串的位置。默认情况下,indexOf方法是区分大小写的,但是我们可以通过一些技巧来实现忽略大小写的搜索。下面是一种常用的方法: 将字符串转换为小写或大写形式。 使用转换后的字符串进行搜索。 下面是一个示例说明: // 示例1:忽略大…

    other 2023年8月18日
    00
  • Axure怎么制作日历日期选择框效果?

    Axure制作日历日期选择框效果攻略 Axure是一款强大的原型设计工具,可以用来制作交互式的界面原型。下面是使用Axure制作日历日期选择框效果的完整攻略。 步骤一:创建基本框架 首先,我们需要创建一个基本的框架来容纳日历和日期选择器。可以使用Axure的“Dynamic Panel”组件来实现这一点。在页面上拖动一个Dynamic Panel组件,并设置…

    other 2023年7月29日
    00
  • 使用whiptail写linux字符界面ssh链接工具2.0

    使用whiptail编写字符界面ssh链接工具2.0 1. 引言 在Linux系统中,使用ssh命令可以方便地登录远程主机,进行管理和操作。但是,如果需要经常登录多个主机,手动输入IP地址,用户名和密码是比较繁琐的事情。因此,为了提高效率,我们可以使用一个字符界面的ssh链接工具来管理和连接多个主机。 本文将介绍如何使用Whiptail编写一个字符界面的ss…

    其他 2023年3月28日
    00
  • uniapp导入导出excel

    uniapp导入导出excel攻略 在uniapp中,可以使用js-xlsx库实现导入导出excel。以下是详细的攻略: 步骤 以下是导入导出excel的步骤: 安装-xlsx库。 在uniapp项目中,使用npm安装js-xlsx库。 bash npm install xlsx –save 导入excel文件。 在uniapp中,可以使用uni.choo…

    other 2023年5月7日
    00
  • tkinter控件详细介绍

    以下是“tkinter控件详细介绍”的完整攻略: tkinter控件详细介绍 Tkinter是Python的标准GUI库,用于创建图形界面。Tkinter提供了许多控件,用于创建各种GUI应用程序。以下是一些常用的Tkinter控件及其用法: Label Label控件用于在GUI中显示文本或图。以下是一个示例: from tkinter import * …

    other 2023年5月7日
    00
  • Matlab实现时间序列预测分类实例代码

    当涉及到使用Matlab实现时间序列预测分类时,以下是一个完整的攻略,其中包含两个示例说明: 1. 数据准备 首先,需要准备时间序列数据集。确保数据集包含时间序列的观测值和相应的标签。可以使用Matlab的数据导入功能,如readtable或csvread,将数据加载到Matlab中。 示例说明1: 假设我们有一个包含每日气温观测值和天气类型标签的数据集。可…

    other 2023年10月18日
    00
  • 网页flash插件怎么设置允许_浏览器如何设置flash插件

    以下是关于如何设置浏览器允许Flash插件的攻略,包括Chrome和Firefox浏览器的设置方法,以及两个使用Flash插件的示例说明。 Chrome浏览器设置Flash插件 Chrome浏览器默认情况下已经禁用了Flash插件,需要手动设置才能允许使用。以下设置Chrome浏览器允许Flash插件的步骤: 打开Chrome浏览器,在地址栏中输入chrom…

    other 2023年5月7日
    00
合作推广
合作推广
分享本页
返回顶部