java學習筆記(7)--鏈表

標籤(空格分隔):筆記java


java其實已經將不少底層的數據結構進行了封裝,雖然工做用不到,可是筆試和麪試問的仍是比較頻繁的,並且這種面試題仍是直接手撕代碼,故專門總結一下。面試


1. 概念

1.1 鏈表(Linked list)數組


是一種常見的基礎數據結構,是一種線性表,可是並不會按線性的順序存儲數據,而是在每個節點裏存到下一個節點的指針(Pointer)。使用鏈表結構能夠克服數組鏈表須要預先知道數據大小的缺點,鏈表結構能夠充分利用計算機內存空間,實現靈活的內存動態管理。可是鏈表失去了數組隨機讀取的優勢,同時鏈表因爲增長告終點的指針域,空間開銷比較大。數據結構

1.2 單向鏈表(Single-Linked List)ide


  1. 單鏈表是鏈表中結構最簡單的。一個單鏈表的節點(Node)分爲兩個部分,第一個部分(data)保存或者顯示關於節點的信息,另外一個部分存儲下一個節點的地址。最後一個節點存儲地址的部分指向空值。
  2. 單向鏈表只可向一個方向遍歷,通常查找一個節點的時候須要從第一個節點開始每次訪問下一個節點,一直訪問到須要的位置。而插入一個節點,對於單向鏈表,咱們只提供在鏈表頭插入,只須要將當前插入的節點設置爲頭節點,next指向原頭節點便可。刪除一個節點,咱們將該節點的上一個節點的next指向該節點的下一個節點。

2. 鏈表的java實現


2.1 設計一個接口,定義鏈表須要哪些操做(已經過驗證,放心用)函數

public interface ILinkedList {
    //添加元素
    boolean addItems(Object obj);
    //刪除元素
    boolean deleteItems(Object obj);
    //刪除頭元素
    boolean deleteheadItems();
    //查找
    Object findItems(Object obj);
    //返回長度
    int length();
    //展現全部元素
    void display();
    //判斷是否爲空
    boolean isEmpty();
}

2.2 定義一個單鏈表,實現上述接口的操做(已經過驗證,放心使用)測試

public class NewSingleList implements ILinkedList{
    private int size;//鏈表長度
    private Node head;//鏈表的頭結點,由於是成員變量,默認爲null
    //
    //定義一個成員內部類Node,包含頭部數據和next指向的對象
    public class Node{
        private Object data;
        private Node next;
        public Node(Object data, Node next) {
            this.data = data;
            this.next = next;
        } 
    }
    //添加
    @Override
    public boolean addItems(Object obj) {
        Node n1=new Node(obj,null);
        if(isEmpty()) {
            head=n1;
            size++;
            return true;
        }
        else {
            n1.next=head;//頭插法,從頭部插入,新插入的節點做爲新的head
            head=n1;
            size++;
            return false;
        }
    
    }
//刪除元素
    @Override
    public boolean deleteItems(Object obj) {
        if(isEmpty()) {
            return false;
        }
        if(head.data.equals(obj)) {
            deleteheadItems();//調用刪除頭部元素的函數
            return true;
        }
        //定義當前節點的前一個節點(初始的時候下面兩個起點相同,可是循環一遍以後位置就變了,能夠本身試試)
        Node previous=head;
        Node current=head;//定義當前節點
        while(current!=null) {
            if(current.data.equals(obj)) {
                previous.next=current.next;//刪除核心代碼
                size--;
                return true;
            }
            else {
                previous=current;
                current=current.next;
            }
            
        }
        return false;
            
    }
        
    //刪除頭部元素
    @Override
    public boolean deleteheadItems() {
        if(isEmpty()) {
            return false;
        }
        else {
            head=head.next;
            size--;
            return true;
        }
        
    }
//查找
    @Override
    public Object findItems(Object obj) {
        if(isEmpty()) {return false;}
        Node tmp=head;
        while(tmp!=null) {
            if(tmp.data.equals(obj)) {return true;}
            else {
                tmp=tmp.next;
            }
        }
        return false;
    }
//返回鏈表長度
    @Override
    public int length() {
        
        return size;
    }
//展現元素
    @Override
    public void display() {
        Node tmp=head;
        while(tmp!=null) {
            System.out.println(tmp.data);
            tmp=tmp.next;   
        }
        
    }
//判斷是否爲空
    @Override
    public boolean isEmpty() {
        if(size==0) {
            return true;
        }
        return false;
    }

}

2.3 對這個鏈表進行測試(已經過驗證,放心使用)this

public class ListTest01 {
    public static void main(String[] args) {
        NewSingleList l1=new NewSingleList();
        l1.addItems(4);
        l1.addItems(7);
        l1.addItems(66);
        l1.addItems(233);
        l1.deleteItems(4);
        l1.display();
    }

}

3. 鏈表的常見面試題

3.1 判斷鏈表是否有環設計

//點擊上述題目連接去LeetCode刷題。第141題
//方法一:雙指針,只要有環,快的指針總會遇上慢的指針,空間複雜度O(1)
public class Solution {
    public boolean hasCycle(ListNode head) {
        if(head==null || head.next==null){
            return false;
        }
        ListNode l1=head;
        ListNode l2=head.next;
        while(l1 !=null && l2 !=null && l2.next!=null){
            if(l1==l2){
                return true;
            }
            l1=l1.next;
            l2=l2.next.next;
            
        }
        return false;
    }
}

//若是須要讓你用一個指針,檢查一個結點此前是否被訪問過來判斷鏈表是否爲環形鏈表。經常使用的方法是使用哈希表。時間和空間複雜度都是O(n)
public class Solution {
    public boolean hasCycle(ListNode head) {
       Set<ListNode> l1=new HashSet<>();
       while(head != null){
           if(l1.contains(head)){
           return true;
           }
           else{
               l1.add(head);
           }
           head=head.next;

       }
       return false;
    }
}

3.2 找出鏈表交點指針

//鏈表的交點難點在於鏈表的長度不一樣,當同時進行移位的時候,因爲長度不一樣,可能會致使相同的點完美錯過

//例如兩個鏈表,一個是1-2-5-7-8-1,一個是4-3-8-1,
//當這兩個同時從頭開始時,若是list1=list1.next;list2=liat2.next;當list2指向8的時候,list1剛指向5,顯然不行。
//可是若是把兩個拼接起來,兩者等長,變成1-2-5-7-8-1-4-3-8-1和 4-3-8-1-1-2-5-7-8-1那就容易多了



//      1-2-5-7-\    /-1-2-5-7-8
//               8-1-
//          4-3-/    \4-3-8

 public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
         ListNode l1 = headA, l2 = headB;
        while (l1 != l2) {
        l1 = (l1 == null) ? headB : l1.next;
        l2 = (l2 == null) ? headA : l2.next;
        }
        return l1;
        }
}

3.3 鏈表翻轉

class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode prev=null;
        ListNode cur=head;
        
            while(cur !=null){
                ListNode nextTemp = cur.next;
                cur.next = prev;
                prev = cur;
                cur = nextTemp;
                
        }
        return prev;
        
    }

}
相關文章
相關標籤/搜索