链表应用:两数相加

2023-11-06

关于链表

链表是一种极其重要的数据结构,因为对指针和抽象思维的要求较高,一度成为身边同学最痛恨的对象。

我在将这里演示如何使用链表制作一个可以按位储存数字的容器。鉴于本人亦初学者,有错误请各位在评论区指正。

这里还是以介绍链表为主,算法部分苦于我表达力不足,只能尽量多写注释,望海涵。

链结

链结是链表最基本的结构。

//链结的结构其实非常简单
//typedef 的声明方式可以避免之后重复写struct。
//C++选手可以无视这种方法。
typedef struct _Node
{
	//Data field
	int num;
	
	//Pointer, points to the next node.
	_Node* next;
}Node;

num用来存储一位数字,每一个Node代表一位数。

严格按照如下概念图来构造链表:

Head
A
B
许多节点
NULL

从空链表开始

链表的头和尾是确定的(Head和NULL)。

//如果忽略head存储的值,这就是一个简单的空链表。
Node* Head={val,NULL};
//不过更常见的是下面这种方式:
//我们需要的不过是一个可以指向链结的东西
Node* Head=NULL;

我们要做的就是实现一个可以向里面添加链结的函数,来扩充我们的链表。

添加链结

添加链结最主要的方法有3:头插法、尾插法、中插法。中插法更适合因地制宜地去使用,这里主要演示前两种。
·

头插法

//头插法
//返回的是指向新加入的链结的指针
Node* add(Node** phead,int val)//要改变指针本身,就传入指针的地址。
{
	//构建一个待插入的链结
	Node* node=(Node*)malloc(sizeof(Node));
	/*一定要使用malloc把node存储在堆区(heap),
	  直接在函数内声明的变量会在函数调用结束的时候灰飞烟灭
	  这样返回的指针指向的地址没有意义。*/
	node->num=val;
	node->next=NULL;//养成好习惯
	
	//把链结node加入链表中去
	Node* temp=*phead;
	*phead=node;
	node->next=temp;

	return node;
}

·
如果暂时感觉到难以理解,不妨拿起纸笔画一下上面的概念图,理清思路,体会一下C语言的招牌特色:面向过程。
`

//由add可以实现一个链表构造函数
Node* struct_list(int num)//输入需要的节点数量
{
	Node* head = NULL;
	
	for(int ix = 0; ix < num; ix++)
		add(&head, val);//val值随意
	
	return head;
}

`

尾插法

尾插法比头插法复杂一些,需要用一个静态变量static Node* tail来记录链表尾的位置。static变量存在于静态区,在整个文件中有效,不用担心会被刷新。
因为其文件作用域特性,static有时候也会被用来声明一个只在这个源代码文件中有效的变量。而不加static会变为全局变量(global variable)。

//尾插法
Node* add(Node** phead,int val)
	//构建一个待插入的链结
	Node* node=(Node*)malloc(sizeof(Node));
	
	node->val=val;
	node->next=NULL;
	
	//把链结node加入链表中去
	static Node* tail=NULL;//避免野指针
	
	if(!phead)//在这里,需要判断链表是否非空
	{
		*phead=node;
		tail=node;
	}
	else
	{
		tail->next=node;
		tail=tail->next;
	}

	return node;
}

也可以基于这个原理写一个构造链表函数。你依然可以根据自己的想法去实现更有特色的构造链表函数。

其实要实现主题功能,学习到这里就已经够了。不过我这里还是会介绍一下链表其他的操作以及其对应的函数。

哦,别忘了删除链表,及时释放内存:

void release_list(Node** phead)
{
	Node* tail,*ptr;
	
	if(!*phead)//空链表,无需释放,退出
        return;

	for(tail=*phead,ptr=tail->next; ptr; tail=ptr,ptr=ptr->next)
		free(tail);
	//链表的for遍历
	free(tail);
	*phead=NULL;
}

我们注意到在如上代码里面有两种常见的代码写法:

Node* ix;
for(ix = head; ix; ix = ix->next)

用指针迭代链表是非常重要的操作,ix=ix->next是指针移动的方式。
条件 ix 可用是因为NULL有如下宏定义:

#define NULL 0
//限定Visual Studio 2019
//C++是nullptr
//相应的,一般对指针操作时要保证指针非空,可以采取如下形式:
if(ptr&&(Condition))
...

掌握了如上原理,以下的操作可以自己实现

遍历打印链表内容

void print_list(const Node* head)//不希望改变值,使用const
{
    for (; head ;head = head->next)
        printf("%-4d", head->num);//%-4d表示用4格空间,左对齐打印一个int。
}

删除链结

可能有一点难度,不妨对照概念图多试几次

void delete_node(Node** phead,int key)
{
    Node *tail = *phead, *ptr = NULL;

    if(!tail)//空链表,异常
        return;

    ptr = tail->next;

    while(ptr)//从第二个开始搜索目标,如果只有一个链结,循环就不会执行
    {
        if(ptr->num==key)
        {
            tail->next = ptr->next;
            free(ptr);
            ptr = tail->next;
        }
        else
        {
            tail = ptr, ptr = ptr->next;
        }
        
    }
    if((*phead)->num==key)//检查第一个是不是目标
    {
        *phead = ptr;
        free(*phead);

        if(ptr)
        {
            tail = ptr;
            ptr = ptr->next;
        }
    }
}

*:搜索链结不妨自己试一下。

两数相加

这是leetcode里面的一道题,同前面两数之和难度形成对比。。
原题:

对于用链表倒序表示的两个数,要求实现两数相加
考虑情况:

1,进位
2,链表不等长(相加的数的位数不一)
3,和的位数高于两链表位数,需要添加。
原题

//我们可以在刚才的基础下,构建这样一个算法。
//假定两个链表l1,l2已经给出。
Node* addNumbers(Node* l1, Node* l2)
{
    Node *head = NULL;//新链表
    Node *tail = NULL;

    int carry = 0;//进位值
    int n1, n2;//两数
    int sum = 0;//两数相加

    while (l1||l2)//解决问题2,取l1,l2最长长度
    {
        n1 = l1 ? l1->num : 0;
        n2 = l2 ? l2->num : 0;//不够长的部分视作0

        sum = n1 + n2 + carry;
        carry = sum / 10;//利用窄化,抛弃小数部分

        if(!head)//第一次执行,tail未曾初始化
        {
            head = (Node *)malloc(sizeof(Node));
            *head = Node{sum % 10, NULL};//结构体字面量,也叫做无名结构体
            tail = head;
        }

        else//tail 已经初始化
        {
            tail->next=(Node*)malloc(sizeof(Node));
            tail=tail->next;
            tail->num=sum%10;
            tail->next=NULL;
        }

        if(l1)//向后推
            l1 = l1->next;
        if(l2)
            l2 = l2->next;
    }

    if(carry>0)//注意最后一位可能还需要进位
    {
        tail->next = (Node *)malloc(sizeof(Node));
        *tail->next = Node{carry, NULL};
    }

    return head;
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

链表应用:两数相加 的相关文章

随机推荐

  • Spring Cloud 学习笔记二:搭建微服务工程之Eureka 注册中心开启安全认证

    目录 Eureka 注册中心开启密码认证 Eureka 注册中心开启密码认证 Eureka 自带了一个 Web 的管理页面 方便我们查询注册到上面的实例信息 但是有一个问题 如果在实际使用中 注册中心地址有公网 IP 的话 必然能直接访问到
  • 如何在30天内,通过TikTok变现一万美金。按照我的方法,你也可以

    大家好 我是项柚 最近创作者基金愈发火热 Tiktok又热了起来 但还是很多朋友停留在川普封停TT的时间节点上 一直没有时间 今天特意写一篇文章来详细分析 其实圈子很重要 方向很重要 所以很多Tiktok运营者做不好的原因是没有交流的圈子
  • [HFCTF2020]EasyLogin

    知识点 jwt伪造 jwt 全称 Json Web Token 是一种令牌格式 可以用来区分各个用户 形式是下面这样 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 eyJzZWNyZXRpZCI6MSwidXNl
  • GitHub C 和 C++ 开源库的清单(含示例代码)

    内容包括 标准库 Web应用框架 人工智能 数据库 图片处理 机器学习 日志 代码分析等 标准库 C 标准库 包括了STL容器 算法和函数等 C Standard Library 是一系列类和函数的集合 使用核心语言编写 也是C ISO自身
  • PintOS lab2 User Programs 实验记录

    Background 大体流程如下图所示 显然这时候start process无法被调度到 然后start process 里面load out文件 o文件就是对象文件 是可重定向文件的一种 通常以ELF格式保存 里面包含了对各个函数的入口
  • 教你手机如何查看真实的IP地址

    有朋友不会查询自己手机的IP地址 很多时候我们需要使用vpn切换手机当前的IP 如何判断我们切换IP成功了呢 今天站长就教你手机如何查看目前真实的IP地址 1 打开手机浏览器 2 在搜索框里输入 ip 然后点击搜索 在搜索结果页面就会显示你
  • ESP32 上快捷部署 Tensorflow lite 机器学习(TinyML)

    在这篇文章中 我将向您展示使用 Arduino IDE 将 TensorFlow Lite 模型部署到 ESP32 的最简单方法 无需任何编译内容 Arduino 库 这个 Arduino 库是为了简化使用 Arduino IDE 将用于微
  • 4.8xml于json

    HTTP 协议 HyperText Transfer Protocol 超文本传输协议 是 TCP IP 协议集中的协议 是一个简单的请求 响应协议 指 定了客户端发送给服务器的消息以及服务器的响应 所有的 WWW 文件都必须遵守这个标准
  • matplotlib绘制饼状图

    源自http blog csdn net skyli114 article details 77508430 ticket ST 41707 PzNbUDGt6R5KYl3TkWDg passport csdn net pyplot使用pl
  • 接口测试基础

    目录 一 接口及接口测试概念 1 接口 接口的类型 2 接口测试 二 HTTP协议 1 HTTP协议的特点 2 URL格式 3 HTTP请求 4 HTTP响应 三 接口规范 1 传统风格接口 2 RESTful风格接口 四 接口测试流程 1
  • Python 11. OpenCV 透视变换

    import cv2 import numpy as np from matplotlib import pyplot as plt img cv2 imread pic4 PNG rows cols img shape 2 cv2 ims
  • 支持图文转换!PSD文档处理工具Aspose全新升级

    Aspose PSD是高级PSD和入门级AI文件格式操作API 允许创建和编辑Photoshop文件 并提供更新图层属性 添加水印 执行图形操作或将一种文件格式转换为另一种文件的功能 没有任何Adobe Photoshop或Adobe Il
  • [系统

    系统环境说明 系统 Deepin V20 平台 amd64 参考文献 asdf maven asdf document asdf plugins asdf vm安装 见多版本管理命令行工具asdf vm安装及使用 asdf vm安装Mave
  • 「C++学习笔记」面向.Net Core的(C++)CLR类库非专业入门(+使用Opencv)

    关键词 C CLR Net Core Net Famework Opencv C 目录 什么是CLR类库 本文说明 创建Demo程序 调用dll 通过项目引用 通过dll文件引用 其他还没完全清楚的坑 有关C CLI这块的资料真的很少而且都
  • 如何看待ChatGPT

    如何看待ChatGPT 如何看待ChatGPT 语言学家乔姆斯基说 这是一个抄袭的机器 欺骗性机器 ChatGPT使用大量文本数据进行训练 然后以一种令人信服的修饰语句展现 这使得它和人的互动能力更加契合 但是仍然不是一个充满创造力的智能机
  • 微信小程序之拨打电话

    微信小程序拨打电话功能的实现是采用wx makePhoneCall 具体方法如下 wxml lt view gt 电话 15888888888 lt view data ph 15888888888 bindtap callPhone gt
  • 【Android 12 AOSP学习】Android 12源码下载编译

    一 搭建环境 liunx系统 Ubuntu20 04 Android系统 12 1 安装 Repo 下载Repo前先安装 curl 库 sudo apt get install curl 下载好 curl 库后 设置清华源下载 Repo 然
  • 前端 JavaScript 提取 JSON 数据

    原文地址 假如我们从后端接收到了以下 JSON 数据 id 1 name Xu Albter age 18 使用 JSON parse 方法处理以上数据 将其转换为 JavaScript 对象 var obj JSON parse id 1
  • select函数缺陷分析

    与poll和epoll不同 select函数是事件为单位组织文件描述符 监视的行为较为单一 函数原型 int select int nfds fd set readfds fd set writefds fd set exceptfds s
  • 链表应用:两数相加

    关于链表 链表是一种极其重要的数据结构 因为对指针和抽象思维的要求较高 一度成为身边同学最痛恨的对象 我在将这里演示如何使用链表制作一个可以按位储存数字的容器 鉴于本人亦初学者 有错误请各位在评论区指正 这里还是以介绍链表为主 算法部分苦于