zoukankan      html  css  js  c++  java
  • 基本数据结构 -- 链表的遍历、查找、插入和删除

      本文将使用 C 语言来实现一个单链表,并实现遍历、查找、插入、删除等操作。

    一、创建一个单链表

       首先,定义一个存放结点相关信息的结构体,结构体有两个元素,分别是键值和一个指向下一节点的指针。

    /* 用于存放结点信息的结构体 */
    struct node {
        int key;
        struct node *next;
    };
    
    typedef struct node Node;
    typedef struct node *PtrToNode;

       想要创建一个单链表,可以先创建一个表头结点(哑结点),然后在表头结点后不断插入新的结点即可,需要注意的是,每新建一个结点都要为该结点分配一段内存空间。

    /* 创建一个链表 */
    PtrToNode CreateList(int listLen)
    {
        int i, keyValue;
    
        /* 创建一个表头结点,并为其分配内存空间 */
        PtrToNode headPtr = (PtrToNode)malloc(sizeof(Node));
    
        if (headPtr == NULL) {
            perror("malloc failed!
    ");
            exit(EXIT_FAILURE);
        }
    
        PtrToNode tailNode = headPtr;    // 创建一个表尾结点,并将表头结点赋给尾结点
        tailNode->next = NULL;
    
        for (i = 0; i < listLen; i++) {
            /* 创建一个新结点,并为其分配内存空间 */
            PtrToNode newNode = (PtrToNode)malloc(sizeof(Node));
            if (newNode == NULL) {
                perror("malloc failed!
    ");
                exit(EXIT_FAILURE);
            }
    
            printf("请输入第 %d 个结点的键值:", i + 1);
            scanf_s("%d",&keyValue);
    
         // 将 newNode 插入链表尾部
            newNode->key = keyValue;    // 赋键值
            newNode->next = NULL;     // next 指针指向 NULL
            tailNode->next = newNode;   // 这里的 tailNode 存放的是上一次循环中创建的 newNode,也就是现在新建结点的前驱结点
                           // 故而这里是将前驱结点的 next 指针指向当前结点
    
            tailNode = newNode;       // 将当前结点赋给 tailNode(实际上,tailNode 就起着一个临时结点的作用)
        }
    
        return headPtr;
    }

    二、遍历一个单链表

    /* 遍历链表 */
    void TraverseList(PtrToNode List)
    {
        PtrToNode ptr = List->next;
        if (ptr == NULL) {
            printf("链表为空
    ");
        }
    
        while (ptr != NULL) {
            printf("%d ", ptr->key);
            ptr = ptr->next;
        }
    }

       这段代码根据链表表尾结点的 next 指针指向 NULL 来遍历整个链表。

    三、查找一个元素

    /* 查找一个元素 */
    PtrToNode FindElement(PtrToNode List,int val)
    {
        PtrToNode ptr = List->next;
        if (ptr == NULL) {
            printf("链表为空
    ");
            return NULL;
        }
    
        while (ptr != NULL && ptr->key != val) {
            ptr = ptr->next;
        }
    
        if (ptr != NULL) {
            printf("找到 %d 了
    ", val);
        }
        else
        {
            printf("没有找到 %d
    ", val);
        }    
        
        return ptr;
    }

      这段代码查找元素 val 是否在链表中,如果在,则打印元素已找到的信息,并返回该元素在链表中所在的结点;如果不在链表中,则打印没找到的信息,并返回一个空指针。

    四、插入一个元素

    /* 插入一个元素 */
    void InsertElement(PtrToNode List,PtrToNode Position,int val) 
    {
        PtrToNode tmpNode = (PtrToNode)malloc(sizeof(Node));
        if (tmpNode == NULL) {
            perror("malloc failed!
    ");
            exit(EXIT_FAILURE);
        }
    
        tmpNode->key = val;
        tmpNode->next = Position->next;
        Position->next = tmpNode;
    }

      这段代码将元素 val 插入到链表中指定结点的后面。 

    五、删除操作

    5.1 删除整个链表

    /* 删除整个链表 */
    void DeleteList(PtrToNode List)
    {
        PtrToNode position, tmpNode;
        position = List->next;
        List->next = NULL;
        while (position != NULL) {
            tmpNode = position->next;        // 先将当前结点的 next 指针赋给临时结点保存
            free(position);                    // 然后释放当前结点
            position = tmpNode;                // 再将以保存的 next 指针赋给 position,即为下一个要删除的结点
        }
    }

      删除整个链表时,需要注意一点,要提前将要删除结点的 next 指针保存下来,再释放该结点。而不能在释放了一个结点后再去利用已释放结点的 next 指针去释放下一个结点,因为此时上一个结点已经被释放了,故而找不到 next 指针。此外,由于在创建链表时,每插入一个新的结点都会用 malloc 来给结点分配一块内存,故而在删除链表时,每释放一个结点也应该使用 free 来释放一次内存。

    5.2 删除一个元素

    /* 删除一个元素 */
    void DeleteElement(PtrToNode List,int val)
    {
        PtrToNode tmpNode;
        PtrToNode prev_position = FindPrevNode(List, val);
        if (prev_position->next == NULL) {
            printf("要删除的元素不存在!
    ");
        }
        else {
            tmpNode = prev_position->next;
            prev_position->next = tmpNode->next;
            free(tmpNode);
        }
    
    }
    
    /* 获取元素的前驱结点 */
    PtrToNode FindPrevNode(PtrToNode List, int val)
    {
        PtrToNode prev_position = List;
    
        while (prev_position->next != NULL && prev_position->next->key != val) {
            prev_position = prev_position->next;
        }
    
        return prev_position;
    }

      删除一个元素时,需要先找到该元素的前驱结点。 

    参考资料:

    《算法导论 第三版》

    《数据结构与算法分析——C语言描述》

  • 相关阅读:
    视频学习网站
    保存文章
    maven常见命令总结
    Eclipse vs IDEA快捷键对比大全(win系统)
    JS调用android逻辑方法
    【原创】不用封装jar包 直接引入工程使用的方法(类似android的 is Library功能)
    windows下eclipse+hadoop2
    Solaris用户管理(一):用户与组管理
    jquery 操作 checkbox
    模拟用户登录的操作
  • 原文地址:https://www.cnblogs.com/tongye/p/9713259.html
Copyright © 2011-2022 走看看