1.鏈表
1.1鏈表的概念和結構
鏈表是一種物理存儲結構上非連續存儲結構,數據元素的邏輯順序是通過鏈表中引用鏈接次序實現的。
這里大多討論無頭單向非循環鏈表。這種結構,結構簡單,一般與其他數據結構結合,作為其他數據結構的子數據。
1.2鏈表的實現
public class MysingleList {static class ListNode{public int val;//節點的值域public ListNode next;//下一個節點為地址public ListNode(int val){this.val=val;}}public ListNode head;//當前鏈表的頭節點public void createList(){ListNode node1 = new ListNode(12);ListNode node2 = new ListNode(23);ListNode node3 = new ListNode(34);ListNode node4 = new ListNode(45);ListNode node5 = new ListNode(56);node1.next = node2;node2.next = node3;node3.next = node4;node4.next = node5;this.head = node1;}}
1.3方法
這里仍然嘗試自己創建方法了解一些基礎的操作
//頭插法public void addFirst(int data){ListNode node=new ListNode(data);node.next=head;head=node;}//尾插法public void addLast(int data){ListNode node=new ListNode(data);ListNode cur=head;if (cur==null){head=node;return ;}while(cur.next!=null){cur=cur.next;}cur.next=node;}//任意位置插入,第一個數據節點為0號下標public void addIndex(int index,int data) {if (index<0||index>size()){System.out.println("位置不合法");return;}if (index==0){addFirst(data);}if (index==size()){addLast(data);}ListNode node = new ListNode(data);ListNode cur=findIndex(index);node.next=cur.next;cur.next=node;}private ListNode findIndex(int index){ListNode cur=head;int count=0;while (cur!=null){cur=cur.next;count++;if (count==index-1){break;}}return cur;}//查找是否包含關鍵字key是否在單鏈表當中public boolean contains(int key){ListNode cur=head;while (cur!=null){if(cur.val==key){return true;}cur=cur.next;}return false;}//刪除第一次出現關鍵字為key的節點public void remove(int key){if (head==null){return;}if (head.val==key){head=head.next;return;}ListNode cur=findKey(key);if(cur==null){System.out.println("沒有對應的數值");return ;}ListNode del=cur.next;cur.next=del.next;}private ListNode findKey(int key){ListNode cur=head;while (cur.next!=null){if (cur.next.val==key){return cur;}cur=cur.next;}return null;}//刪除所有值為key的節點public void removeAllKey(int key){if (head==null){return;}ListNode cur=head.next;ListNode pre=head;while(cur!=null){if(cur.val==key){pre.next=cur.next;cur=cur.next;}else {pre=cur;cur=cur.next;}}if (head.val==key){head=head.next;//需要放在最后不然找不到后面的數據了。}}//得到單鏈表的長度public int size(){int count=0;ListNode cur=head;while(cur!=null){count++;cur=cur.next;}return count;}public void clear() {this.head=null;}public void display() {ListNode cur=head;while(cur!=null){System.out.print(cur.val+" ");cur=cur.next;}System.out.println();}
另外在管理員中使用jps可以顯示當前系統中所有正在運行的 Java 進程的 進程 ID(PID) 和 主類名 或 JAR 包名。jmap語言可以用于查看 Java 進程的內存使用情況、生成堆轉儲(heap dump)等。
這里再補充幾道常見鏈表操作的題目:
876. 鏈表的中間結點
這一題可以使用快慢指針,快指針永遠是慢支針步數的兩倍。
class Solution {public ListNode middleNode(ListNode head) {if(head==null){return null;}if(head.next==null){return head;}ListNode fast=head;ListNode slow=head;while(fast!=null&&fast.next!=null){fast=fast.next.next;slow=slow.next;}return slow;}
}
206. 反轉鏈表
class Solution {public ListNode reverseList(ListNode head) {if(head==null){return null;}if(head.next==null){return head;}ListNode cur=head.next;head.next=null;while(cur!=null){ListNode curNext=cur.next;//保存下一個節點cur.next=head;head=cur;cur=curNext;}return head;}
}
LCR 027. 回文鏈表
class Solution {public boolean isPalindrome(ListNode head) {ListNode fast=head;ListNode slow=head;//找到中間節點while (fast!=null && fast.next!=null){fast=fast.next.next;slow=slow.next;}//翻轉后半部分的鏈表ListNode cur=slow.next;while(cur!=null){ListNode curNext=cur.next;cur.next=slow;slow=cur;cur=curNext;}//判斷回文while(head!=slow){if(head.val!=slow.val){return false;}if(head.next==slow){return true;}head=head.next;slow=slow.next;}return true;}
}
鏈表分割_牛客題霸_牛客網
public ListNode partition(ListNode pHead, int x) {// write code hereListNode bs = null;ListNode be = null;ListNode as = null;ListNode ae = null;ListNode cur = pHead;//沒有遍歷完 整個鏈表while(cur != null) {if(cur.val < x) {//第一次插入if(bs == null) {bs = be = cur;}else {be.next = cur;be = be.next;}}else {//第一次插入if(as == null) {as = ae = cur;}else {ae.next = cur;ae = ae.next;}}cur = cur.next;}//第一個段 沒有數據if(bs == null) {return as;}be.next = as;//防止 最大的數據 不是最后一個if(as!=null) {ae.next = null;}return bs;}
141. 環形鏈表 - 力扣(LeetCode)
public class Solution {public boolean hasCycle(ListNode head) {if(head==null){return false;}ListNode fast=head;ListNode slow=head;while(fast!=null&&fast.next!=null){fast=fast.next.next;slow=slow.next;if(fast==slow){return true;}}return false;}
}
?160. 相交鏈表 - 力扣(LeetCode)
一定是Y型
public class Solution {public ListNode getIntersectionNode(ListNode headA, ListNode headB) {int lenA=0;int lenB=0;ListNode pl=headA;ListNode ps=headB;while(pl!=null){lenA++;pl=pl.next;}while(ps!=null){lenA++;ps=ps.next;}pl=headA;ps=headB;int len=lenA-lenB;if(len<0){pl=headB;ps=headA;len=lenB-lenA;//讓len能夠一定是正數}}//讓最長的鏈表先走差值步while(len>0){pl=pl.next;len--;}//找到相遇的點while(pl!=ps){pl=pl.next;ps=ps.next;}return pl;
}
?142. 環形鏈表 II - 力扣(LeetCode)
public class Solution {public ListNode detectCycle(ListNode head) {if(head==null){return null;}ListNode fast=head;ListNode slow=head;while(fast!=null&&fast.next!=null){fast=fast.next.next;slow=slow.next;if(fast==slow){break;}}if(fast==null||fast.next==null){return null;}fast=head;while(fast!=slow){fast=fast.next;slow=slow.next;}return fast;}
}
2.LinkedList
2.1概念
LinkedList的底層是雙向鏈表結構,由于鏈表沒有將元素儲存在連續空間中,元素存儲在單獨節點中,通過引用將節點鏈接,因此在進行插入和刪除元素的操作的時候,不需要搬移元素,效率較高。
2.2方法
為幫助理解常用方法的底層邏輯,這里再自己對方法進行實現。
public class MyLinkList {//雙向鏈表static class ListNode{private int val;private ListNode prev;private ListNode next;public ListNode(int val) {this.val=val;}}public ListNode head;public ListNode last;//得到單鏈表的長度public int size(){ListNode cur=head;int count=0;while(cur!=null){count++;cur=cur.next;}return count;}public void display(){ListNode cur=head;while(cur!=null){System.out.print(cur.val+" ");cur=cur.next;}System.out.println();}//查找是否包含關鍵字key是否在單鏈表當中public boolean contains(int key){ListNode cur=head;while(cur!=null){if (cur.val==key){return true;}cur=cur.next;}return false;}//頭插法public void addFirst(int data){ListNode node=new ListNode(data);if (head==null){head=node;last=node;}else{node.next=head;head.prev=node;head=node;}}//尾插法public void addLast(int data){ListNode node=new ListNode(data);if (head==null){head=node;last=node;}else {last.next=node;node.prev=last;last=last.next;}}//任意位置插入,第一個數據節點為0號下標public void addIndex(int index,int data){checkIndex(index);if (index==0){addFirst(data);}if (index==size()){addLast(data);}ListNode cur=findIndex(index);ListNode node=new ListNode(data);node.next=cur.next;cur.prev.next=node;node.prev=cur.prev;cur.prev=node;}private void checkIndex(int index){if (index<0||index>size()){throw new IndexOutOfException("index位置不合法");}}private ListNode findIndex(int index){ListNode cur=head;while(index !=0){cur=cur.next;index--;}return cur;}//刪除第一次出現關鍵字為key的節點public void remove(int key){ListNode cur=head;while (cur!=null){if (cur.val==key){if (cur==head){//如果頭節點正好是目標節點head=head.next;//如果只有這一個節點則為空if (head!=null){head.prev=null;}else {last=null;}}else {//中間節點if (cur.next!=null){cur.prev.next=cur.next;cur.next.prev=cur.prev;}else {//如果正好是last為目標節點cur.prev.next=cur.next;last=last.prev;}}return ;}else {cur=cur.next;}}}//刪除所有值為key的節點public void removeAllKey(int key){ListNode cur=head;while (cur!=null){if (cur.val==key){if (cur==head){//如果頭節點正好是目標節點head=head.next;//如果只有這一個節點則為空if (head!=null){head.prev=null;}else {last=null;}}else {//中間節點if (cur.next!=null){cur.prev.next=cur.next;cur.next.prev=cur.prev;}else {//如果正好是last為目標節點cur.prev.next=cur.next;last=last.prev;}}cur=cur.next;}}}public void clear(){ListNode cur=head;while(cur!=head){ListNode curNext=cur.next;//保存一下cur.prev=null;cur.next=null;cur=curNext;}head=null;last=null;}
}
2.3LinkedList的使用
LinkedList實現了List接口。
1.LinkedList的構造
LinkedList()? ? ? ?--無參構造
public LinkedList(Collection<? extends E> c) --使用其他集合容器中元素構造List
public static void main(String[] args) {List<Integer>list1=new LinkedList<>();list1.add(1);list1.add(2);list1.add(3);}
?2.4遍歷
public static void main(String[] args) {List<Integer>list1=new LinkedList<>();list1.add(1);list1.add(2);list1.add(3);for (int x: list1) {System.out.print(x+" ");}System.out.println();ListIterator<Integer>it=list1.listIterator();while (it.hasNext()){System.out.print(it.next()+" ");}System.out.println();ListIterator<Integer>it2=list1.listIterator(list1.size());while (it.hasPrevious()){System.out.print(it.previous()+" ");}System.out.println();}
2.5ArrayList和LinkedList的區別
又可以說是鏈表和順序表的區別
不同點 | ArrayList | LinkedList |
存儲空間上 | 物理地址上連續 | 邏輯上連續,但物理地址不一定連續 |
隨機訪問 | 支持O(1) | 不支持:O(N) |
頭插法 | 需要搬移元素,效率低 O(N) | 只需要修改引用的指向,時間復雜度為 O(1) |
插入法 | 空間不夠,需要進行擴容 | 沒有容量 |
應用場景 | 元素高效存儲,頻繁訪問 | 任意位置插入和刪除頻繁 |