📜  使用双向链表的大数算法(1)

📅  最后修改于: 2023-12-03 15:06:55.497000             🧑  作者: Mango

使用双向链表的大数算法

在计算机科学中,大数是指位数比计算机所能处理的位数还要大的数。在进行大数计算时,通常会使用双向链表来实现。

双向链表

双向链表是一种链表结构,每个节点包含了指向前一个节点和后一个节点的两个指针。相对于单向链表,双向链表可以在常量时间内向前或向后遍历,因此在进行大数计算时十分适用。

下面是一个双向链表的实现代码:

class Node:
    def __init__(self, val, prev_node=None, next_node=None):
        self.val = val
        self.prev_node = prev_node
        self.next_node = next_node

class LinkedList:
    def __init__(self):
        self.head = None
        self.tail = None

    def append(self, val):
        if not self.head:
            self.head = Node(val)
            self.tail = self.head
        else:
            new_node = Node(val, prev_node=self.tail)
            self.tail.next_node = new_node
            self.tail = new_node
大数加法

在进行大数加法时,需要将两个数的每一位相加,并将结果保存到新的链表中。如果有进位,则需要将进位加到下一位相加的结果中。最后需要反转链表,得到结果。

代码实现如下:

def add(l1, l2):
    result = LinkedList()
    carry = 0

    while l1 or l2:
        val1 = l1.val if l1 else 0
        val2 = l2.val if l2 else 0

        sum_ = val1 + val2 + carry
        carry = sum_ // 10
        val = sum_ % 10

        result.append(val)

        if l1:
            l1 = l1.next_node
        if l2:
            l2 = l2.next_node

    if carry:
        result.append(carry)

    return result
大数减法

在进行大数减法时,需要从高位向低位逐位相减,并将结果保存到新的链表中。如果被减数小于减数,则需要向高位借位。最后需要反转链表,并去掉高位的 0,得到结果。

代码实现如下:

def subtract(l1, l2):
    result = LinkedList()
    borrow = 0

    while l1 or l2:
        val1 = l1.val if l1 else 0
        val2 = l2.val if l2 else 0

        diff = val1 - val2 - borrow

        if diff < 0:
            diff += 10
            borrow = 1
        else:
            borrow = 0

        result.append(diff)

        if l1:
            l1 = l1.next_node
        if l2:
            l2 = l2.next_node

    # 去掉高位的 0
    while result.tail and result.tail.val == 0:
        result.tail = result.tail.prev_node

    return result
大数乘法

在进行大数乘法时,需要将两个数的每一位分别相乘,并将结果保存到新的链表中。同时需要将每个结果的位数向前移动,最后将所有结果相加得到最终的结果。

代码实现如下:

def multiply(l1, l2):
    m = LinkedList()

    i = 0
    while l2:
        carry = 0
        n = LinkedList()

        for j in range(i):
            n.append(0)

        j = l1.head
        while j:
            val = l2.val * j.val + carry
            carry = val // 10
            val = val % 10
            n.append(val)
            j = j.next_node

        if carry:
            n.append(carry)

        m = add(m, n)

        l2 = l2.next_node
        i += 1

    # 去掉高位的 0
    while m.tail and m.tail.val == 0:
        m.tail = m.tail.prev_node

    return m
大数除法

在进行大数除法时,需要将被除数和除数都转换为链表,并依次减去除数,记录减的次数,直到被除数小于除数。最后的结果为减的次数。

代码实现如下:

def divide(l1, l2):
    count = 0

    while l1:
        dividend = LinkedList()
        copy_l2 = LinkedList()

        copy_l2.head = l2.head
        dividend.append(l1.val)

        while compare(dividend, copy_l2) >= 0:
            count += 1
            dividend = subtract(dividend, copy_l2)

        if l1.next_node:
            dividend.append(l1.next_node.val)

        l1 = l1.next_node

    return count
大数比较

在进行大数比较时,需要从高位向低位逐位比较。如果两个数某一位不同,则可以直接得出结果。如果两个数完全相同,则需要比较长度,长度更长的数更大。

代码实现如下:

def compare(l1, l2):
    n1, n2 = l1.head, l2.head

    while n1 or n2:
        val1 = n1.val if n1 else 0
        val2 = n2.val if n2 else 0

        if val1 > val2:
            return 1
        elif val1 < val2:
            return -1

        n1 = n1.next_node if n1 else None
        n2 = n2.next_node if n2 else None

    return 0
总结

使用双向链表进行大数计算,使得计算过程更加高效和便捷。以上便是使用双向链表的大数算法的实现代码。