日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

模拟实现顺序表ArrayList2(三级)

發布時間:2024/4/13 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 模拟实现顺序表ArrayList2(三级) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
package com.learn.datastructure;/*** 線性接口表* 我怎么覺得這些方法我們都學過,* 是不是都學過,大同小異,* 注意這是一個接口,和存儲結構無關* 無論是順序表還是鏈表,都要把這些功能給我實現,* 首先我們來講順序表啦,* @author Leon.Sun**/ public interface List {// 返回線性表的大小,即數據元素的個數。/*** 線性表里又幾個元素* @return*/public int size();// 返回線性表中序號為 i 的數據元素/*** 獲取第i個元素* @param i* @return*/public Object get(int i);// 如果線性表為空返回 true,否則返回 false。/*** 線性表是不是空的,* @return*/public boolean isEmpty();// 判斷線性表是否包含數據元素 e/*** 線性表是不是包括某個元素* 是不是查找* @param e* @return*/public boolean contains(Object e);// 返回數據元素 e 在線性表中的序號/*** 某個元素在線性表的索引* @param e* @return*/public int indexOf(Object e);// 將數據元素 e 插入到線性表中 i 號位置/*** 添加* 這是加到指定位置,線性表的插入操作* @param i* @param e*/public void add(int i, Object e);// 將數據元素 e 插入到線性表末尾/*** 這兩個添加有什么區別,* 這是加到最后,又插入就有添加* @param e*/public void add(Object e);// 將數據元素 e 插入到元素 obj 之前/*** 在誰誰之前加* @param obj* @param e* @return*/public boolean addBefore(Object obj, Object e);// 將數據元素 e 插入到元素 obj 之后/*** 在誰誰之后加* 這個大家自己都可以來寫* @param obj* @param e* @return*/public boolean addAfter(Object obj, Object e);// 刪除線性表中序號為 i 的元素,并返回之/*** 刪除第幾個,這是刪除第幾個元素* 比如我刪除第5個元素* @param i* @return*/public Object remove(int i);// 刪除線性表中第一個與 e 相同的元素/*** 刪除指定值的元素* 比如我刪除值是30的元素* @param e* @return*/public boolean remove(Object e);// 替換線性表中序號為 i 的數據元素為 e,返回原數據元素/*** 修改,把第幾個元素改成新的值* @param i* @param e* @return*/public Object replace(int i, Object e);} package com.learn.datastructure;import java.util.Arrays;/*** 現在這個代碼有沒有缺點,有* * 這里頭有兩個屬性,一個是elementData,一個是size* * 我們只寫了添加,那刪除的時候呢,那更新的時候呢,他不用擴容,* 他只要后移前移,刪除的話前移就可以了,不要擴容,* @author Leon.Sun**/ public class ArrayList implements List {private Object[] elementData;private int size;/*** 構造方法,默認長度是4,JAVA的源碼默認是0*/public ArrayList() {this(4); // elementData = new Object[] {};}/*** 可以指定默認長度* @param initialCapacity*/public ArrayList(int initialCapacity) {/*** 這一個給他賦值了,給他分配了4個空間,*/elementData = new Object[initialCapacity];// size = 0;}/*** 獲取元素個數都非常的簡單*/@Overridepublic int size() {return size;}/*** 我們也簡單的模擬了獲取第i個 元素* 當然要考慮完整的話,就考慮到越界了* 我們還自定義了一個異常*/@Overridepublic Object get(int i) { // if(i<0 || i>=size) { // throw new RuntimeException("數組索引越界異常:" + i); // }if(i<0 || i>=size) {throw new MyArrayIndexOutOfBoundsException("數組索引越界異常:" + i);}return elementData[i];}/*** 判斷是否為空*/@Overridepublic boolean isEmpty() {return size==0;}@Overridepublic boolean contains(Object e) {return false;}@Overridepublic int indexOf(Object e) {return 0;}/*** 數組滿了要擴容這段代碼還是要有,這是我們講的數組一個擴容的原理*/@Overridepublic void add(int i, Object e) {/*** 要是想更嚴謹一些,i加到最后就是size,* 判斷一下,i的位置要正確,* 如果i小于0,或者大于size*/if(i<0 || i>size) {/*** 把我們自定義的數組再寫一下* 索引就是i*/throw new MyArrayIndexOutOfBoundsException("數組指針越界異常!" + i);}/*** 首先數組滿了就要先擴容,擴容之后才考慮添加的問題,*/if(size==elementData.length) {grow();}/*** 假如在678這個位置要添加一個666,首先把678后面的元素都往后移一個位置* 然后空出678這個位置,把666放進去,移動的首先從最后一個位置往后移動* 不能直接移動678,因為直接移動是把678后面一個元素直接覆蓋了,不可以的,* 后移元素,從最后一個元素開始,后面i后面的元素,并從最后一個元素開始* */ for(int j=size;j>i;j--) {elementData[j] = elementData[j-1];}/*** 給數組的第i個位置賦值*/elementData[i] = e;size++;}/*** 做這個操作是有前提的* * 這個add只是往最后加的*/@Overridepublic void add(Object e) {/*** 這個添加到最后是添加到指定位置的特殊情況,* 加到最后就是加到size,*/this.add(size, e);/*** 如果數組滿了,就擴容就可以了*/ // if(size==elementData.length) { // /** // * 新創建一個新的數組,長度是舊數組的2倍, // * 寫elementData.length這個更容易理解 // */ // Object[] newArr = new Object[elementData.length*2]; // /** // * 將舊數組的數據拷貝到新數組, // */ // for(int i=0;i<size;i++) { // newArr[i] = elementData[i]; // } // /** // * 這個時候elementData還是指向原來的數組,這樣添加元素還是往舊數組里面添加, // * 這個時候堆里面的對象不能再指向舊數組地址0X2012,應該寫0X3012了, // * 這樣就指向了新數組0X3012了,這個時候就會往新數組的后面添加了,這個時候就是把棧里的newArr變量 // * 指向堆里的地址,這個就是一個賦值語句,讓elementData指向新數組, // * newArr的賦給elementData // * // * 我們這里一共寫了三條語句,實際上這一條語句用一條語句就可以搞定了, // */ // elementData = newArr;/*** 舊數組是誰,舊數組是elementData* 新數組長度是多少newLength,然后在賦值給elementData* 把舊的數組擴容到原來的2倍,讓舊的引用指向它,擴容并復制,然后再指向,只要這一條語句就夠了* 我們是擴了一倍,我們看一下真正的ArrayList是擴了多少呢,* JDK里面的int newCapacity = oldCapacity + (oldCapacity >> 1);* JDK是每次增長50%,java.util.ArrayList每次增長50%,* 增長50%是比較合適的,增加1倍可能會導致浪費,*/// elementData = Arrays.copyOf(elementData, elementData.length*2);/*** 越來越像真正的ArrayList*/ // grow(); // }/*** 我們每次都輸出一下數組的長度,我要看一下這個length等于幾* 每次添加都會輸出*/ // System.out.println("length="+elementData.length);// elementData[size] = e; // // size++;// elementData[size++] = e;}/*** JDK里面的是叫grow*/private void grow() {elementData = Arrays.copyOf(elementData, elementData.length*2);}@Overridepublic boolean addBefore(Object obj, Object e) {return false;}@Overridepublic boolean addAfter(Object obj, Object e) {return false;}@Overridepublic Object remove(int i) {return null;}@Overridepublic boolean remove(Object e) {return false;}@Overridepublic Object replace(int i, Object e) {return null;}/*** 我們要產生[123,321,456,678,....]這個結構* */@Overridepublic String toString() {/*** 如果長度等于0,你還那么費勁干嘛* 如果size等于0,一個元素也沒有*/if(size==0) {return "[]";}/*** 創建一個StringBuilder,因為它便于追加* 這個應該有一個初始值"["*/StringBuilder builder = new StringBuilder("[");/*** 開始循環了*/for(int i=0;i<size;i++) {builder.append(elementData[i]);if(i!=size-1) {builder.append(",");}}/*** 他應該有個結尾的值*/builder.append("]");return builder.toString();}} package com.learn.datastructure;/*** 他們在內存里面是怎么實現的,首先畫一個棧內存,然后要畫一個堆內存* * @author Leon.Sun**/ public class TestArrayList {public static void main(String[] args) {// java.util.ArrayList list;/*** 當我們執行這行的時候,我們new ArrayList,* 在堆里面創建了一個對象,這里面有兩個屬性,* 第一個屬性是elementData,第二個屬性是size,* elementData這個初始值是null,size這個初始值是0,* 我們這個對象在堆里的地址是0X1012,當我們執行這個無參構造方法的時候是空的* 里面調用了this(4),在這里面分配了連續的空間,4個空間,這個地址叫0X2012,* 我們熟練以后就不用寫這個地址了,你看他就這么指向了,結果這個數組就不為空,* 就指向了這個數組,然后我們在棧里開辟一個空間,main方法在棧里面,里面定義一個變量,* 這個變量叫list,他的值是0X1012,棧里面的list變量指向堆里面的0X1012,* 堆里面創建了一個對象指向了堆里面的一個數組,當然目前這個數組里面都是有值的,* 初始值是null,因為是Object,對象都是null,我加123,456,678,什么意思,* 我們看一下add里面的代碼,size是0,先把123加到這兒,把123壓到數組0這個位置* size++這樣size就變成1了,當我們加789的時候行不行,不行了,為什么這個時候不行了,* 因為這個數組已經滿了,下面就要擴容了,擴容的條件是什么,數組滿了,你怎么知道數組滿了,* 就是size等于elementData.length,這就滿了,下面一個如何擴容,擴容的策略,* 4個不夠了,下次變成6個,還是8個,還是100個,總得有一個特點吧,比如增長一倍,那就是4變成8,* 還有增長一半,就是4個變6個了,擴容的步驟,不可以在原來的數組后面直接加2個,第一步,我們是調用的add方法* 我們在棧里面分配一個空間,這是add方法,第一步不是四個嗎,再創建一個新的數組,這個長度我們就寫成8唄,* 給新數組的地址X3012,在棧里面定義一個新的變量newArr,給一個地址0X3012,擴容的第二步復制原來數組* 的內容到新數組,后邊還剩下4個,是不是有空間了嗎* * 剛才我們添加第5個就報錯,現在我們看一下,沒報錯,長度變成5了,*/List list = new ArrayList();list.add(123);list.add(321);list.add(456);list.add(678);/*** 當我們的元素添加超過4個的時候,馬上就報錯了* 這個是數組要動態的擴容,這個擴容我們已經看的很清楚了*/list.add(789);list.add(111);list.add(222);list.add(111);/*** 超過8個的時候又會擴容,*/list.add(222);/*** 我在678這個位置要新加一個數* * 我們加到20,我們沒有20個元素* 就會報我們自定義的數組異常錯誤* 核心就是數組的一個擴容* 包括元素的前移和后移* 我們擴展了自定義異常,還有一些方法的提取* 然后結合了ArrayList真正的源碼來寫的* 對ArrayList底層的原理有一個掌握了*/list.add(20, 666);System.out.println(list.size());System.out.println(list.isEmpty());System.out.println(list.get(2));System.out.println(list.get(0));/*** 這個8我們先改成3*/System.out.println(list.get(3));/*** 輸出一下list,因為你直接調用list相當于直接調用toString* 我想把所有的元素都輸出出來,按照順序,沒有重寫它的toString方法* */System.out.println(list);} } package com.learn.datastructure;/*** 這個叫自定義異常,他要繼承RuntimeException* 這里面也非常的簡單,只要實現兩個構造方法,* 我們要一個無參的,和一個帶有異常信息的* @author Leon.Sun**/ public class MyArrayIndexOutOfBoundsException extends RuntimeException {public MyArrayIndexOutOfBoundsException() {super();}public MyArrayIndexOutOfBoundsException(String message) {super(message);}}

?

總結

以上是生活随笔為你收集整理的模拟实现顺序表ArrayList2(三级)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。