关于链表的学习
前言:
在java内部提供了list、set、map等数据类型,链表常用的有ArrayList和LinkedList,它们二者的区别在于:
- ArrayList实现了随机访问(RandomAccess)的接口,基于动态数组;LinkedList实现了队列(Quene)的接口,基于链表的数据结构。
- ArrayList适合随机读取,可以一步get(index),但是添加数据的时候就会很慢,如果添加到中间位置,要依次移动后面的数据;而LinkedList添加数据很方便,只需要更改这个数据前后的指针就能添加到链表中去,但是读取速度会很慢,要依次查询。
- ArrayList的扩容方式采用oldSize*3/2+1,相当于只要容量不足就要增加1/2的容量;LinkedList采用动态链接,除此之外还有的是数组的容量固定不可改变,且存储在连续存储区域。
- 实现栈和队列方面,LinkedList要优于ArrayList。增删操作LinkedList开销一致比ArrayList更好。
当操作是在一列数据的后面添加数据而不是在前面或中间,并且需要随机地访问其中的元素时,使用ArrayList会提供比较好的性能;当你的操作是在一列数据的前面或中间添加或删除数据,并且按照顺序访问其中的元素时,就应该使用LinkedList了。
下面记录一下LinkedList实现栈和队列的操作细节:(记录只为更好的学习~~)
1 import java.util.*; 2 3 class Stack{ 4 private LinkedList list; 5 public Stack(){ 6 list=new LinkedList(); 7 } 8 9 public Object top(){ //输出最上面的元素 10 if(list.size()!=0){ 11 return list.getFirst(); 12 } 13 return -1; 14 } 15 16 public void pop(){ //出栈 17 if(list.size()!=0){ 18 list.removeFirst(); 19 } 20 } 21 22 public void push(Object v){ //入栈 23 list.addFirst(v); 24 } 25 26 public int getLen(){ 27 return list.size(); 28 } 29 }
再记录一下利用ArrayList处理斐波拉契数列的问题:
1 import java.util.ArrayList; 2 import java.util.Scanner; 3 4 /** 5 * Created by ygh. 6 */ 7 public class Main { 8 public static void main(String[] args) { 9 ArrayList<Integer> list = new ArrayList<>(); 10 list.add(0); //斐波拉契数列头两个元素是0和1 11 list.add(1); 12 Scanner sc = new Scanner(System.in); 13 while (sc.hasNext()) { 14 int n = sc.nextInt(); // 表示查询斐波拉契数列的第n个元素 15 if (n >= list.size()) { 16 for (int i = list.size(); i <= n; i++) { 17 list.add(list.get(i - 2) + list.get(i - 1)); //依次遍历增加元素到list里,结果为前两个元素相加 18 } 19 } 20 System.out.println(list.get(n)); //打印当前元素 21 } 22 } 23 }
下面进入重点:
在平时编程中会用到自定义的链表,这时就要面向对象了,哈哈~。构建Node节点类,利用对象的指针进行链表的连接来实现自定义链表。下面是自定义的链表类:
public class ListNode{ int value; ListNode next;
public ListNode(int value){ this.value=value; this.next=null; } }
比如说要实现查找链表中倒数第k个结点,直接上代码:
1 public ListNode FindKthToTail(ListNode head,int k) { 2 if(head==null||k<=0)return null; 3 ListNode nodePre=head; //两个指针都指向头结点 4 ListNode nodeLast=head; 5 6 for(int i=1;i<k;i++){ 7 if(nodePre.next!=null)nodePre=nodePre.next; 8 else return null; 9 } 10 11 while(nodePre.next!=null){ 12 nodePre = nodePre.next; 13 nodeLast=nodeLast.next; 14 } 15 return nodeLast; 16 }
要说一下,这里查找倒数第k个节点是采用两个指针,第一个先往前读,直到到了第k-1个元素时停止,第二个还在头节点,这时他们相距k-1的距离,然后就让它们一起向前读,直到第一个读到链表的末尾,就停止操作,此时第二个的指针指向的就是倒数第k个结点,是不是很机智,嘿嘿~~
也可以采用先遍历出链表长度n,再重新走到第n-k+1个元素的位置,这也可以找出倒数第k个结点:
1 public ListNode FindKthToTail(ListNode head,int k) { 2 ListNode p,q; 3 q=head; 4 p=head; 5 int count=0; 6 if(p==null){ 7 return null; 8 } 9 while(p.next!=null){ 10 p=p.next; 11 count++; 12 } 13 if(k>(count+1)){ 14 return null; 15 } 16 else{ 17 for(int i=0;i<=(count-k);i++){ 18 q=q.next; 19 } 20 } 21 return q; 22 }
还有一些链表操作的方法,感受下~ 不论是什么都要举一反三,没有固定不变的,这只是给自己提供一种解决问题的好思路。
比如:
- 查找单链表的中间结点
public static Node getMiddleNode(Node head){ if(head==null||head.next==null)return head; Node target=head; Node temp=head; while(temp!=null&&temp.next!=null){ target=target.next; temp=temp.next.next; } return target; }
- 合并两个有序的单链表head1和head2(采用循环的方式)
1 public static Node mergeSortedList(Node head1,Node head2){ 2 if(head1==null)return head2; 3 if(head2==null)return head1; 4 Node target=null; 5 if(head1.value>head2.value){ 6 target=head2; 7 head2=head2.next; 8 } 9 else{ 10 target=head1; 11 head1=head1.next; 12 } 13 target.next=null; 14 Node mergeHead=target; 15 while(head1!=null && head2!=null){ 16 if(head1.value>head2.value){ 17 target.next=head2; 18 head2=head2.next; 19 } 20 else{ 21 target.next=head1; 22 head1=head1.next; 23 } 24 target=target.next; //指针向后移 25 target.next=null; 26 } 27 if(head1==null)target.next=head2; 28 else target.next=head1; 29 return mergeHead; 30 }
- 合并两个有序的单链表head1和head2(采用递归的方式)
1 public static Node mergeSortedListRec(Node head1,Node head2){ 2 if(head1==null)return head2; 3 if(head2==null)return head1; 4 if(head1.value>head2.value){ 5 head2.next=mergeSortedListRec(head2.next,head1); 6 return head2; 7 } 8 else{ 9 head1.next=mergeSortedListRec(head1.next,head2); 10 return head1; 11 } 12 }
其他的比如排序的方法等详见博客:http://blog.csdn.net/kerryfish/article/details/24043099
(完)
By Still、