zoukankan      html  css  js  c++  java
  • 关于链表的学习

     前言:

        在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、

     

  • 相关阅读:
    手把手教你在CSDN博客中插入图片之剑走偏锋系列
    PCD文件格式详解及在PCL下读取PCD文件
    C 基于数组存储的堆栈实现
    C++ Opencv remap()重映射函数详解及使用示例
    C 线性表的链式存储实现及插入、删除等操作示例
    C 线性表的顺序存储实现及插入、删除等操作示例
    C 单向链表就地逆转
    C 单向链表的创建、插入及删除
    [C#]SQL Server Express LocalDb(SqlLocalDb)的一些体会
    [C#]关于DataDirectory的一些思考
  • 原文地址:https://www.cnblogs.com/ygh1229/p/5753102.html
Copyright © 2011-2022 走看看