• 上机实验二 设计单循环链表 西安石油大学数据结构


    实验名称:设计单循环链表

    (1)实验目的:掌握线性表的链式存储结构;掌握单循环链表及其基本操作的实现。

    (2)主要内容:实现单循环链表的初始化、求数据元素个数、插入、删除、取数据元素等操作;用插入法建立带头结点的单循环链表;设计一个测试主函数验证所设计单循环链表的正确性。

    1.实验目的

    掌握线性表的链式存储结构;掌握单循环链表及其基本操作的实现。

    2.问题描述

    利用C语言设计实现单循环链表,并实现初始化、求数据元素个数、插入、删除、取数据元素等基本操作。使用插入法建立带头结点的单循环链表,并设计一个测试主函数验证所设计单循环链表的正确性。

    3.基本要求

    具体要求如下:

    1. 设计一个结构体表示链表的节点,包括数据域和指针域。

    2. 实现单循环链表的初始化操作,即创建一个空链表。

    3. 实现求数据元素个数的操作,即统计链表中已有的节点数。

    4. 实现插入操作,在指定位置插入一个节点,并将新节点链接到链表中。

    5. 实现删除操作,删除指定位置的节点。

    6. 实现取数据元素的操作,返回指定位置的节点值。

    7. 使用插入法建立带头结点的单循环链表,即通过用户输入逐个插入节点来创建链表,直到用户结束输入。

    8. 编写一个测试主函数,验证所设计单循环链表的正确性,包括对各个操作的测试。测试包括但不限于以下内容:创建一个空链表并输出链表元素个数。
      插入若干节点,并验证插入后链表的正确性。
      删除某个位置的节点,并验证删除后链表的正确性。
      取某个位置的节点值,并输出验证结果。

    4.测试数据

    初始链表为空,链表元素个数为:0

    插入后的链表元素:10

    插入后的链表元素:5 15 10 20

    删除后的链表元素:15 20

    取节点值的结果:

    Position 0: 15

    Position 1: 20

    Position 2: -1

    5.算法思想

    链表数据结构的基本操作,包括初始化链表、获取链表元素个数、在指定位置插入节点、删除指定位置的节点、获取指定位置节点的值以及打印链表中的元素。其中,链表是一种线性结构,每个节点包括数据和指向下一个节点的指针,头结点不包含数据。

    该算法通过遍历链表的方式来找到指定位置的节点,然后进行相应的操作。具体实现方法包括:在空链表中插入第一个节点时,直接将头结点指向新节点;在链表头部插入节点时,将新节点的指针指向原头结点,再将头结点指向新节点;在链表中间和尾部插入节点时,在找到插入位置的前一个节点后,将新节点的指针指向原位置的节点,再将前一个节点的指针指向新节点;删除节点时,首先找到要删除节点的前一个节点,将前一个节点的指针指向要删除节点的下一个节点,然后释放要删除节点的内存空间;获取节点值时,找到指定位置的节点,返回其数据域的值。

    6.模块划分

    1. initList():初始化链表,返回头结点。
    2. listLength(Node* head):获取链表的元素个数。
    3. insertNode(Node* head, int position, int data):在链表指定位置插入节点。
    4. deleteNode(Node* head, int position):删除链表指定位置的节点。
    5. getNodeData(Node* head, int position):获取链表指定位置节点的值。
    6. printList(Node* head):打印链表中的元素。
    7. main():主函数。

    7.数据结构

    (1) 数据类型DataType定义如下:

    typedef struct {
        int number;
        int cipher;
    } DataType;
    
    • 1
    • 2
    • 3
    • 4

    这个定义表示DataType结构体包含两个成员变量,即numbercipher,分别表示一个整数的数字和位数。

    (2) 带头结点单循环链表结点的结构体定义如下:

    typedef struct SCLNode {
        DataType data;
        struct SCLNode* next;
    } SCLNode;
    
    • 1
    • 2
    • 3
    • 4

    这个定义表示SCLNode结构体是一个带头结点的单循环链表的节点,包含两个成员变量。其中,data是存储数据元素的DataType类型的变量。next是指向下一个节点的指针,类型为指向SCLNode结构体的指针。

    通过这样的定义,可以创建一个带头结点的单循环链表,每个节点存储一个数据元素,并且通过next指针连接起来形成循环链表。头结点的作用是指示链表的起始位置,尾节点的next指针指向头结点,形成循环。

    8.源程序

    #include 
    #include 
    
    typedef struct Node {
        int data;
        struct Node* next;
    } Node;
    
    // 初始化链表,返回头结点
    Node* initList() {
        Node* head = (Node*)malloc(sizeof(Node));
        head->next = NULL;  // 初始化时头结点指向NULL,形成空链表
        return head;
    }
    
    // 获取链表的元素个数
    int listLength(Node* head) {
        int count = 0;
        Node* current = head->next;
        while (current != NULL) {
            count++;
            current = current->next;
        }
        return count;
    }
    
    // 在链表指定位置插入节点
    void insertNode(Node* head, int position, int data) {
        Node* newNode = (Node*)malloc(sizeof(Node));
        newNode->data = data;
    
        Node* current = head;
        int count = 0;
        while (current != NULL && count < position) {
            current = current->next;
            count++;
        }
        newNode->next = current->next;
        current->next = newNode;
    }
    
    // 删除链表指定位置的节点
    void deleteNode(Node* head, int position) {
        Node* current = head;
        int count = 0;
        while (current->next != NULL && count < position) {
            current = current->next;
            count++;
        }
        if (current->next != NULL) {
            Node* temp = current->next;
            current->next = temp->next;
            free(temp);
        }
    }
    
    // 获取链表指定位置节点的值
    int getNodeData(Node* head, int position) {
        Node* current = head->next;
        int count = 0;
        while (current != NULL && count < position) {
            current = current->next;
            count++;
        }
        if (current != NULL)
            return current->data;
        else
            return -1;  // 返回-1表示节点不存在
    }
    
    // 打印链表中的元素
    void printList(Node* head) {
        Node* current = head->next;
        while (current != NULL) {
            printf("%d ", current->data);
            current = current->next;
        }
        printf("\n");
    }
    
    int main() {
        Node* head = initList();
    
        printf("初始链表为空,链表元素个数为:%d\n", listLength(head));
    
        insertNode(head, 0, 10);  // 在空链表中插入第一个节点
        printf("插入后的链表元素:");
        printList(head);
    
        insertNode(head, 0, 5);  // 在链表头部插入节点
        insertNode(head, 1, 15); // 在链表中间插入节点
        insertNode(head, 3, 20); // 在链表尾部插入节点
        printf("插入后的链表元素:");
        printList(head);
    
        deleteNode(head, 0); // 删除头结点
        deleteNode(head, 1); // 删除链表中的某个节点
        deleteNode(head, 2); // 删除尾节点
        printf("删除后的链表元素:");
        printList(head);
    
        int data1 = getNodeData(head, 0); // 取链表头结点的数据
        int data2 = getNodeData(head, 1); // 取链表中间某个节点的数据
        int data3 = getNodeData(head, 2); // 取链表尾节点的数据
        printf("取节点值的结果:\n");
        printf("Position 0: %d\n", data1);
        printf("Position 1: %d\n", data2);
        printf("Position 2: %d\n", data3);
    
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112

    9.测试情况

    在这里插入图片描述

    进行测试结果分析

    初始化链表后,链表为空,元素个数为0。

    在空链表中插入第一个节点,插入后的链表元素为10。可以看到插入操作正常。

    在链表头部插入节点5,链表中间插入节点15,链表尾部插入节点20。插入后的链表元素为5 15 10 20。可以看到在不同位置插入节点的操作正常。

    删除头结点,删除链表中的某个节点,删除尾节点。删除后的链表元素为5 10。可以看到删除操作正常。

    取链表头结点的数据,取链表中间某个节点的数据,取链表尾节点的数据。取节点值的结果如下:

    Position 0: 5
    Position 1: 10
    Position 2: -1
    可以看到,成功获取了节点的值,并且当位置越界时返回了-1。说明获取节点值的功能正常。

    综上所述,根据测试结果,代码实现了链表的基本操作,并且功能正常。

    描述存在的问题及建议

    存在的问题是在插入和删除节点时没有进行越界检查,可能导致访问非法内存。建议在插入和删除节点的代码中增加对位置的合法性检查,确保不会越界。

    另外,代码中的打印函数printList()可以优化,避免每次都要遍历整个链表才能打印出结果。可以考虑在插入、删除和修改节点时维护链表的长度,并在需要打印时直接使用链表长度进行循环打印。这样可以提高效率。

  • 相关阅读:
    阿里提前批(阿里云)一面30min
    学习 MySQL 需要知道的 28 个小技巧
    vite进行打包时如何把某个静态文件原封不动地拷贝到打包后的文件中
    [附源码]java毕业设计网上书店的设计
    Intel 芯片 Mac 如何重新安装系统
    【算法刷题-栈与队列篇】
    重上吹麻滩——段芝堂创始人翟立冬游记
    java方法返回多个值,使用Pair、Triple
    MySQL进阶实战9,InnoDB和MyISAM的数据分布对比
    Quantlab整合Alpha158因子集,为机器学习大类资产配置策略做准备(代码+数据)
  • 原文地址:https://blog.csdn.net/shaozheng0503/article/details/133783840