數據結構與算法 (Java 語言實現) —— 線性表
一、Java 數組的回顧學習
在學 java 基礎的時候,我們會經常用到數組來存儲相同類型的數據,下面我們就來簡單回顧一下 Java 數組的簡單使用,實在忘記怎麼使用 java 數組的同學可以查看這篇文章 Java 數組的使用
import java.util.Arrays;
public class TestArray {
public static void main(String[] args) {
// 創建一個數組
int[] arr = new int[5];
// 獲取數組長度
int len = arr.length;
// 循環給數組賦值
for (int i=0;i<len;i++) {
arr[i] = i*i;
}
// 遍歷數組
for (int i=0; i<len; i++)
System.out.println(arr[i]);
// 顯示數組中的所有元素
System.out.println(Arrays.toString(arr));
}
}
以上便是系統給我們提供的 數組 api ,基於此我們可以我們就可以完成很多常規操作。但是內置的數組有時候也會帶來極大的侷限性?
- 數組是定長的,我們需要動態的修改數據要怎麼解決呢?
- 比如往數組添加一個元素?可以使用 List ArrayList 等等現成的數據結構
- 刪除一個元素又要如何來做呢?
- 修改元素很簡單,直接替換對應的下標的值即可
- 在任意位置插入一個元素該怎麼處理呢?
但是如果能夠出現一個變長數組的話,這些問題就可以很輕鬆的解決了。
二、使用 OOP 編寫變長數組
注意:如果要實現傳入任意數據類型的話,我們就可以把 int 數組 改爲 object即可
2.0 準備
定義一個 MyArray 的 Java 類,然後添加一個私有的數組屬性,並使用 無參的構造方法把數組初始化爲長度爲0的一個數組
/**
* 封裝數組
* */
public class MyArray {
private int[] elements;// 存儲數據的數組,如果存儲其他類型,聲明爲 Object
public MyArray() {
elements=new int[0];
}
}
2.1 實現 add 動態添加一個元素
我們使用定長數組的時候,要實現往數組中添加一個元素,這時候我們想到的一個方式就是創建一個新的數組來實現擴容,順着這個思路就這往下想,是不是輕鬆很多了呢?
思路有了,我們就用代碼實現
// 我們要實現新增一個元素,所以需要傳一個要新增元素的參數
public void add(int element) {
// 創建一個比元素組容量多一個元素的數組空間
int[] newArr = new int[elements.length+1];
// 使用循環給新數組賦值
for(int i=0;i<elements.length;i++) {
newArr[i] = elements[i];
}
// 賦值完畢之後,把新增的元素放在數組的最後一個位置, 這裏填寫 elements.length 大家可以仔細思考以下 下標和 長度的位置關係
newArr[elements.length] = element;
// 把數組更新即可
elements = newArr;
}
2.2 實現 delete 刪除任意一個位置的元素
刪除一個元素,分爲兩種情況:
- 一種是刪除末尾元素
- 一種是刪除中間的元素
刪除末尾的元素比較容易,直接把數組的長度減一,然後把剩下的元素重新賦值給一個新的元素就 OK 了
刪除中間的元素,要考慮一個元素,就是是否越界的情況要考慮在內,如果沒有越界,就把刪除的元素的前面的元素重新賦值,刪除的元素的後面的元素也直接賦值的新數組當中就可以了
// 刪除數組中的元素
public void delete(int index) {
// 判斷下標是否越界
if (index<0 || index>elements.length-1) {
throw new RuntimeException("下標越界");
}
int newArr[] = new int[elements.length-1];
// 複製原有數據到新數組
for (int i=0; i<newArr.length; i++) {
if (i<index) {
newArr[i] = elements[i];
} else {
// 想要刪除之後的元素
newArr[i] = elements[i+1];
}
}
// 新數組替換就數組
elements = newArr;
}
2.3 實現 size 方法獲取當前數組的長度
直接返回當前數組的長度即可
public int size() {
return elements.length;
}
2.4 實現 get 獲取指定下標的元素
用戶傳入一個下標值,然後判斷傳入的值是否合理,不合理則返回異常。反之就正常返回數據
public int get(int index) {
if (index<0 || index >elements.length)
throw new RuntimeException("下標越界");
return elements[index];
}
2.5 實現 insert 在任意位置插入一個元素
和刪除元素是一樣的道理,只不過是在任意位置增加一個元素
// 插入元素到一個指定位置
public void insert(int index, int element) {
// 創建一個新數組
int[] newArr = new int[elements.length + 1];
for (int i=0;i<newArr.length;i++) {
// 前面的數據保持一致
if (i<index) {
newArr[i] = elements[i];
} else {
// 後面的數據在插入的位置留出來
newArr[i+1] = elements[i];
}
}
// 實現插入操作
newArr[index] = element;
// 數組替換
elements = newArr;
}
2.6 實現 set 替換任意一個元素
替換隻需要用戶傳入下標值,以及要替換的元素即可
// 替換指定位置的元素
public void set(int index, int element) {
elements[index] = element;
}
三、棧的實現 (Stack)
3.1 棧的基本特點
棧是一個 單進單出的數據結構,棧只能在一端進,一端出。下面畫一個圖給大家加深一下印象
- 棧具有棧底 以及 棧頂兩部分
- 每次入棧 和 出棧 都是從棧頂進入和出去的
- 第一個入棧的元素會直接壓入棧底,然後慢慢的往棧頂堆,直到棧被裝滿
- 棧是具有 先進後出, 後進顯出的特點
3.2 棧的實現之準備工作
我是使用動態數組完成棧的操作的,當然一個棧的空間應該一開始就指定好的。
/**
* 實現棧,使用數組存儲數據
* 每次往棧頂添加元素
* */
public class MyStack {
int[] elements;
// 棧的初始化
public MyStack() {
elements = new int[0];
}
}
3.3 棧的實現之入棧 (push)
// 入棧 push, 把數據放進棧的最後
public void push(int element) {
int newArr[] = new int[elements.length+1];
for (int i=0;i<elements.length-1;i++) {
newArr[i] = elements[i];
}
//
newArr[elements.length] = element;
// 更新數組
elements = newArr;
}
3.4 棧的實現之出棧(pop)
// 出棧 pop, 取棧頂元素
public int pop() {
if (elements.length == 0) {
throw new RuntimeException("tack is empty!");
}
// 去最後一個元素
int element = elements[elements.length-1];
// 創建一個新數組
int newArr[] = new int[elements.length-1];
for (int i=0;i<elements.length-1;i++) {
newArr[i] = elements[i];
}
elements = newArr;
// 返回棧頂元素
return element;
}
3.5 棧的實現之查看棧頂元素(peek)
//查看棧頂元素
public int peek() {
if (elements.length == 0) {
throw new RuntimeException("stack is empty!");
}
return elements[elements.length-1];
}
3.6 棧的實現之判斷棧爲空(isEmpty)
// 判斷棧是否爲空
public boolean isEmpty() {
return elements.length == 0;
}
四、隊列的實現 (Queue)
4.1 隊列的基本特點
- 隊列有兩端,一段是隊首,另一端就是隊尾
- 隊列進入元素一般是從隊首進入
- 隊列出元素一般是從隊尾出
- 隊列的特點,先進先出,後進後出
4.2 隊列之入隊(add)
第一次用 PPT 動畫做
// 入隊
public void add(int element) {
int newArr[] = new int[elements.length + 1];
// 數組拷貝
for (int i=0;i<elements.length;i++) {
newArr[i] = elements[i];
}
newArr[elements.length] = element;
this.elements = newArr;
}
4.3 隊列之出隊 (pull)
// 出隊
public int pull() {
int element = elements[0]; // 取出第一個數
int newArr[] = new int[elements.length-1];
// 這裏使用新數組的長度來拷貝
for (int i=0;i<newArr.length;i++) {
newArr[i] = elements[i+1];
}
this.elements = newArr;
return element;
}
4.4 隊列之判斷隊列是否爲空(isEmpty)
// 判斷隊列是否爲空
public boolean isEmpty() {
return this.elements.length == 0;
}