数据结构单链表之将链表表示的两个数字相加 | 第十四套

简介: 数据结构单链表之将链表表示的两个数字相加 | 第十四套

给定由两个列表表示的两个数字,编写一个返回总和列表的函数。总和列表是两个输入数字相加的列表表示。

示例


输入: 

List1: 5->6->3 // 代表数字 563

List2: 8->4->2 // 代表数字 842

输出: 

结果列表:1->4->0->5 // 代表数字 1405

解释:  563 + 842 = 1405

输入: 

List1: 7->5->9->4->6 // 代表数字 75946

List2: 8->4 // 代表数字 84

输出: 

结果列表:7->6->0->3-> 0// 代表数字 76030

解释:  75946+84=76030

方法:从末尾遍历两个列表,并一一选择两个列表的节点并添加值。如果总和大于 10,则进位为 1 并减少总和。如果一个列表的元素多于另一个,则将此列表的剩余值视为 0。反转最终列表以获得总和。

步骤是:

  1. 从头到尾遍历两个链表。
  2. 分别从各自的链表中添加两位数字。
  3. 如果其中一个列表已到达末尾,则取 0 作为其数字。
  4. 继续它直到列表的末尾。
  5. 如果两位数之和大于 9,则将进位设置为 1,将当前位数设置为和 % 10反转结果列表以获得实际和。

下面是这个方法的实现。

#include <bits/stdc++.h>
using namespace std;
class Node {
public:
  int data;
  Node* next;
};
Node* newNode(int data)
{
  Node* new_node = new Node();
  new_node->data = data;
  new_node->next = NULL;
  return new_node;
}
void push(Node** head_ref, int new_data)
{
  Node* new_node = newNode(new_data);
  new_node->next = (*head_ref);
  (*head_ref) = new_node;
}
Node* addTwoLists(Node* first, Node* second)
{
  Node* res = NULL;
  Node *temp, *prev = NULL;
  int carry = 0, sum;
  while (first != NULL
    || second != NULL) {
    sum = carry + (first ? first->data : 0)
      + (second ? second->data : 0);
    carry = (sum >= 10) ? 1 : 0;
    sum = sum % 10;
    temp = newNode(sum);
    if (res == NULL)
      res = temp;
    else
      prev->next = temp;
    prev = temp;
    if (first)
      first = first->next;
    if (second)
      second = second->next;
  }
  if (carry > 0)
    temp->next = newNode(carry);
  return res;
}
Node* reverse(Node* head)
{
  if (head == NULL || head->next == NULL)
    return head;
  Node* rest = reverse(head->next);
  head->next->next = head;
  head->next = NULL;
  return rest;
}
void printList(Node* node)
{
  while (node != NULL) {
    cout << node->data << " ";
    node = node->next;
  }
  cout << endl;
}
int main(void)
{
  Node* res = NULL;
  Node* first = NULL;
  Node* second = NULL;
  push(&first, 6);
  push(&first, 4);
  push(&first, 9);
  push(&first, 5);
  push(&first, 7);
  printf("First List is ");
  printList(first);
  push(&second, 4);
  push(&second, 8);
  cout << "Second List is ";
  printList(second);
  first = reverse(first);
  second = reverse(second);
  res = addTwoLists(first, second);
  res = reverse(res);
  cout << "Resultant list is ";
  printList(res);
  return 0;
}

输出

First List is 7 5 9 4 6 
Second List is 8 4 
Resultant list is 5 0 0 5 6 

复杂度分析:

  • 时间复杂度:  O(m + n),其中 m 和 n 分别是第一个和第二个列表中的节点数。
    列表只需要遍历一次。
  • 空间复杂度:  O(m + n)。
    需要一个临时链表来存储输出编号

方法二(Using STL): 使用栈数据结构

方法 :

  • 创建 3 个堆栈,即 s1、s2、s3。
  • 用 list1 的节点填充 s1,用 list2 的节点填充 s2。
  • 通过创建新节点并将新节点的数据设置为 s1.top()、s2.top() 的总和来填充 s3,并进位直到 list1 和 list2 为空。
  • 如果总和 >9
  • 设置进位 1
  • 别的
  • 设置进位 0
  • 创建一个包含总和列表头部的节点(比如上一个)。
  • 从上到下链接s3的所有元素
  • 返回上一页

代码:

#include <bits/stdc++.h>
using namespace std;
class Node {
public:
  int data;
  Node* next;
};
Node* newnode(int data)
{
  Node* x = new Node();
  x->data = data;
  return x;
}
Node* addTwoNumbers(Node* l1, Node* l2)
{
  Node* prev = NULL;
  stack<Node*> s1, s2, s3;
  while (l1 != NULL) {
    s1.push(l1);
    l1 = l1->next;
  }
  while (l2 != NULL) {
    s2.push(l2);
    l2 = l2->next;
  }
  int carry = 0;
  while (!s1.empty() && !s2.empty()) {
    int sum = s1.top()->data + s2.top()->data + carry;
    Node* temp = newnode(sum % 10);
    s3.push(temp);
    if (sum > 9) {
      carry = 1;
    }
    else {
      carry = 0;
    }
    s1.pop();
    s2.pop();
  }
  while (!s1.empty()) {
    int sum = carry + s1.top()->data;
    Node* temp = newnode(sum % 10);
    s3.push(temp);
    if (sum > 9) {
      carry = 1;
    }
    else {
      carry = 0;
    }
    s1.pop();
  }
  while (!s2.empty()) {
    int sum = carry + s2.top()->data;
    Node* temp = newnode(sum % 10);
    s3.push(temp);
    if (sum > 9) {
      carry = 1;
    }
    else {
      carry = 0;
    }
    s2.pop();
  }
  if (carry == 1) {
    Node* temp = newnode(1);
    s3.push(temp);
  }
  if (!s3.empty())
    prev = s3.top();
  while (!s3.empty()) {
    Node* temp = s3.top();
    s3.pop();
    if (s3.size() == 0) {
      temp->next = NULL;
    }
    else {
      temp->next = s3.top();
    }
  }
  return prev;
}
void Display(Node* head)
{
  if (head == NULL) {
    return;
  }
  while (head->next != NULL) {
    cout << head->data << " -> ";
    head = head->next;
  }
  cout << head->data << endl;
}
void push(Node** head_ref, int d)
{
  Node* new_node = newnode(d);
  new_node->next = NULL;
  if (*head_ref == NULL) {
    new_node->next = *head_ref;
    *head_ref = new_node;
    return;
  }
  Node* last = *head_ref;
  while (last->next != NULL && last != NULL) {
    last = last->next;
  }
  last->next = new_node;
  return;
}
int main()
{
  Node* first = NULL;
  Node* second = NULL;
  Node* sum = NULL;
  push(&first, 9);
  push(&first, 5);
  push(&first, 0);
  push(&second, 6);
  push(&second, 7);
  cout << "First List : ";
  Display(first);
  cout << "Second List : ";
  Display(second);
  sum = addTwoNumbers(first, second);
  cout << "Sum List : ";
  Display(sum);
  return 0;
}

输出

First List : 9 -> 5 -> 0
Second List : 6 -> 7
Sum List : 1 -> 0 -> 1 -> 7

另一种时间复杂度为 O(N) 的方法:

  给定的方法按以下步骤工作:

  1. 首先,我们分别计算链表 size1 和 size2 的大小。
  2. 然后我们遍历更大的链表,如果有的话,递减直到两者的大小相同。
  3. 现在我们遍历两个链表直到结束。
  4. 现在在执行加法时发生回溯。
  5. 最后,返回包含答案的链表的头节点。
#include <iostream>
using namespace std;
struct Node {
  int data;
  struct Node* next;
};
Node* addition(Node* temp1, Node* temp2, int size1,
      int size2)
{
  Node* newNode
    = (struct Node*)malloc(sizeof(struct Node));
  if (temp1->next == NULL && temp2->next == NULL) {
    newNode->data = (temp1->data + temp2->data);
    newNode->next = NULL;
    return newNode;
  }
  Node* returnedNode
    = (struct Node*)malloc(sizeof(struct Node));
  if (size2 == size1) {
    returnedNode = addition(temp1->next, temp2->next,
                size1 - 1, size2 - 1);
    newNode->data = (temp1->data + temp2->data)
            + ((returnedNode->data) / 10);
  }
  else {
    returnedNode = addition(temp1, temp2->next, size1,
                size2 - 1);
    newNode->data
      = (temp2->data) + ((returnedNode->data) / 10);
  }
  returnedNode->data = (returnedNode->data) % 10;
  newNode->next = returnedNode;
  return newNode;
}
struct Node* addTwoLists(struct Node* head1,
            struct Node* head2)
{
  struct Node *temp1, *temp2, *ans = NULL;
  temp1 = head1;
  temp2 = head2;
  int size1 = 0, size2 = 0;
  while (temp1 != NULL) {
    temp1 = temp1->next;
    size1++;
  }
  while (temp2 != NULL) {
    temp2 = temp2->next;
    size2++;
  }
  Node* returnedNode
    = (struct Node*)malloc(sizeof(struct Node));
  if (size2 > size1) {
    returnedNode = addition(head1, head2, size1, size2);
  }
  else {
    returnedNode = addition(head2, head1, size2, size1);
  }
  if (returnedNode->data >= 10) {
    ans = (struct Node*)malloc(sizeof(struct Node));
    ans->data = (returnedNode->data) / 10;
    returnedNode->data = returnedNode->data % 10;
    ans->next = returnedNode;
  }
  else
    ans = returnedNode;
  return ans;
}
void Display(Node* head)
{
  if (head == NULL) {
    return;
  }
  while (head->next != NULL) {
    cout << head->data << " -> ";
    head = head->next;
  }
  cout << head->data << endl;
}
void push(Node** head_ref, int d)
{
  Node* new_node
    = (struct Node*)malloc(sizeof(struct Node));
  new_node->data = d;
  new_node->next = NULL;
  if (*head_ref == NULL) {
    new_node->next = *head_ref;
    *head_ref = new_node;
    return;
  }
  Node* last = *head_ref;
  while (last->next != NULL && last != NULL) {
    last = last->next;
  }
  last->next = new_node;
  return;
}
int main()
{
  // Creating two lists
  Node* first = NULL;
  Node* second = NULL;
  Node* sum = NULL;
  push(&first, 5);
  push(&first, 6);
  push(&first, 3);
  push(&second, 8);
  push(&second, 4);
  push(&second, 2);
  cout << "First List : ";
  Display(first);
  cout << "Second List : ";
  Display(second);
  sum = addTwoLists(first, second);
  cout << "Sum List : ";
  Display(sum);
  return 0;
}

输出

First List : 5 -> 6 -> 3
Second List : 8 -> 4 -> 2
Sum List : 1 -> 4 -> 0 -> 5


目录
相关文章
|
12天前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
30 5
|
1月前
|
存储 C语言
【数据结构】手把手教你单链表(c语言)(附源码)
本文介绍了单链表的基本概念、结构定义及其实现方法。单链表是一种内存地址不连续但逻辑顺序连续的数据结构,每个节点包含数据域和指针域。文章详细讲解了单链表的常见操作,如头插、尾插、头删、尾删、查找、指定位置插入和删除等,并提供了完整的C语言代码示例。通过学习单链表,可以更好地理解数据结构的底层逻辑,提高编程能力。
62 4
|
1月前
|
算法 安全 搜索推荐
2024重生之回溯数据结构与算法系列学习之单双链表精题详解(9)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第2.3章之IKUN和I原达人之数据结构与算法系列学习x单双链表精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
1月前
|
存储 Web App开发 算法
2024重生之回溯数据结构与算法系列学习之单双链表【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构之单双链表按位、值查找;[前后]插入;删除指定节点;求表长、静态链表等代码及具体思路详解步骤;举例说明、注意点及常见报错问题所对应的解决方法
|
2月前
|
存储
[数据结构] -- 单链表
[数据结构] -- 单链表
26 1
|
1月前
|
C语言
【数据结构】双向带头循环链表(c语言)(附源码)
本文介绍了双向带头循环链表的概念和实现。双向带头循环链表具有三个关键点:双向、带头和循环。与单链表相比,它的头插、尾插、头删、尾删等操作的时间复杂度均为O(1),提高了运行效率。文章详细讲解了链表的结构定义、方法声明和实现,包括创建新节点、初始化、打印、判断是否为空、插入和删除节点等操作。最后提供了完整的代码示例。
43 0
|
2月前
|
存储
[数据结构] -- 双向循环链表
[数据结构] -- 双向循环链表
25 0
|
2月前
|
存储
数据结构(单链表)
数据结构(单链表)
19 0
|
6月前
|
存储 SQL 算法
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表
|
6月前
|
存储 SQL 算法
LeetCode 题目 86:分隔链表
LeetCode 题目 86:分隔链表