关于链表的学习

 前言:

    在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 }
View Code

   再记录一下利用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 }
View Code

 

下面进入重点:

      在平时编程中会用到自定义的链表,这时就要面向对象了,哈哈~。构建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     }
View Code

    还有一些链表操作的方法,感受下~   不论是什么都要举一反三,没有固定不变的,这只是给自己提供一种解决问题的好思路。

比如:

  •  查找单链表的中间结点  
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     }  
View Code
  • 合并两个有序的单链表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     }  
View Code

其他的比如排序的方法等详见博客:http://blog.csdn.net/kerryfish/article/details/24043099

(完)

                                                                                                              By  Still、

 

posted @ 2016-08-09 16:44  华不摇曳  阅读(553)  评论(1编辑  收藏  举报