<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
線性表(linear list)是n個具有相同特性的資料元素的有限序列。
線性表是一種在實際中廣泛使用的資料結構,常見的線性表:順序表、連結串列、棧、佇列、字串。
用一段實體地址連續的儲存單元依次儲存資料元素的線性結構(邏輯上連續,物理上也連續)
(1)靜態順序表:使用定長陣列儲存。
(2)動態順序表:使用動態開闢的陣列儲存
【注意】靜態順序表的定長陣列導致N定大了,空間開多了浪費,開少了不夠用,所以相比之下,動態陣列更為靈活,可根據需要動態分配空間大小
增、刪、改、查
增加操作:從頭部插入、從尾部插入、在任意索引位置處插入
刪除操作:根據索引刪除元素、根據元素值刪除第一個出現的該元素、根據元素值刪除所有該值元素
查詢操作:根據元素值查詢是否存在某元素、根據索引下標返回該處元素值、根據元素值返回索引下標
修改操作:根據索引下標修改該處元素
public class MyArray { private int[]data; private int size; // 無參構造 public MyArray(){ this.data=new int[5]; } // 有參構造 public MyArray(int n){ this.data=new int[n]; } // grow方法用於擴充記憶體 private void grow() { int[] newdata= Arrays.copyOf(data,size*2); this.data=newdata; } // toString方法輸出順序表內容 public String toString(){ String str="["; for (int i = 0; i <size ; i++) { str+=data[i]; if(i!=size-1){ str+=","; } } str+="]"; return str; } // 尾插法: public void addLast(int value){ if(size== data.length){ grow(); } data[size]=value; size++; } // 頭插法: public void addFirst(int value){ if(size==data.length){ grow(); } for (int i = size-1; i >=0; i--) { data[i+1]=data[i]; } data[0]=value; size++; } // 中間任意位置插入: public void addIndex(int index,int value){ if(size==data.length) grow(); if(index<0||index>size){ System.err.println("插入位置不合理!"); return; } else { for (int i = size - 1; i >= index; i--) { data[i + 1] = data[i]; } data[index] = value; size++; } } // 檢視當前陣列中是否存在該元素 public boolean contains(int value){ for (int i = 0; i < size; i++) { if(data[i]==value) return true; } return false; } // 查詢當前陣列元素對應的下標 public int getIndex(int value){ for (int i = 0; i < size; i++) { if(data[i]==value){ return i; } } return -1; } // 查詢陣列下標為index的元素 public int getValue(int index) { if (index < 0 || index > size - 1) { System.out.println("輸入下標不合理"); return -1; } return data[index]; } // 根據索引刪除元素,注意將最後一個元素置為0 public void removeIndex(int index){ if(index<0||index>=size){ System.err.println("輸入不合法!"); } for (int i = index; i <size-1; i++) { data[i]=data[i+1]; } size--; data[size]=0; } // 刪除第一個元素值為value的元素 public void removeValueOnce(int value){ int a=getIndex(value); removeIndex(a); } // 刪除所有元素值為value的元素 public void removeValueAll(int value){ for (int i = 0; i < size; i++) { while(i!=size||data[i]==value) removeIndex(i); } } // 根據索引修改元素 public void recompose(int index,int newValue){ if(index<0||index>=size){ System.err.println("輸入不合法!"); } data[index]=newValue; } }
邏輯上連續,物理上非連續儲存。
連結串列由一個個節點組成,每個節點儲存該節點處的元素值val 以及下一個節點的地址next,由地址next實現邏輯上連續
分類方式:
(1)單連結串列、雙連結串列
(2)帶虛擬頭節點、不帶虛擬頭節點
(3)迴圈連結串列、非迴圈連結串列
按不同分類方式組合有8種:
非迴圈四種:
(1)不帶虛擬頭節點的單向連結串列(非迴圈)
(2)帶虛擬頭節點的單向連結串列(非迴圈)
(3)不帶虛擬頭節點的雙向連結串列(非迴圈)
(4)帶虛擬頭節點的雙向連結串列(非迴圈)
迴圈四種:
(5)不帶虛擬頭節點的單向連結串列(迴圈)
(6)帶虛擬頭節點的單向連結串列(迴圈)
(7)不帶虛擬頭節點的雙向連結串列(迴圈)
(8)帶虛擬頭節點的雙向連結串列(迴圈)
其中:
(1)不帶虛擬頭節點的單向連結串列(非迴圈):結構簡單,一般不會單獨用來存資料。實際中更多是作為其他資料結構的子結構,如雜湊桶、圖的鄰接表等等。這種結構在筆試面試中出現很多
(7)不帶虛擬頭節點的雙向連結串列(迴圈):在Java的集合框架庫中LinkedList底層實現就是無頭雙向迴圈連結串列
增、刪、查、改 和順序表實現方法基本一樣;
唯一注意:帶虛擬頭節點與不帶虛擬頭節點相比,帶虛擬頭節點避免了考慮頭節點為空的特殊情況
(1)不帶虛擬頭節點的單連結串列:
class Node { // val表示儲存的數值,next表示下一個節點的地址 int val; Node next; // 構造方法 public Node(int val) { this.val = val; } } public class SingleList { // size表示節點個數 // head表示頭節點 private int size; private Node head; //定義toString方法以輸出連結串列內容 public String toString() { String str = ""; Node node = head; while (node != null) { str += node.val; str += "->"; node = node.next; } str += null; return str; } //將判斷輸入的索引是否合法抽象為方法islegal public boolean islegal(int index) { if (index < 0 || index > size) { return false; } else { return true; } } // 頭插法 public void addHead(int value) { Node node = new Node(value); if (head == null) { head = node; } else { node.next = head; head = node; } size++; } // 中間任意位置插入 public void addIndex(int index, int val) { if (!islegal(index)) { System.out.println("輸入資料不合法!"); return; } if (index == 0) { addHead(val); return; } Node node = new Node(val); Node pre = head; for (int i = 0; i < index - 1; i++) { pre = pre.next; } node.next = pre.next; pre.next = node; size++; return; } // 尾插法 public void addLast(int val) { if (head == null) { addHead(val); } else { addIndex(size, val); } } // 刪除指定索引位置的元素 public void removeIndex(int index) { if (islegal(index)) { if (index == 0) { Node temp = head; head = head.next; temp.next = null; size--; return; } else { Node pre = head; for (int i = 0; i < index - 1; i++) { pre = pre.next; } Node cur = pre.next; pre.next = cur.next; cur.next = null; size--; } } else { System.out.println("輸入資料不合法!"); } } // 根據元素值刪除元素,且只刪除第一次出現的該元素 public void removeValueOnce(int val) { if (head.next != null && head.val == val) { removeIndex(0); } else { Node pre = head; while (pre.next != null) { if (pre.next.val == val) { pre.next = pre.next.next; pre.next.next = null; size--; return; } pre = pre.next; } } } // 根據元素值刪除元素,且刪除所有該元素 public void removeValueAll(int val) { while (head.next != null && head.val == val) { Node temp = head; head = head.next; temp = null; size--; } if (head == null) { return; } else { Node pre = head; while (pre.next != null) { if (pre.next.val == val) { pre.next = pre.next.next; size--; return; } else { pre = pre.next; } } } } // 根據元素值刪除元素,且刪除所有該元素並返回頭節點(帶虛假節點) public Node removeValueAllWithDummy(int val) { Node dummyHead = new Node(-1); dummyHead.next = head; Node pre = dummyHead; while (pre.next != null) { if (pre.next.val == val) { Node cur = pre.next; pre.next = cur.next; cur.next = null; size--; } else { pre = pre.next; } } return dummyHead.next; } // 根據索引查元素值 public int get(int index) { if (islegal(index)) { Node cur = head; for (int i = 0; i < index; i++) { cur = cur.next; } return cur.val; } else { System.out.println("輸入資料不合法!"); return -1; } } // 能否查到給定的某元素值(自己寫的,好像很複雜) public boolean contains(int val) { boolean a = false; if (head == null) { System.out.println("該連結串列為空!"); return false; } else { Node node = head; for (int i = 0; i < size; i++) { if (node.val == val) { a = true; } node = node.next; } } return a; } // 能否查到給定的某元素值,老師寫的方法 public boolean contains2(int val) { for (Node temp = head; temp != null; temp = temp.next) { if (temp.val == val) { return true; } } return false; } // 根據索引修改元素值 public void set(int index, int newValue) { if (islegal(index)) { Node node = head; for (int i = 0; i < index; i++) { node = node.next; } node.val = newValue; return; } System.out.println("輸入資料不合法!"); } }
(2)帶虛擬頭節點的單連結串列
以在指定索引位置插入元素為例,理解虛擬頭節點的作用即可
public class SingleListWithDummyHead { Node dummyNode=new Node(-1); int size; // 在指定位置插入元素,因為有虛擬頭節點故不用考慮index=0的情況,全部為在中間位置插入的情況 public void addIndex(int index,int value){ // 先判斷index是否合法 if(index<0||index>size){ System.out.println("illegal"); return; } Node a=new Node(value); Node pre=dummyNode; for(int i=0;i<index;i++){ pre=pre.next; } a.next=pre.next; pre.next=a; size++; } }
(3)帶虛擬頭節點的雙連結串列
public class DoubleLinkedList { private int size; private Node dummyHead = new Node(-1); private Node tail; // 定義toString方法用以方便輸出 public String toString() { String s = ""; Node node = dummyHead.next; while (node != null) { s = s + node.val; s = s + "->"; node = node.next; } s += "null"; return s; } // 判斷輸入的索引是否合法 private boolean isRange(int index) { if (index < 0 || index >= size) { System.out.println("輸入不合法!"); return false; } else return true; } // 頭插法 public void addHead(int val) { Node a = new Node(val, dummyHead, dummyHead.next); //連結串列為空 if (dummyHead.next == null) { tail = a; dummyHead.next = a; } // 否則連結串列不為空 else { dummyHead.next.prev = a; dummyHead.next = a; } size++; } // 尾插法 public void addTail(int val) { Node a = new Node(val, tail, null); // 連結串列為空 if (dummyHead.next == null) { dummyHead.next = a; } // 連結串列不為空 else { tail.next = a; } tail = a; size++; } // 中間位置插入 public void addMiddle(int index, int val) { // 判斷插入位置合理否 if (index < 0 || index > size) { System.out.println("輸入不合法!"); } // 頭部插入 else if (index == 0) { addHead(val); } // 尾部插入 else if (index == size) { addTail(val); } // 中間任意位置插入 else { //先找到要插入位置的前一個元素,可另一個方法找該元素 Node a = new Node(val, find(index), find(index).next); find(index).next.prev = a; find(index).next = a; size++; } } // 這裡find的方法是找到index位置的前一個節點元素 public Node find(int index) { Node f = dummyHead; for (int i = 0; i < index; i++) { f = f.next; } return f; } // 根據索引刪除指定位置的元素 public void removeIndex(int index) { if (index < 0 || index >= size) { System.out.println("輸入不合法!"); return; } else { find(index).next.next.prev = find(index); find(index).next = find(index).next.next; size--; } } // 刪除指定節點 private void deleteNode(Node node) { // 分治思想,先處理node與左邊節點,再處理node與右邊節點 Node pre = node.prev; Node next = node.next; // 處理左邊,因為有虛擬頭節點,故不用另討論為頭節點的情況 pre.next = next; node.prev = null; // 處理右邊 if (next == null) { tail = pre; } else { next.prev = pre; node.next = null; } size--; } // 刪除指定元素值(只刪除第一次出現的) public void removeValueOnce(int val) { for (Node a = dummyHead.next; a != null; a = a.next) { if (a.val == val) { deleteNode(a); return; } } System.out.println("連結串列中無該元素故無法刪除"); } public void removeValueAll(int val) { for (Node a = dummyHead.next; a != null; ) { if (a.val == val) { Node b = a.next; deleteNode(a); a = b; } else a = a.next; } } // 根據索引查詢元素值 public int get(int index) { if (isRange(index)) { return find(index).next.val; } else { return -1; } } // 查詢是否存在某元素 public boolean contains(int val) { Node a = dummyHead; while (a.next != null) { if (a.next.val == val) { return true; } a = a.next; } return false; } // 修改,將指定位置元素修改為另一值 public void set(int index, int newValue) { if (isRange(index)) { find(index).next.val = newValue; } } } //節點類 class Node { int val; Node prev; Node next; public Node(int val) { this.val = val; } public Node(int val, Node prev, Node next) { this.val = val; this.prev = prev; this.next = next; } }
順序表:
優點:空間連續、支援隨機存取
缺點:中間或前面部分的插入刪除時間複雜度O(N)
增容的代價比較大。
連結串列:
優點:任意位置插入刪除時間複雜度為O(1)
沒有增容問題,插入一個開闢一個空間
缺點:以節點為單位儲存,不支援隨機存取
到此這篇關於Java實現順序表和連結串列結構的文章就介紹到這了,更多相關Java順序表和連結串列內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45