编程导航算法通关村第1关 | 单链表的基础与构造方法

这篇具有很好参考价值的文章主要介绍了编程导航算法通关村第1关 | 单链表的基础与构造方法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1 单链表的基础与构造方法(C语言)

1.1 链表的结构

  • 什么是链表
    不强制要求数据在内存集中存储,可以分散存储在内存中。例如数据{1,8,6,2},在链表的存储状态可能如图示:
    编程导航算法通关村第1关 | 单链表的基础与构造方法,算法,链表,c语言只要让每一个元素知道它下一个元素的位置,就可以依次找出各个元素。
    那么,链表是如何实现这种存储数据间的关系呢?为每一个元素配置一个指针,每个元素的指针指向自己的直接后继数据元素。通过指针建立数据连接关系。

1.2 链表的构建

  • 链表组成
    链表的”元素“由本身的数据信息和指针组成,标准定义如下图:
    编程导航算法通关村第1关 | 单链表的基础与构造方法,算法,链表,c语言
    数据域用来存储元素的值。
    指针域用来存放指针。
    两部分构成的整体称为结点,也就是链表的基本单位。
    也就是说,链表中实际存放的是一个一个的结点,
    数据元素存放在各个结点的数据域中。如数据{1,8,6,2},用链表存储可表示为:
    编程导航算法通关村第1关 | 单链表的基础与构造方法,算法,链表,c语言
    链表中第一个结点的存储位置叫做头指针;
    最后一个结点的指针为"空",通常用NULL表示。
  • C语言代码实现链表创建
// 定义链表的结点
struct ListNode
{
    int val;               // 定义数据
    struct ListNode *next; // 定义指针,由于指针指向的是结构体的地址,所以定义指向结构体类型的指针变量
};
// 创建链表函数,返回指向结构体类型的指针变量
struct ListNode *initListNode()
{
    int i = 0;
    struct ListNode *head = NULL;                                 // 定义头指针
    struct ListNode *temp = (ListNode *)malloc(sizeof(ListNode)); // 定义第一个结点, temp 为第一个节点的地址  malloc返回值类型为(void *),所以用强制转换变为(ListNode *)类型
    temp->val = 0;                                                // 第一个节点的数据域赋初值
    temp->next = NULL;                                            // 给第一个节点的指针域赋初值
    head = temp;                                                  // 给头指针赋值
    for (i = 1; i < 10; i++)
    {
        struct ListNode *a = (ListNode *)malloc(sizeof(ListNode)); // 创建节点
        a->val = i;                                                // 给结点的数据域赋值
        a->next = NULL;                                            // 给结点的指针域赋初值
        temp->next = a;                                            // 将地址给到上一个结点的指针域
        temp = a;                                                  // 让temp指向下一个结点  也就是a节点的地址,能够将之后的节点赋值给到a节点的指针域
    }

    return head;
}

1.3 遍历链表

  • 思路:只要知道链表的头指针地址,就可以获取第一个结点的数据域和指针域,当指针域的值不为空时,由于指针域为下一个结点的地址,就可以依次获取链表结点的值,直到获取的指针域为空时,表示已经到链表的最后一个结点,结束遍历。
    通过遍历可以得到链表数据的值和链表长度。
  • C语言代码实现链表遍历获取值和长度
//打印链表的值
void PrintListNode(struct ListNode *p)
{
    struct ListNode *temp = p; // 定义一个循环的指针变量,把链表的头指针给到它
    while (temp)               // 当temp的值不等于NULL时,打印链表的值,空有2种情况,列表本身空的,打印无值,以及到了链表的最后一个结点
    {
        printf("%d ", temp->val); // 打印值
        temp = temp->next;        // 指向下一个结点的地址
    }
    printf("\n");
}
//获取链表的长度
int32_t getLength(struct ListNode *p)
{
    struct ListNode *temp = p; // temp指针用来遍历链表
    int32_t length = 0;
    // 只要temp指向结点的next值不是NULL,就执行输出语句。
    while (temp)
    {
        // struct ListNode* f = temp;//准备释放链表中的结点
        length++;
        temp = temp->next;
        // free(f);
    }
    return length;
}

输出结果
编程导航算法通关村第1关 | 单链表的基础与构造方法,算法,链表,c语言

1.4 链表的插入

  • 单链表的插入要考虑3种情况:首部、中部、尾部。
  • 链表表头插入
    新结点比较简单,容易出错的是经常忘记把head需要重新指向表头。创建一个新结点后,执行newNode ->next =
    head,就可以链接原来的链表;之后,执行 head = newNode,把头指针重新指向表头即可,如下图:
    编程导航算法通关村第1关 | 单链表的基础与构造方法,算法,链表,c语言
  • 链表中间插入
    在中间位置,要先遍历找找到要插入的位置(如值为8的第三个结点位置),然后将当前结点接入到前驱结点和后继结点之间,但是到该位置后我们却不能获得前驱结点了,也就无法将结点接到前面去。这就好比是一边过河一边拆桥,结果自己也回不去了。
    为此,我们需要在目标结点的前一个位置停下来,使用cur->next的值而不是cur的值来判断,这是链 表最常用的策略。
    例如下图中,如果要在第三个结点(值为8的位置)的前面插入,当cur->next = node(8)就应该停下,此时cur->val =
    1,然后需要给newNode前后接2根线,此时只能先让newNode->next =
    cur->next(图中虚线),然后cur->next = newNode,而且顺序不能颠倒。
    为什么顺序不能颠倒?
    由于每一个结点只有一个next,因此执行了cur->next =
    newNode后,结点Node(1)和Node(8)的连接就断了,所以不能颠倒。
    编程导航算法通关村第1关 | 单链表的基础与构造方法,算法,链表,c语言

  • 链表尾部插入
    将尾结点指向新结点
    编程导航算法通关村第1关 | 单链表的基础与构造方法,算法,链表,c语言

  • C语言实现链表插入

/*
 链表插入
 head:待插入的链表
 nodeInsert: 插入结点
 position:插入位置 
*/
struct ListNode *insertNode(struct ListNode *head, struct ListNode *nodeInsert, int32_t position)
{
    if (head == NULL) // 待插入链表为空,可以认为待插入结点就是链表的头结点,也可以抛出不能插入的异常
    {
        nodeInsert->next = NULL;
        return nodeInsert;
    }

    int32_t len = getLength(head);
    if ((position < 1) || (position > (len + 1))) //插入位置限制,如果待插链表有2个结点,那么插入位置可以为1、2、3,其他位置非法
    {
        printf("插入位置非法");
    }
    if (position == 1)
    {
        nodeInsert->next = head;
        head = nodeInsert;
        return head;
    }
    struct ListNode *pNode = head;
    int count = 1; // 判断插入结点的前一个位置
    // if (count != position - 1)
    while (count < position - 1)
    {
        pNode = pNode->next;
        count++;
    }
    nodeInsert->next = pNode->next;
    pNode->next = nodeInsert;

    return head;
}

输出结果
编程导航算法通关村第1关 | 单链表的基础与构造方法,算法,链表,c语言

1.5 链表的删除

  • 链表的删除同样分为删除头部元素,中部元素和尾部元素三部分。

  • 删除头部结点元素
    把头指针指向后一个结点,执行 head = head->next 就行。如下图示,将head向前移动一次之后,原来的结点不可达,然后就可以将其删除。
    编程导航算法通关村第1关 | 单链表的基础与构造方法,算法,链表,c语言

  • 删除尾部结点元素
    找到要删除元素的前驱结点,这里同样要在提前一个位置判断,例如下图中,删除值为2的结点,其前驱结点是值为1的结点,遍历的时候需要判断cur->next是否为2,如果是,则只要执行cu->next = NULL即可,此时值为2的结点就可以删掉了。
    编程导航算法通关村第1关 | 单链表的基础与构造方法,算法,链表,c语言

  • 删除中间结点元素
    删除中间结点时,也用cur->next进行比较,找到位置后,将cur->next指针的值更新为cur->next->next ,然后就可以放新删除中间值为1的结点,如下图示:
    编程导航算法通关村第1关 | 单链表的基础与构造方法,算法,链表,c语言

  • C语言实现

/*
 链表删除
 head:待插入的链表
 position:插入位置
*/
struct ListNode *deleteNode(struct ListNode *head, int32_t position)
{
    if (head == NULL) // 待插入链表为空,可以认为待插入结点就是链表的头结点,也可以抛出不能插入的异常
    {
        return NULL;
    }

    int32_t len = getLength(head);
    if ((position < 1) || (position > len))
    {
        printf("删除位置非法\n");
        return head;
    }
    if (position == 1)
    {
        struct ListNode *temp = head;
        head = head->next;
        free(temp);
        return head;
    }
    else
    {
        struct ListNode *curNode = head;
        int count = 1; // 判断插入结点的前一个位置
        // if (count != position - 1)
        while (count < position - 1)
        {
            curNode = curNode->next;
            count++;
        }
        struct ListNode *deleteNode = curNode->next;
        curNode->next = curNode->next->next;
        free(deleteNode);
        return head;
    }
}

输出结果
编程导航算法通关村第1关 | 单链表的基础与构造方法,算法,链表,c语言文章来源地址https://www.toymoban.com/news/detail-621233.html

到了这里,关于编程导航算法通关村第1关 | 单链表的基础与构造方法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 编程导航算法第一关 |链表的基础

    今天也是算法通关村刚开始,学习了链表。 首先,链表是一种最基本的结构,我们通常在收到一个链表的时候只有一个指向链表头的指针head,因为链表就是通过头指针来寻找其他结点的。 链表中的每个结点都存在它的数据和指向下一个节点的指针。 在遍历链表中,我们只需

    2024年02月15日
    浏览(26)
  • 编程导航算法通关村 | 链表中环的问题

    在链表中还有一类经典的问题,那就是判断链表中是否有环,如果有环,环的入口如何确定。 用Hash来做会很容易,遍历一遍,把每一个元素都放入map中,有环的话,那我们就一定能匹配到。 这里最重要的问题, 如果快的能到达表尾就不会有环,否则如果存在环,则慢指针一

    2024年02月14日
    浏览(30)
  • 算法通关村第二关——单链表加一

    LeetCode369 用一个非空单链表来表示一个非负整数,然后将这个整数加一。你可以假设这个整数除了 0 本身,没有任何前导的 0.这个证书的各个数位按照 高位在链表头部、低位在链表尾部 的顺序排列。 计算是从低位开始的,而链表是从高位开始的,所以要处理就必须反转过来

    2024年02月14日
    浏览(34)
  • 算法通关村第一关——链表青铜挑战笔记(单链表)

    在LeeCode中一般这样创建链表 要注意创建一个变量来遍历,不要把head丢掉了 count position - 1可以方便操作,还能防止下标越界(cur为null)

    2024年02月15日
    浏览(30)
  • [算法通关村] 1.2 链表的插入

    上一节我们谈到了链表的概念,以及链表的创建方法,忘记的小伙伴可以复习一下: [算法通关村] 1.1 单向链表的创建         今天我们来探究一下链表的插入,链表的插入共有 3 种可能性,分别是在链表的 头部 插入、在 中间 插入,和在链表的 尾部 插入(追加),不同

    2024年02月15日
    浏览(30)
  • [算法通关村] 1.1 单向链表的创建

    各位读者朋友们, 从今天开始,我将通过博文的形式,概述数据结构中应知必会的基本算法, 由于我更加熟悉 Java 语言,所以全程使用 Java 语言进行叙述, 如果您发现了文章中的错误,请您不吝赐教。         “链表”(Linked List)是一种常见的数据结构,用于存储和组

    2024年02月16日
    浏览(28)
  • 算法通关村第一关——链表经典问题之寻找两个链表的第一个公共结点

    这是一道经典的链表问题,来自剑指offer52,题目是这样的:输入两个链表,找出它们的第一个公共结点,如下图所示: 两个链表的头结点均已知,相交之后成为一个单链表,但是相交的位置未知,并且相交之前的结点数也是未知的,请设计算法找到两个链表的合并点。 第一

    2024年02月16日
    浏览(45)
  • 算法通关村第一关---链表经典问题之两个链表的第一个公共节点笔记

    源码地址:GitHub-算法通关村 1.hash 2.集合 3.栈 4.双指针

    2024年02月16日
    浏览(33)
  • 四种创建单链表的方法

    学习了这么久的数据结构,终于把链表吃透啦,下面是我整理的四种创建单链表的的方法 以及一些非常容易犯的错误,让我们一起来看看吧~ 目录 一、单链表的分类 二、单链表的初始化 2.1 初始化不带头结点的单链表 2.2 初始化带头结点的单链表 三、单链表的创建 3.1 创建不

    2024年02月08日
    浏览(29)
  • 【数据结构与算法】单链表的排序算法(选择,冒泡,递归)

    目录 选择排序 冒泡排序 快速排序 合并两条链表并排序 选择排序 链表的选择排序思想与数组的排序类似,但是链表需要先找到里面最小或者最大的值,然后将这个值用改链语句进行操作 我们先看这个改链语句的操作(min是笔者打错了应该是max,但是图已经画好了就没有改)

    2024年02月04日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包