链表(Linked list)
引入
数组作为数据存储结构有一定的缺陷。无序数组中搜索性能差,有序数组中,插入效率低。两种数组的删除效率都很低。并且,数组在创建后大小就固定了,设置过大会造成内存浪费,过小不能满足数据存储的需要。
数组是一种通用数据结构,可以用来实现栈,队列等很多数据结构。链表也是一种通用数据结构,可以作为实现栈,队列等数据结构的基础。除非需要频繁的通过下标来随机访问各个数据,否则很多使用数组的地方可以使用链表代替。
定义
链表通常由一连串节点组成,每个节点包含任意的实例数据(data fields)和一或两个用来指向上一个/或下一个节点的位置的链接(“links”)。
链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer)。
使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。
单向链表(Single-Linked List)
单链表是链表中结构最简单的。一个单链表的节点(Node)分为两个部分,第一个部分(data)保存或者显示关于节点的信息,另一个部分存储下一个节点的地址。最后一个节点存储地址的部分指向空值。
单向链表只可向一个方向遍历,一般查找一个节点的时候需要从第一个节点开始每次访问下一个节点,一直访问到需要的位置。而插入一个节点,对于单向链表,我们只提供在链表头插入,只需要将当前插入的节点设置为头节点,next指向原头节点即可。删除一个节点,我们将该节点的上一个节点的next指向该节点的下一个节点。
参考文章:
https://www.cnblogs.com/ysocean/p/7928988.html
力扣第二题:
自己写的解法:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
int sum1=0,sum2=0;
ListNode p=l1;
ListNode q=l2;
while(p!=null){
int current=p.val;
sum1=10*sum1+current;
p=p.next;
}
while(q!=null){
int current=q.val;
sum2=10*sum2+current;
q=q.next;
}
int revsum1=0,revsum2=0;
while(sum1!=0){
int pop=sum1%10;
sum1=sum1/10;
revsum1=revsum1*10+pop;
}
while(sum2!=0){
int pop=sum2%10;
sum2=sum2/10;
revsum2=revsum2*10+pop;
}
int result=revsum1+revsum2;
System.out.println(result);
System.out.println(revsum1);
System.out.print(revsum2);
ListNode l3=new ListNode(0);
ListNode curr=l3;
while(result!=0){
curr.val=result%10;
result=result/10;
if(result>0){
curr.next=new ListNode(result);
curr=curr.next;
}
}
return l3;
}
}
比较麻烦,而且正常可以运行出结果。但是
这种情况就会出现错误,在反转加数过程中出现了溢出。
将int转换为long,可以避免溢出,但是出现了新的问题
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
int sum1=0,sum2=0;
ListNode p=l1;
ListNode q=l2;
while(p!=null){
int current=p.val;
sum1=10*sum1+current;
p=p.next;
}
while(q!=null){
int current=q.val;
sum2=10*sum2+current;
q=q.next;
}
long revsum1=0,revsum2=0;
while(sum1!=0){
int pop=sum1%10;
sum1=sum1/10;
revsum1=revsum1*10+pop;
}
// System.out.println(sum2);
while(sum2!=0){
int pop=sum2%10;
sum2=sum2/10;
revsum2=revsum2*10+pop;
}
Long result=revsum1+revsum2;
// System.out.println(result);
// System.out.println(revsum1);
// System.out.print(revsum2);
ListNode l3=new ListNode(0);
ListNode curr=l3;
while(result!=0){
curr.val=(result.intValue())%10;
int temp=result.intValue()/10;
result=result/10;
// System.out.println(result);
if(result>0){
curr.next=new ListNode(temp);
curr=curr.next;
}
}
return l3;
}
}
与原结果差了一个8,很神奇。
官方解法
使用按位相加,保存进位的方法
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode root=new ListNode(0);
ListNode curr=root;
int carry=0;//save jinwei
while(l1!=null||l2!=null||carry!=0){
int n1=l1!=null?l1.val:0;
int n2=l2!=null?l2.val:0;
int sum=n1+n2+carry;
carry=sum/10;
ListNode sumNode=new ListNode(sum%10);
curr.next=sumNode;
curr=sumNode;
if(l1!=null) l1=l1.next;
if(l2!=null) l2=l2.next;
}
return root.next;
}
}
大佬果然还是大佬,小弟佩服佩服。
面对问题我总想用最暴力的方法解决,这个想法应该纠正。编代码前多思考。
对于链表的使用还不太熟练,不太理解。要学的还有很多。。