You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.
You may assume the two numbers do not contain any leading zero, except the number 0 itself.
Example
Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)Output: 7 -> 0 -> 8Explanation: 342 + 465 = 807.翻译: 给出两个表示两个非负数整数的 非空 链接列表。数字以 逆序 形式存储, 每个节点都包含一个数字。添加两个数字并将其作为链接列表返回。您可能假定两个数字不包含任何前导零, 但数字0本身除外。难度:中等2.以下这种方法是在讨论中见到的最简洁的一种方法/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { ListNode preheader(-1), *curr=&preheader; int carry=0; while(l1||l2||carry) { curr->next = new ListNode(((l1?l1->val:0)+(l2?l2->val:0)+carry)%10); curr = curr->next; carry = ((l1?l1->val:0)+(l2?l2->val:0)+carry)/10; l1?l1=l1->next:0; l2?l2=l2->next:0; } return preheader.next; } };
另外一种比较清晰的解法:说明: 这道并不是什么难题,算法很简单,链表的数据类型也不难。就是建立一个新链表,然后把输入的两个链表从头往后撸,每两个相加,添加一个新节点到新链表后面,就是要处理下进位问题。还有就是最高位的进位问题要最后特殊处理一下。class Solution { public: ListNode *addTwoNumbers(ListNode *l1, ListNode *l2) { ListNode *res = new ListNode(-1); ListNode *cur = res; int carry = 0; while (l1 || l2) { int n1 = l1 ? l1->val : 0; int n2 = l2 ? l2->val : 0; int sum = n1 + n2 + carry; carry = sum / 10; cur->next = new ListNode(sum % 10); cur = cur->next; if (l1) l1 = l1->next; if (l2) l2 = l2->next; } if (carry) cur->next = new ListNode(1); return res->next; } };
要考虑以下几种情况1.某一个加数为空,此时需要做一个判断,故采用 l1?l1->val:0和 l2?l2->val:0来分别表示两个加数,若为空则置为0;2.请注意该题定义的结点结构体,可以进行初始化运算,所以可以在为新的结点申请存储空间时.就把值写入;
3.求和和进位是在leetcode中比较常见的运算形式,进位的值就是A/10(一般就是0或者1,为了统一运算,就用A/10表示),进位之后剩余的值就是A%10;4.最后一点就是本题考查的关键了,对链表知识的考察,需要理解清楚,方能灵活运用。
3.链表知识复习链表分类
链表分为单向链表(Singly linked lis)、双向链表(Doubly linked list)、循环链表(Circular Linked list)。
单向链表(Singly linked lis)
单向链表是最简单的链表形式。我们将链表中最基本的数据称为节点(node),每一个节点包含了数据块和指向下一个节点的指针。
![]()
typedef struct node { int val; struct node *next; }Node;
头结点
单向链表有时候也分为有头结点和无头结点。有头结点的链表实现比较方便(每次插入新元素的时候,不需要每次判断第一个节点是否为空),并且可以直接在头结点的数据块部分存储链表的长度,而不用每次都遍历整个链表。
不带头结点的单链表
带头结点的单链表
1.单链表的初始化,即建立一个空链表。
- //不带头结点的单链表的初始化
- void LinkedListInit1(LinkedList L)
- {
- L=NULL;
- }
- //带头结点的单链表的初始化
- void LinkedListInit2(LinkedList L)
- {
- L=(LNode *)malloc(sizeof(LNode));
- if(L==NULL)
- {
- printf("申请空间失败!");
- exit(0);
- }
- L->next=NULL;
- }
//不带头结点的单链表的初始化 void LinkedListInit1(LinkedList L) { L=NULL; } //带头结点的单链表的初始化 void LinkedListInit2(LinkedList L) { L=(LNode *)malloc(sizeof(LNode)); if(L==NULL) { printf("申请空间失败!"); exit(0); } L->next=NULL; }
2.单链表的求表长操作
单链表的求表长操作需要设定当前指针p和一个计数器j,初始时p指向链表中的第一个结点,p每向下移动一个结点时,j就加1,直到到达p链表的尾部。带头结点的链表,链表长度不包括头结点。
- //带头结点的单链表求表长
- int LinkedListLength(LinkedList L)
- {
- LNode *p; //p需要声明为LNode类型
- p=L->next;
- int j=0;
- while(p!=NULL)
- {
- j++;
- p=p->next; //将p向下移动一个结点
- }
- return j;
- }
//带头结点的单链表求表长 int LinkedListLength(LinkedList L) { LNode *p; //p需要声明为LNode类型 p=L->next; int j=0; while(p!=NULL) { j++; p=p->next; //将p向下移动一个结点 } return j; }
3.单链表获取第i个结点元素的操作
设定p为当前结点,初始时p指向链表的第一个结点,然后向下移动i,此时p所指向的元素就是需要查找的第i个结点元素。
- //带头结点的单链表取元素操作
- LinkedList LinkedListGetINode(LinkedList L, int i)
- {
- LNode *p;
- p=L->next;
- int j=1;
- while((p!=NULL)&&(j<i))
- {
- p=p->next;
- j++;
- }
- return p;
- }
//带头结点的单链表取元素操作 LinkedList LinkedListGetINode(LinkedList L, int i) { LNode *p; p=L->next; int j=1; while((p!=NULL)&&(j<i)) { p=p->next; j++; } return p; }
4.单链表的定位操作
查找元素e第一次出现的位置。从链表的第一个结点开始,判断当前结点的值是否等于e,等于则返回该结点的指针,否则继续向后查找,直至到达链表的最后。
- //带头结点的单链表定位操作
- LNode LinkedListLocateE(LinkedList L, ElemType e)
- {
- LNode *p;
- p=L->next;
- while((p!=NULL)&&(p->data!=e))
- {
- p=p->next;
- }
- return p;
- }
//带头结点的单链表定位操作 LNode LinkedListLocateE(LinkedList L, ElemType e) { LNode *p; p=L->next; while((p!=NULL)&&(p->data!=e)) { p=p->next; } return p; }
5.单链表的插入操作
在结点p之前插入一个新的结点q:对于不带头结点的单链表,结点p的位置有所不同,插入操作有以下两种情况:
1)在链表的表头插入:
(1)创建一个新的结点q。
(2)将此结点的数据域赋值为e,并将它的next指针指向第一个结点,即L。
(3)将L修改为指向新的结点q。
操作示意图如下:
2)在链表的中间插入
(1)创建一个新的结点q。
(2)将此结点的数据域赋值为e,并将它的next指针指向p。
(3)查找到p的前驱结点pre。
(4)将pre的next指针指向新创建的结点q。
操作示意图如下:
- //不带头结点的单链表的插入操作
- void LinkedListInertQE1(LinkedList L, LinkedList p, ElemType e)
- {
- q=(LNode *)malloc(sizeof(LNode)); //创建一个新的结点q
- if(q==NULL)
- {
- printf("申请空间失败!");
- exit(0);
- }
- q->data=e;
- if(p==L) //在表头插入
- {
- q->next=L;
- L=q;
- }
- else //在表的中间进行插入
- {
- pre=L;
- while((pre!=NULL)&&(pre->next!=p)) //寻找p的前驱
- pre=pre->next;
- q->next=pre->next;
- pre->next=q;
- }
- }
- //带头结点的单链表的插入操作
- void LinkedListInertQE2(LinkedList L, LinkedList p, ElemType e)
- {
- q=(LNode *)malloc(sizeof(LNode)); //创建一个新的结点q
- if(q==NULL)
- {
- printf("申请空间失败!");
- exit(0);
- }
- q->data=e;
- //插入新的结点
- pre=L;
- while((pre!=NULL)&&(pre->next!=p)) //寻找p的前驱
- pre=pre->next;
- q->next=pre->next;
- pre->next=q;
- }
//不带头结点的单链表的插入操作 void LinkedListInertQE1(LinkedList L, LinkedList p, ElemType e) { q=(LNode *)malloc(sizeof(LNode)); //创建一个新的结点q if(q==NULL) { printf("申请空间失败!"); exit(0); } q->data=e; if(p==L) //在表头插入 { q->next=L; L=q; } else //在表的中间进行插入 { pre=L; while((pre!=NULL)&&(pre->next!=p)) //寻找p的前驱 pre=pre->next; q->next=pre->next; pre->next=q; } } //带头结点的单链表的插入操作 void LinkedListInertQE2(LinkedList L, LinkedList p, ElemType e) { q=(LNode *)malloc(sizeof(LNode)); //创建一个新的结点q if(q==NULL) { printf("申请空间失败!"); exit(0); } q->data=e; //插入新的结点 pre=L; while((pre!=NULL)&&(pre->next!=p)) //寻找p的前驱 pre=pre->next; q->next=pre->next; pre->next=q; }
6.单链表的删除操作
删除链表中的某个元素e,如果e在链表中出现不止一次,将删除第一次出现的e,否则什么也不做。
用p找到元素e所在的结点:
1)p是链表中的第一个结点
(1)将L指向p->next。
(2)释放p。
示意图如下:
2)p是链表中的其他结点
(1)找到p的前驱结点pre。
(2)将pre->next指向p->next。
(3)释放p。
示意图如下:
![]()
- //不带头结点的单链表的删除操作
- void LinkedListDeleteQE1(LinkedList L, LinkedList p, ElemType e)
- {
- pre=L;
- while((pre!=NULL)&&(pre->next->data!=e)) //查找元素e的前驱
- pre=pre->next;
- p=pre->next;
- if(p!=NULL) //找到需要删除的结点
- {
- if(p==L) //删除的是第一个结点
- L=p->next;
- else //删除的是其他结点
- pre->next=p->next;
- free(p);
- }
- }
- //带头结点的单链表的删除操作
- void LinkedListDeleteQE2(LinkedList L, LinkedList p, ElemType e)
- {
- pre=L;
- while((pre!=NULL)&&(pre->next->data!=e)) //查找元素e的前驱
- pre=pre->next;
- p=pre->next;
- if(p!=NULL) //找到需要删除的结点
- {
- pre->next=p->next;
- free(p);
- }
- }
//不带头结点的单链表的删除操作 void LinkedListDeleteQE1(LinkedList L, LinkedList p, ElemType e) { pre=L; while((pre!=NULL)&&(pre->next->data!=e)) //查找元素e的前驱 pre=pre->next; p=pre->next; if(p!=NULL) //找到需要删除的结点 { if(p==L) //删除的是第一个结点 L=p->next; else //删除的是其他结点 pre->next=p->next; free(p); } } //带头结点的单链表的删除操作 void LinkedListDeleteQE2(LinkedList L, LinkedList p, ElemType e) { pre=L; while((pre!=NULL)&&(pre->next->data!=e)) //查找元素e的前驱 pre=pre->next; p=pre->next; if(p!=NULL) //找到需要删除的结点 { pre->next=p->next; free(p); } }
7.单链表的创建操作
单链表的创建方法有两种:头插法和尾插法。
头插法是将新增结点插入第一个结点之前,示意图如下:
尾插法是将新增结点插入最后一个结点之后,示意图如下:
- //用头插法创建带头结点的单链表
- void LinkedListCreateHeadL(LinkedList L, ElemType a[n])
- {
- L=(LNode *)malloc(sizeof(LNode));
- if(L==NULL)
- {
- printf("申请空间失败!");
- exit(0);
- }
- L->next=NULL;
- for(i=0; i<n; i++)
- {
- p=(LNode *)malloc(sizeof(LNode));
- if(p==NULL)
- {
- printf("申请空间失败!");
- exit(0);
- }
- p->data=a[i];
- p->next=L->next;
- L->next=p;
- }
- }
- //用尾插法创建带头结点的单链表
- void LinkedListCreateTailL(LinkedList L, ElemType a[n])
- {
- L=(LNode *)malloc(sizeof(LNode));
- if(L==NULL)
- {
- printf("申请空间失败!");
- exit(0);
- }
- L->next=NULL;
- tail=L; //设置尾指针,方便插入
- for(j=0; j<n; j++)
- {
- p=(LNode *)malloc(sizeof(LNode));
- if(p==NULL)
- {
- printf("申请空间失败!");
- exit(0);
- }
- p->data=a[j];
- p->next=NULL;
- tail->next=p;
- tail=p;
- }
- }
//用头插法创建带头结点的单链表 void LinkedListCreateHeadL(LinkedList L, ElemType a[n]) { L=(LNode *)malloc(sizeof(LNode)); if(L==NULL) { printf("申请空间失败!"); exit(0); } L->next=NULL; for(i=0; i<n; i++) { p=(LNode *)malloc(sizeof(LNode)); if(p==NULL) { printf("申请空间失败!"); exit(0); } p->data=a[i]; p->next=L->next; L->next=p; } } //用尾插法创建带头结点的单链表 void LinkedListCreateTailL(LinkedList L, ElemType a[n]) { L=(LNode *)malloc(sizeof(LNode)); if(L==NULL) { printf("申请空间失败!"); exit(0); } L->next=NULL; tail=L; //设置尾指针,方便插入 for(j=0; j<n; j++) { p=(LNode *)malloc(sizeof(LNode)); if(p==NULL) { printf("申请空间失败!"); exit(0); } p->data=a[j]; p->next=NULL; tail->next=p; tail=p; } }
8.单链表的合并操作
首先设置3个指针pa、pb、pc, pa和pb分别指向链表La与Lb的当前待比较插入结点,pc指向链表Lc的最后一个结点。当pa->data≤pb->data时,将pa所指的结点插入到pc后面,否则就将pb所指的结点插入到pc后面。最后,当有一个表合并完,将另一个表剩余的结点全插入到pc。
- //带头结点的单链表合并操作
- void LinkedListMergeLaLb(LinkedList La, LinkedList Lb, LinkedList Lc)
- {
- pa=La->next;
- pb=Lb->next;
- Lc=La; //借用表La的头结点作为表Lc的头结点
- pc=Lc;
- while((pa!=NULL)&&(pb!=NULL))
- {
- if(pa->data<=pb->data)
- {
- pc->next=pa;
- pc=pa;
- pa=pa->next;
- }
- else
- {
- pc->next=pb;
- pc=pb;
- pb=pb->next;
- }
- }
- if(pa!=NULL)
- pc=pa->next;
- else
- pc=pb->next;
- free(pb); //将Lb的表头结点释放
- }
//带头结点的单链表合并操作 void LinkedListMergeLaLb(LinkedList La, LinkedList Lb, LinkedList Lc) { pa=La->next; pb=Lb->next; Lc=La; //借用表La的头结点作为表Lc的头结点 pc=Lc; while((pa!=NULL)&&(pb!=NULL)) { if(pa->data<=pb->data) { pc->next=pa; pc=pa; pa=pa->next; } else { pc->next=pb; pc=pb; pb=pb->next; } } if(pa!=NULL) pc=pa->next; else pc=pb->next; free(pb); //将Lb的表头结点释放 }
附录:
程序实例:尾插法创建单链表
首先在VS2010中新建Win32 控制台应用程序的项目LinkedList,结果如下:
LinkedList.cpp : 定义控制台应用程序的入口点。
- // LinkedList.cpp : 定义控制台应用程序的入口点。
- #include "stdafx.h"
- #include<stdio.h>
- #include<stdlib.h>
- typedef struct node
- {
- int data;
- struct node *next;
- }*LinkedList;
- LinkedList LinkedListCreateTailL(int a[8])
- {
- LinkedList p, L, tail;
- int i=0;
- L=(struct node*)malloc(sizeof(struct node));
- tail=L;
- for(i=0; i<8; i++)
- {
- p=(struct node*)malloc(sizeof(struct node));
- p->data=a[i];
- tail->next=p;
- tail=p;
- }
- tail->next=NULL;
- return L;
- }
- void LinkedListPrint(LinkedList L)
- {
- LinkedList p;
- p=L->next;
- while(p!=NULL)
- {
- printf("%d ",p->data);
- p=p->next;
- }
- }
- void main()
- {
- int a[8], i;
- LinkedList L;
- printf("请输入8个列表元素,以回车结束:\n");
- for(i=0; i<8; i++)
- {
- scanf("%d", &a[i]);
- }
- L=LinkedListCreateTailL(a);
- LinkedListPrint(L);
- }
Ctrl+F5执行以上cpp文件,程序运行截图:// LinkedList.cpp : 定义控制台应用程序的入口点。 #include "stdafx.h" #include<stdio.h> #include<stdlib.h> typedef struct node { int data; struct node *next; }*LinkedList; LinkedList LinkedListCreateTailL(int a[8]) { LinkedList p, L, tail; int i=0; L=(struct node*)malloc(sizeof(struct node)); tail=L; for(i=0; i<8; i++) { p=(struct node*)malloc(sizeof(struct node)); p->data=a[i]; tail->next=p; tail=p; } tail->next=NULL; return L; } void LinkedListPrint(LinkedList L) { LinkedList p; p=L->next; while(p!=NULL) { printf("%d ",p->data); p=p->next; } } void main() { int a[8], i; LinkedList L; printf("请输入8个列表元素,以回车结束:\n"); for(i=0; i<8; i++) { scanf("%d", &a[i]); } L=LinkedListCreateTailL(a); LinkedListPrint(L); }