Smaller And Smarter Python数据结构:链表相加

欢迎关注微信公众号:简说Python
关注后回复:1024,可以领取精选编程学习电子书籍。

这两天和几个朋友组了个互相督促学习群,想着督促一下自己学习,也督促自己的原创输出,其实很多时候都是懒,真不是没有东西可以写了,这不,我在我的免费知识星球简说编程里开了个新的标签日常编程问题,后面我会把自己学习工作中遇到的一些问题和解决方法记录到里面,有些可以扩展的点,我会写到微信公众号里。
我定的目标是:

我简单写了个规则,大家说可以,然后,我们就开始吧,我习惯把该做的事情提前一天做(如果有时间的话)。

今天给大家分享的书籍《Python程序员面试算法宝典》第一章第三小节:计算两个单链表所代表数之和。

如果你是第一次看,也许,你可以看看本系列下面的文章:
Smaller And Smarter Python数据结构:链表逆转
Smaller And Smarter Python数据结构:删除无序链表重复结点

今日问题

"""
目标:写一段程序,计算两个单链表所代表数之和
例如:
输入-> 9->0->3
输入-> 2->1->2
输出-> 1->2->5

过程:309 + 212 = 521
"""

"""
Objective: write a program to calculate the sum of the numbers represented by two single chain tables
For example:
Input - > 9 - > 0 - > 3
Input - > 2 - > 1 - > 2
Output - > 1 - > 2 - > 5

Process: 309 + 212 = 521
"""

首先我们写好链表的基本操作,在a_0_base.py文件中,目前包含对链表的定义类,初始化函数,遍历函数。(带头结点)

# -*- coding: utf-8 -*-
"""
@author = 老表
@date = 2019-10-19
@个人微信公众号 : 简说Python
"""


# 链表数据结构定义
class ListNode:
    def __init__(self, x):
        self.data = x
        self.next = None


class ListOperation:

    # 根据链表数据初始化链表
    @staticmethod
    def init_list(n_list):
        # 初始化一个头指针
        head = ListNode("head")
        cur = head
        for i in n_list:
            node = ListNode(i)
            cur.next = node
            cur = node  # 相当于 cur = cur.next,后移
        return head

    # 遍历链表
    @staticmethod
    def ergodic_list(head):
        cur = head.next
        while cur:
            print(cur.data)
            cur = cur.next

解题

开始程序前需提前导入前面写好的链表基本操作包和结点数据结构,在Linked_list的a_0_base.py中。

from Linked_list.a_0_base import ListOperation
from Linked_list.a_0_base import ListNode
方法一:递归去重
"""
Method One : 整数相加

核心思想:遍历两个链表,把链表转化为对应的整数,
然后整数相加,最后把结果转化为链表。

优点:思路顺畅,实现简单

时间复杂度:O(N)
空间复杂度:O(N)
"""
代码
# 写个辅助函数,将链表转变成整数
def link_to_int(head):
    i = 1  # 指数(位数)
    val1 = head.next  # 第一个结点
    sum1 = val1.data  # 先记录下第一个结点值,链表右边为高位
    while val1.next:  # 遍历链表
        a1 = val1.next.data  # 取出结点数据
        sum1 = sum1 + a1 * pow(10, i)  # 计算和
        i = i + 1  # 后移,指数加1
        val1 = val1.next  # 链表后移
    return sum1  # 返回计算结果

# 主功能函数
def links_sum_one(l1, l2):
    # 链表为空的情况,有一个链表为空,则返回另外一个链表
    if not l1.next:
        return l2
    if not l2.next:
        return l1
    # 调用写好的函数,将链表转为整数
    sum1 = link_to_int(l1)
    # print(sum1)
    sum2 = link_to_int(l2)
    # print(sum2)
    result = sum1 + sum2  # 计算和
    # print(result)
    head = ListNode("head")  # 创建一个新的头结点
    cur_node = head
    while result != 0:  # 按位将整数转变成为链表
        a0 = result % 10  # 取出余数,即从个位一个个取出
        result = result // 10  # 取商(整数部分 注意 / 表示取商,包含小数部分)
        node = ListNode(a0)  # 创建新的结点
        cur_node.next = node  # 结点插入
        cur_node = node  # 当前结点后移
    return head  # 返回头结点
方法二:顺序删除
"""
Method Two : 链表相加法

核心思想:同时遍历两个链表,把对应结点的数据相加,
存储到新的结点中,然后插入新的链表。

优点:代码简洁
难点:两个链表不一样长的情况不好处理

时间复杂度:O(N)
空间复杂度:O(N)
"""
代码
def links_sum_two(l1, l2):
    # 链表为空的情况,有一个链表为空,则返回另外一个链表
    if not l1.next:
        return l2
    if not l2.next:
        return l1
    flag = 0  # 进位
    i = 0  # 头结点指示器
    val1 = l1.next  # 获取第一个结点
    val2 = l2.next  # 获取第一个结点
    head = ListNode("head")  # 创建一个新的头结点
    cur_node = head  # 设置当前结点
    # 遍历链表,求和
    while val1 or val2 or flag != 0:
        a = val1.data if val1 else 0  # 取链表1数据
        b = val2.data if val2 else 0  # 取链表2数据
        sum1 = a + b + flag  # 计算对应结点和
        flag = sum1 // 10  # 取商(整数部分),计算进位
        node = ListNode(sum1 % 10)  # 创建新的结点
        cur_node.next = node  # 结点插入
        cur_node = node  # 当前结点后移
        val1 = val1.next if val1 else None  # 后移,遍历
        val2 = val2.next if val2 else None  # 后移,遍历
    return head  # 返回头结点
代码精进
def links_sum_three(l1, l2):
    head = ListNode("head")  # 创建一个新的头结点
    cur_node = head  # 设置当前结点
    l1 = l1.next  # 获取第一个结点
    l2 = l2.next  # 获取第一个结点
    val = 0  # 进位
    while val != 0 or l1 or l2:
        val, cur = divmod(val + (l1.data if l1 else 0) + (l2.data if l2 else 0), 10)
        # divmod 返回元组(x//y,x%y) (取商,取余)
        cur_node.next = ListNode(cur)  # 创建新结点,结点插入
        cur_node = cur_node.next  # 当前结点后移
        l1 = l1.next if l1 else None  # 后移,遍历
        l2 = l2.next if l2 else None  # 后移,遍历
    return head  # 返回头结点

测试代码

# 当然,也许还有别的方法,比如建一个辅助的链表
# 欢迎你说出你的想法

# 程序入口,测试函数功能
if __name__ == "__main__":
    s0 = ListOperation()  # 初始化一个链表基本操作对象实例
    list_data1 = [1, 9]  # 链表1初始化数据
    list_data2 = [1, 3]  # 链表2初始化数据
    l1 = s0.init_list(list_data1)  # 初始化链表,带头结点
    l2 = s0.init_list(list_data2)  # 初始化链表,带头结点
    s0.ergodic_list(l1)  # 未操作前,遍历打印链表
    s0.ergodic_list(l2)  # 未操作前,遍历打印链表
    # head = links_sum_one(l1, l2)  # 测试方法一
    head = links_sum_two(l1, l2)  # 测试方法二
    # head = links_sum_three(l1, l2)  # 测试方法三
    print("---------------------")
    s0.ergodic_list(head)  # 操作后,遍历打印链表

本文代码思路部分来自书籍《Python程序员面试宝典》,书中部分代码有问题或未提供代码,文中已经修改过了,并添加上了丰厚的注释,方便大家学习,后面我会把所有内容开源放到Github上,包括代码,思路,算法图解(手绘或者电脑画),时间充裕的话,会录制视频。
希望大家多多支持。

大家好,我是老表
觉得本文不错的话,转发、留言、点赞,是对我最大的支持。

欢迎关注微信公众号:简说Python
关注后回复:1024,可以领取精选编程学习电子书籍。

你可能感兴趣的:(数据结构,Python)