1、線性表
線性表,在邏輯結構上是連續的(可理解為連續的一條直線,一對一的關系),而在物理結構上不一定連續,通常以數組和鏈式結構進行存儲。
線性表是一種在實際中廣泛使用的數據結構,常見的線性表有:順序表、鏈表、棧、隊列......
2、順序表
順序表是線性表的一種,其物理地址是連續的,并采用數組的的存儲結構,在數組上完成數據的增刪查改。
3、集合類ArrayList
在Java集合框架中,ArrayList是一個泛型類,并且實現了List接口,是Java為我們封裝好的順序表。
當我們想存儲哪種類型的元素時,都可以通過泛型傳參來構建相應類型的順序表。
接下來,讓我為大家仔細講解一下ArrayList這個集合類。
3.1 ArrayList的成員變量
我們通過觀察ArrayList的源碼,得到其成員變量如下:
已知,DEFAULT_CAPACITY是指默認容量(10),elementData是用來實際存儲數據的數組,size記錄順序表數據的數量,剩下的兩個數組均為空數組。
想要知道他們的用途,我們還需要觀察ArrayList的構造方法。
3.2 ArrayList的構造方法
通過觀察源碼,我們依然可以得出其構造方法:
接下來,我們逐個分析。
3.2.1 帶參構造之public ArrayList(int initialCapacity)
不難看出,我們傳入的參數就是我們初始化順序表時的容量(即大小)。
通過if-else語句可以看出:
1.傳入的參數為正數時,初始化的大小即為參數值。
2.傳入的參數為0時,該順序表數組的引用指向的就是成員變量中的空數組。
3.傳入的參數為負數時,則會拋出異常(數組大小肯定為正數)。
public static void main(String[] args) {ArrayList<Integer> list = new ArrayList<>(10);//初始容量為10}
3.2.2 無參構造之public ArrayList()
這個構造方法就更簡單了,無參構造時,該順序表數組的引用指向的也是成員變量中的空數組。
public static void main(String[] args) {ArrayList<Integer> list = new ArrayList<>();}
3.2.1 帶參構造之public ArrayList(Collection<? extends E> c)
大家看到這個構造方法時,是不是愣住了一下子,哈哈哈~,不要慌張,聽我道來。
我們先來看這個參數Collection,Collection是一個接口,不知道大家是否還有印象,它曾出現在集合框架中的頂層:
而<>中的內容,"?"是指通配符(這里了解即可),extends我們在講解泛型時就已經知道,這規定了通配符的上界為E。
也就是說,該構造方法所傳參數必須滿足以下幾點:
1.實現了Collection接口
2.所具備的泛型必須是E或者E的子類
也就說,我們也可以將另一個順序表當做這個順序表構造方法的參數傳入。
代碼示例:
public static void main(String[] args) {ArrayList<Integer> list = new ArrayList<>();list.add(1);list.add(2);list.add(3);ArrayList<Integer> list1 = new ArrayList<>(list);//將list當做順序表構造方法的參數傳入list1.add(99);list1.add(100);System.out.println(list1);//[1, 2, 3, 99, 100]}
3.3?ArrayList的擴容機制
在上面講順序表的構造方法時,我們講當構造方法為無參構造或者傳入的參數為零時,數組是空數組。既然是空數組,那么我們如何進行數據的添加或者插入呢?以及當數組容量滿時,如何進行數據的添加或者插入呢?
實際上,當無參構造或者傳入的參數為零時,經過源碼的處理,也是將數組的初始容量設置成了DEFAULT_CAPACITY(10)。
且,ArrayList是一個動態順序表,即:在插入元素的過程中會以1.5倍自動擴容(調用Arrays的copyOf方法進行擴容)。
3.4?ArrayList的常用方法
ArrayList提供了很多的方法,在這里,我將列舉較常用的方法。
3.4.1 add方法(數據插入)
該方法實現了重載,分別在順序表尾部插入和在指定下標位置插入。
3.4.1.1 尾部插入數據
方法格式:
代碼示例:
3.4.1.2?指定位置插入數據
方法格式:
代碼示例:
3.4.2?addAll方法
方法格式:
同樣的道理,傳入的參數必須實現了Collection接口,并且其泛型參數的上界為E(上文已經進行了講解)。
調用該方法,可以將參數的數據尾插到當前順序表當中。
代碼演示:
3.4.3?remove方法(數據刪除)
3.4.3.1 刪除指定下標數據
方法格式:
注意:該方法的返回值,為所刪除的數據。
3.4.3.2?刪除確定數值的數據
方法格式:
因為ArrayList是一個泛型類,數組中的元素都為一個對象,所以我們應該傳入相應類型的對象作為參數。
代碼示例:
注意:我們看到,remove方法中的參數被劃上了橫線,這說明該方法的這種傳參調用方式被廢棄了(不常用了),但是我們仍然可以使用。
3.4.4?get方法(獲取數據)
方法格式:
傳入下標,返回指定下標的數據。
3.4.5?set方法(修改數據)
方法格式:
修改指定下標的數據。、
3.4.6?set方法(清空順序表)
方法格式:
?
該方法的底層就是:將有效數據修改為null(各元素為引用類型),再將size(數組大小)置為0。
3.4.7 subList方法(截取順序表)
方法格式:
該方法能夠截取順序表的指定區間(區間為左閉右開),并返回截取后的順序表(注意:返回類型為List,是ArrayList實現的一個接口)。
代碼示例:
需要注意的,新截取的順序表list1和原來的順序表list,指向的的是同一塊空間:
也就是說,修改順序表list1中的數據,list中的數據也會被修改。
3.5 ArrayList的遍歷
3.5.1 for循環遍歷
代碼示例:
public static void main(String[] args) {ArrayList<Integer> list = new ArrayList<>();list.add(1);list.add(2);list.add(3);int size = list.size();for (int i = 0; i < size; i++) {int data = list.get(i);//得到i下標的元素System.out.print(data+" ");}System.out.println();}
3.5.2?for-each循環遍歷
因為順序表實際上是個數組,我們可以通過for-each循環來遍歷順序表:
public static void main(String[] args) {ArrayList<Integer> list = new ArrayList<>();list.add(1);list.add(2);list.add(3);for (int data : list) {System.out.print(data+" ");}}
3.5.3?迭代器遍歷
3.5.3.1?Iterator迭代器
在ArrayList中,存在iterator方法:
通過調用這個方法,我們可以得到一個迭代器對象,再通過這個對象將數據一個一個打印,直到全部打印完成。
public static void main(String[] args) {ArrayList<Integer> list = new ArrayList<>();list.add(1);list.add(2);list.add(3);Iterator<Integer> iterator = list.iterator();while (iterator.hasNext()) {//hasNext方法 用來判斷是否有下一個數據int data = iterator.next();//next方法是 得到下一個數據System.out.print(data+" ");}}
hasNext方法 用來判斷是否有下一個數據。
next方法是 得到下一個數據。
3.5.3.2?ListIterator迭代器
與Iterator迭代器用法相同,我們可以通過listIterator來遍歷順序表:
public static void main(String[] args) {ArrayList<Integer> list = new ArrayList<>();list.add(1);list.add(2);list.add(3);ListIterator<Integer> listIterator = list.listIterator();while (listIterator.hasNext()) {int data = listIterator.next();System.out.print(data+" ");}}
3.5.3.3? Iterator迭代器和ListIterator迭代器的關系
首先,這兩者均為接口。
其次,我們通過源碼可以發現,ListIterator拓展了Iterator,也就是說,ListIterator迭代器拓展了Iterator迭代器的功能,其方法更加豐富。
3.5.3.3.1?ListIterator迭代器的新增功能
這里,我們演示一個ListIterator的新增方法。
通過源碼,我們可以發現ArrayList的listIterator方法可以傳入參數,
調用listIterator方法并傳入參數,得到的迭代器就會來到該下標的元素之后的位置,
我們再使用ListIterator新增的hasPrevious和previous方法就可以實現對順序表從后往前的遍歷:
代碼:
public static void main(String[] args) {ArrayList<Integer> list = new ArrayList<>();list.add(1);list.add(2);list.add(3);int size = list.size();ListIterator<Integer> listIterator = list.listIterator(size);while (listIterator.hasPrevious()) {int data = listIterator.previous();System.out.print(data+" ");}}
OK~本次博客到這里就結束了,
感謝大家的閱讀~歡迎大家在評論區交流問題~
如果博客出現錯誤可以提在評論區~
創作不易,請大家多多支持~