面試常見-Java 原生實現常見數據結構

Java 原生實現常見數據結構

文章目錄

  • Java 原生實現常見數據結構
    • 一、引言
    • 二、數組(Array)
      • (一)概念
      • (二)代碼實現
    • 三、鏈表(Linked List)
      • (一)概念
      • (二)代碼實現(以單鏈表為例)
    • 四、棧(Stack)
      • (一)概念
      • (二)代碼實現(基于數組實現棧)
    • 五、隊列(Queue)
      • (一)概念
      • (二)代碼實現(基于鏈表實現隊列,也可以基于數組實現)

一、引言

在計算機科學的廣袤領域中,數據結構猶如構建高樓大廈的基石,其重要性不言而喻。它們為數據的組織、存儲與操作提供了標準化的方式,直接影響著算法的效率以及軟件系統的整體性能。Java,作為一門廣泛應用于企業級開發、移動應用開發、大數據處理等眾多領域的編程語言,雖然其類庫已經內置了豐富的數據結構實現,但深入探究如何用 Java 原生代碼實現這些數據結構,對于每一位渴望提升編程內功、透徹理解計算機底層原理的開發者來說,都具有不可估量的價值。這不僅能夠加深我們對數據結構本質的認識,更能在面對復雜多變的業務需求和性能挑戰時,游刃有余地進行定制化開發與優化。本文將帶領讀者踏上一段深入的編程之旅,詳細介紹如何用 Java 原生代碼實現幾種常見且極為重要的數據結構——數組、鏈表、棧和隊列,并對它們的特性、應用場景以及性能特點進行全面剖析。

二、數組(Array)

(一)概念

數組,作為一種最為基礎和常用的線性數據結構,在內存中呈現為一段連續的存儲空間。它猶如一列整齊排列的儲物柜,每個儲物柜都有其唯一的編號(索引),從 0 開始,依次遞增。這些儲物柜專門用于存放相同類型的數據元素,例如整數、浮點數或者對象引用等。這種連續存儲的特性使得數組在隨機訪問元素時具有極高的效率,只需通過索引,就能在常量時間內迅速定位并獲取到指定位置的元素。然而,數組的長度在創建之初就已確定,這就好比儲物柜的數量一旦確定就難以輕易更改,當需要插入或刪除元素時,尤其是在數組中間位置進行操作時,往往需要移動大量后續元素,這無疑會帶來較大的時間開銷。

(二)代碼實現

public class MyArray {private int[] data; // 存儲數組元素的內部數組private int size; // 當前數組中元素的個數// 構造函數,初始化數組的容量public MyArray(int capacity) {data = new int[capacity];size = 0;}// 獲取數組中元素的個數public int getSize() {return size;}// 獲取數組的容量public int getCapacity() {return data.length;}// 判斷數組是否為空public boolean isEmpty() {return size == 0;}// 在數組末尾添加元素public void addLast(int element) {add(size, element);}// 在數組指定位置添加元素public void add(int index, int element) {// 檢查索引的合法性,若索引不合法則拋出異常if (index < 0 || index > size) {throw new IllegalArgumentException("索引不合法");}// 當數組已滿時,進行擴容操作if (size == data.length) {resize(2 * data.length);}// 將指定位置及之后的元素向后移動一位,為新元素騰出空間for (int i = size - 1; i >= index; i--) {data[i + 1] = data[i];}data[index] = element;size++;}// 獲取指定位置的元素public int get(int index) {// 檢查索引的合法性,若索引不合法則拋出異常if (index < 0 || index >= size) {throw new IllegalArgumentException("索引不合法");}return data[index];}// 修改指定位置的元素public void set(int index, int newElement) {// 檢查索引的合法性,若索引不合法則拋出異常if (index < 0 || index >= size) {throw new IllegalArgumentException("索引不合法");}data[index] = newElement;}// 查找元素是否在數組中存在,返回索引,不存在返回 -1public int contains(int element) {for (int i = 0; i < size; i++) {if (data[i] == element) {return i;}}return -1;}// 刪除指定位置的元素,并返回被刪除的元素public int remove(int index) {// 檢查索引的合法性,若索引不合法則拋出異常if (index < 0 || index >= size) {throw new IllegalArgumentException("索引不合法");}int ret = data[index];// 將指定位置之后的元素向前移動一位,覆蓋要刪除的元素for (int i = index + 1; i < size; i++) {data[i - 1] = data[i];}size--;// 當數組元素數量過少時,進行縮容操作,以節省內存空間if (size == data.length / 4 && data.length / 2!= 0) {resize(data.length / 2);}return ret;}// 從數組末尾刪除元素public int removeLast() {return remove(size - 1);}// 數組擴容或縮容方法private void resize(int newCapacity) {int[] newData = new int[newCapacity];// 將原數組中的元素復制到新數組中for (int i = 0; i < size; i++) {newData[i] = data[i];}data = newData;}
}

可以通過以下方式測試這個自定義數組類:

public class Main {public static void main(String[] args) {MyArray myArray = new MyArray(10);myArray.addLast(1);myArray.addLast(2);myArray.add(1, 3);System.out.println("數組元素個數: " + myArray.getSize());System.out.println("數組容量: " + myArray.getCapacity());System.out.println("索引為 1 的元素: " + myArray.get(1));myArray.remove(1);System.out.println("刪除元素后數組元素個數: " + myArray.getSize());}
}

三、鏈表(Linked List)

(一)概念

鏈表,同樣屬于線性數據結構的范疇,但與數組截然不同。它就像是一條由多個節點連接而成的鏈條,每個節點恰似鏈條上的一環,包含了數據元素以及指向下一個節點的指針(在單鏈表的情況下)。鏈表的節點在內存中并非連續存儲,而是通過指針相互鏈接,這種離散存儲的方式使得鏈表在插入和刪除元素時具有獨特的優勢,只需調整相關節點的指針指向,無需像數組那樣大規模地移動元素,從而在頻繁進行插入和刪除操作的場景中表現出色。然而,鏈表在隨機訪問元素方面相對較弱,因為要訪問某個特定位置的元素,需要從鏈表頭開始逐個遍歷節點,直到找到目標節點,這一過程的時間復雜度為 O(n),其中 n 為鏈表的長度。

(二)代碼實現(以單鏈表為例)

// 定義鏈表節點類
class ListNode {int val;ListNode next;ListNode(int val) {this.val = val;this.next = null;}
}// 自定義單鏈表類
public class MyLinkedList {private ListNode head; // 頭節點private int size; // 鏈表節點個數// 獲取鏈表長度public int getSize() {return size;}// 判斷鏈表是否為空public boolean isEmpty() {return size == 0;}// 在鏈表頭部添加節點public void addFirst(int val) {ListNode newNode = new ListNode(val);newNode.next = head;head = newNode;size++;}// 在鏈表指定位置添加節點public void add(int index, int val) {// 檢查索引的合法性,若索引不合法則拋出異常if (index < 0 || index > size) {throw new IllegalArgumentException("索引不合法");}if (index == 0) {addFirst(val);return;}ListNode prev = head;// 找到要插入位置的前一個節點for (int i = 0; i < index - 1; i++) {prev = prev.next;}ListNode newNode = new ListNode(val);newNode.next = prev.next;prev.next = newNode;size++;}// 在鏈表末尾添加節點public void addLast(int val) {add(size, val);}// 獲取指定位置的節點的值public int get(int index) {// 檢查索引的合法性,若索引不合法則拋出異常if (index < 0 || index >= size) {throw new IllegalArgumentException("索引不合法");}ListNode cur = head;// 遍歷鏈表,找到指定位置的節點for (int i = 0; i < index; i++) {cur = cur.next;}return cur.val;}// 修改指定位置節點的值public int set(int index, int newVal) {// 檢查索引的合法性,若索引不合法則拋出異常if (index < 0 || index >= size) {throw new IllegalArgumentException("索引不合法");}ListNode cur = head;// 遍歷鏈表,找到指定位置的節點for (int i = 0; i < index; i++) {cur = cur.next;}int oldVal = cur.val;cur.val = newVal;return oldVal;}// 查找元素是否在鏈表中存在,返回索引,不存在返回 -1public int contains(int val) {ListNode cur = head;for (int i = 0; i < size; i++) {if (cur.val == val) {return i;}cur = cur.next;}return -1;}// 刪除指定位置的節點,并返回被刪除節點的值public int remove(int index) {// 檢查索引的合法性,若索引不合法則拋出異常if (index < 0 || index >= size) {throw new IllegalArgumentException("索引不合法");}if (index == 0) {return removeFirst();}ListNode prev = head;// 找到要刪除位置的前一個節點for (int i = 0; i < index - 1; i++) {prev = prev.next;}ListNode retNode = prev.next;prev.next = retNode.next;size--;return retNode.val;}// 從鏈表頭部刪除節點,并返回被刪除節點的值public int removeFirst() {if (isEmpty()) {throw new IllegalArgumentException("鏈表為空");}ListNode retNode = head;head = head.next;size--;return retNode.val;}// 從鏈表末尾刪除節點,并返回被刪除節點的值public int removeLast() {return remove(size - 1);}
}

以下是測試代碼:

public class Main {public static void main(String[] args) {MyLinkedList myLinkedList = new MyLinkedList();myLinkedList.addFirst(1);myLinkedList.addLast(2);myLinkedList.add(1, 3);System.out.println("鏈表長度: " + myLinkedList.getSize());System.out.println("索引為 1 的節點值: " + myLinkedList.get(1));myLinkedList.remove(1);System.out.println("刪除節點后鏈表長度: " + myLinkedList.getSize());}
}

四、棧(Stack)

(一)概念

棧,作為一種特殊的線性數據結構,遵循后進先出(LIFO)的操作原則。可以將其形象地比喻為一個只能從頂部放入和取出物品的儲物箱。棧只提供了兩個基本操作:入棧(push),即將元素壓入棧頂;出棧(pop),即將棧頂元素彈出。這種特性使得棧在處理具有嵌套結構或需要回溯的問題時大顯身手,例如函數調用棧、表達式求值以及括號匹配等場景。當一個函數被調用時,其相關的局部變量、返回地址等信息就會被壓入棧中,當函數執行完畢后,這些信息又會按照后進先出的順序從棧中彈出,從而實現函數調用的正確返回和資源的回收。

(二)代碼實現(基于數組實現棧)

public class MyStack {private int[] data; // 存儲棧元素的內部數組private int top; // 棧頂指針,指向棧頂元素的下一個位置// 構造函數,初始化棧的容量public MyStack(int capacity) {data = new int[capacity];top = 0;}// 判斷棧是否為空public boolean isEmpty() {return top == 0;}// 獲取棧中元素的個數public int size() {return top;}// 入棧操作public void push(int element) {// 當棧已滿時,進行擴容操作if (top == data.length) {resize(2 * data.length);}data[top++] = element;}// 出棧操作,返回彈出的棧頂元素public int pop() {// 檢查棧是否為空,若為空則拋出異常if (isEmpty()) {throw new IllegalArgumentException("棧為空");}int ret = data[top - 1];top--;// 當棧中元素數量過少時,進行縮容操作,以節省內存空間if (top == data.length / 4 && data.length / 2!= 0) {resize(data.length / 2);}return ret;}// 獲取棧頂元素,但不彈出public int peek() {// 檢查棧是否為空,若為空則拋出異常if (isEmpty()) {throw new IllegalArgumentException("棧為空");}return data[top - 1];}// 棧的擴容或縮容方法private void resize(int newCapacity) {int[] newData = new int[newCapacity];// 將原棧中的元素復制到新棧中for (int i = 0; i < top; i++) {newData[i] = data[i];}data = newData;}
}

測試代碼示例:

public class Main {public static void main(String[] args) {MyStack myStack = new MyStack(10);myStack.push(1);myStack.push(2);System.out.println("棧頂元素: " + myStack.peek());System.out.println("彈出元素: " + myStack.pop());System.out.println("棧是否為空: " + myStack.isEmpty());}
}

五、隊列(Queue)

(一)概念

隊列,與棧類似,也是一種線性數據結構,但它遵循先進先出(FIFO)的原則。就像日常生活中的排隊場景,先到達的人先接受服務。隊列提供了兩個核心操作:入隊(enqueue),即在隊尾添加元素;出隊(dequeue),即從隊頭取出元素。隊列在許多實際應用場景中有著廣泛的應用,例如任務調度系統中,任務按照提交的先后順序依次被處理;消息隊列中,消息按照發送的順序被接收和處理,以確保消息的順序性和公平性。

(二)代碼實現(基于鏈表實現隊列,也可以基于數組實現)

// 定義隊列節點類(與鏈表節點類似)
class QueueNode {int val;QueueNode next;QueueNode(int val) {this.val = val;this.next = null;}
}public class MyQueue {private QueueNode head; // 隊頭節點private QueueNode tail; // 隊尾節點private int size; // 隊列中元素的個數// 判斷隊列是否為空public boolean isEmpty() {return size == 0;}// 獲取隊列中元素的個數public int getSize() {return size;}// 入隊操作,在隊尾添加元素public void enqueue(int element) {QueueNode newNode = new QueueNode(element);if (isEmpty()) {head = tail = newNode;} else {tail.next = newNode;tail = newNode;}size++;}// 出隊操作,從隊頭取出元素并返回public int dequeue() {if (isEmpty()) {throw new IllegalArgumentException("隊列為空");}int ret = head.val;head = head.next;if (head == null) {tail = null;}size--;return ret;}//

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/62770.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/62770.shtml
英文地址,請注明出處:http://en.pswp.cn/web/62770.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

1. 機器學習基本知識(5)——練習題(參考答案)

20.&#x1f517;本章代碼筆記&#x1f4d3;鏈接&#xff08;需要&#x1fa9c;&#xff09;&#xff1a;&#xff08;01_the_machine_learning_landscape.ipynb - Colab (google.com)&#xff09; 如果你不想通過上面的官方網址下載本章的筆記&#xff0c;還可以在本篇博文的…

通常一個 Xml 映射文件,都會寫一個 Dao 接口與之對應, 請問,這個 Dao 接口的工作原理是什么?Dao 接口里的方法, 參數不同時,方法能重載嗎?

Dao 接口 即 Mapper 接口 。接口 的 全 限 名 &#xff0c;就是 映 射 文 件 中 的 namespace 的值 &#xff1b; 接口 的 方 法 名 &#xff0c; 就 是 映 射 文 件 中 Mapper 的 Statement 的 id 值&#xff1b; 接 口 方 法 內 的 參數 &#xff0c; 就 是 傳 遞 給 sql 的參…

硬件設計 | Altium Designer軟件PCB規則設置

基于Altium Designer&#xff08;24.9.1&#xff09;版本 嘉立創PCB工藝加工能力范圍說明-嘉立創PCB打樣專業工廠-線路板打樣 規則參考-嘉立創 注意事項 1.每次設置完規則參數都要點擊應用保存 2.每次創建PCB&#xff0c;都要設置好參數 3.可以設置默認規則&#xff0c;將…

WebDAV服務不能上傳大文件,文件超過50M報錯[0x800700DF]怎么辦?

這個問題需要分別從服務端和客戶端解決。 1.Windows客戶端 解除50M文件限制&#xff0c;Windows訪問Webdav服務時&#xff0c;大于50M文件提示錯誤[錯誤:0x800700DF] 部署了webdav&#xff0c;Windows10映射網絡磁盤&#xff0c;傳輸文件超過大約50MB的文件會彈出“0x800700…

安全基礎學習-keil調試匯編代碼

初始目的是為了通過匯編編寫CRC功能。 但是基礎為0&#xff0c;所以目前從搭建工程開始記錄。 大佬繞路。 &#xff08;一&#xff09;創建項目 1. 新建項目 打開 Keil uVision。選擇 Project -> New uVision Project 創建一個新項目。選擇你的目標設備&#xff08;如 AR…

安裝qt 5.15.2筆記

撰文是2024年12月 最終實現了 1、用梯子下載了離線包5.14.2&#xff0c;最后沒用 2、用內地鏡像在線安裝5.15.2&#xff0c;3分鐘裝完 正文開始&#xff0c;qt官方簡稱官方。 官方包官方自5.15.X起&#xff0c;不再提供的exe/run安裝包https://download.qt.io/archive/qt/ …

Redis Java 集成到 Spring Boot

Hi~&#xff01;這里是奮斗的明志&#xff0c;很榮幸您能閱讀我的文章&#xff0c;誠請評論指點&#xff0c;歡迎歡迎 ~~ &#x1f331;&#x1f331;個人主頁&#xff1a;奮斗的明志 &#x1f331;&#x1f331;所屬專欄&#xff1a;Redis &#x1f4da;本系列文章為個人學習筆…

【Syncfusion系列】Diagram 雜談 第三篇 序列化和反序列化

目錄 序列化保存C# 代碼示例&#xff0c; 方式1 &#xff1a;C# 代碼示例&#xff0c; 方式2 &#xff1a; 反序列化加載C# 代碼示例, 方式1&#xff1a;C# 代碼示例, 方式2&#xff1a; **如何序列化自定義屬性**序列化和反序列化都存在的一個問題解決方式 圖表是否已修改&…

麒麟信安推出支持信創PC的新一代云桌面方案,助力政務信創高效安全運維

12月11日&#xff0c;在第二屆國家新一代自主安全計算系統產業集群融通生態大會上&#xff0c;麒麟信安發布了支持信創PC的新一代云桌面方案&#xff0c;該方案是基于國際TCI架構實現國產PC機云化納管在國內的首次發布&#xff0c;并與銀河麒麟桌面操作系統、長城國產PC整機實現…

中國科學院2001年數據結構試題

一、單項選擇題(每空2分&#xff0c;共20分) 1&#xff0e;下列函數中漸近時間復雜度最小的是( )。 A&#xff0e;T1(n)nlog2n5000n B&#xff0e;T2(n)n2-8000n C&#xff0e;T3(n)nlog221-6000n D&#xff0e;T4(n)2nlog2n-7000n 2&#xff0e;線性表的靜態鏈表存儲結構與順序…

MySQL數據表記錄刪操作

刪除操作&#xff1a;作用刪除表里的記錄行&#xff08;都是整行整行的刪除的&#xff09; 1.單表的刪除 語法 delete from 表名 where 要刪除的記錄篩選條件; 案例&#xff1a;刪除員工編號大于203的員工信息 delete from employees where employee_id>203; 2.多表的刪除…

網絡原理04

可靠傳輸&#xff0c;是TCP最核心的特性 可靠傳輸不是說數據100%傳輸給接收方了 1&#xff09;發送方發出數據后&#xff0c;能過知道接收方是否收到數據 2&#xff09;一旦發現對方沒收到&#xff0c;可以通過一定的方法”補救” 1. 確認應答 發送方&#xff0c;把數據已…

微信小程序5-圖片實現點擊動作和動態加載同類數據

搜索 微信小程序 “動物覓蹤” 觀看效果 感謝閱讀&#xff0c;初學小白&#xff0c;有錯指正。 一、功能描述 a. 原本想通過按鈕加載背景圖片&#xff0c;來實現一個可以點擊的搜索button&#xff0c;但是遇到兩個難點&#xff0c;一是按鈕大小調整不方便&#xff08;網上搜索…

Java里局部變量和成員變量的隱式初始化

注&#xff1a;本文是對另一篇文檔&#xff08; https://blog.csdn.net/duke_ding2/article/details/142365872 &#xff09;的補充。 文章目錄 環境初始化局部變量&#xff08;棧&#xff09;成員變量&#xff08;堆&#xff09;其它數組 分析安全性性能成員變量 VS. 局部變量…

孚盟云 MailAjax.ashx SQL注入漏洞復現

0x01 產品簡介 上海孚盟軟件有限公司是一家外貿SaaS服務提供商,也是專業的外貿行業解決方案專業提供商。 全新的孚盟云產品,讓用戶可以用云模式實現信息化管理,讓用戶的異地辦公更加流暢,大大降低中小企業在信息化上成本,用最小的投入享受大型企業級別的信息化服務,主要…

“切片賦值”創建列表批量操作“新”方法(Python)

[start:end]切片賦值&#xff0c;擴展了list批量增減元素的操作能力。 (筆記模板由python腳本于2024年12月06日 15:07:56創建&#xff0c;本篇筆記適合研python基礎的coder翻閱) 【學習的細節是歡悅的歷程】 Python 官網&#xff1a;https://www.python.org/ Free&#xff1a;…

LabVIEW實現GPS通信

目錄 1、GPS通信原理 2、硬件環境部署 3、程序架構 4、前面板設計 5、程序框圖設計 6、測試驗證 本專欄以LabVIEW為開發平臺,講解物聯網通信組網原理與開發方法,覆蓋RS232、TCP、MQTT、藍牙、Wi-Fi、NB-IoT等協議。 結合實際案例,展示如何利用LabVIEW和常用模塊實現物聯網系…

Java簡介:打開通往變成世界的大門

Java是什么&#xff1f;為什么它是全球開發者廣泛使用的語言&#xff1f;本篇文章介紹Java的特點、應用場景以及“寫一次&#xff0c;隨處運行”的核心特性&#xff0c;讓零基礎的你建立對Java語言的初步認知。 注&#xff1a;此文章可以僅作了解&#xff0c;不影響之后的學習。…

Unraid實現相冊同步與展示的方案探討

背景&#xff1a;Unraid作為一個NAS系統&#xff0c;能夠實現基本的NAS文件管理功能&#xff0c;但是不提供額外的功能如影音、同步、辦公、和內網穿透等&#xff0c;這些在其他的NAS產品如群暉、綠聯、威聯通等都是提供支持的。然而unraid也有其他方案&#xff0c;即通過特別方…

常見的網絡攻擊手段

IP 欺騙 IP 是什么? 在網絡中&#xff0c;所有的設備都會分配一個地址。這個地址就仿佛小藍的家地址「多少號多少室」&#xff0c;這個號就是分配給整個子網的&#xff0c;「室」對應的號碼即分配給子網中計算機的&#xff0c;這就是網絡中的地址。「號」對應的號碼為網絡號…