android 获取数组大小,看得见的数据结构Android版之数组表(数据结构篇)
零、前言:
一講到裝東西的容器,你可能習(xí)慣于使用ArrayList和數(shù)組,你有想過(guò)ArrayList和數(shù)組的區(qū)別嗎?
Java的類起名字都不是隨便亂起的,一般前面是輔助,后面是實(shí)質(zhì):ArrayList = Array + List
Array就是數(shù)組,List便是表結(jié)構(gòu),ArrayList即數(shù)組實(shí)現(xiàn)的表結(jié)構(gòu),問(wèn)題來(lái)了,什么是表結(jié)構(gòu)
注:不要問(wèn)我效果圖用什么軟件畫的...因?yàn)楸緛?lái)就沒(méi)用什么軟件畫。下一節(jié)帶你一起自己畫!!!
希望你可以和我在Github一同見(jiàn)證:DS4Android的誕生與成長(zhǎng),歡迎star
0.不管別的,先留圖鎮(zhèn)樓:
表結(jié)構(gòu)的常規(guī)操作
數(shù)組的擴(kuò)容與縮容
1.在我們生活中都有什么表?
課程表,成績(jī)表,作息時(shí)間表、列車行程表、手表(這個(gè)算了吧...)
復(fù)制代碼
2.表有什么用?
可以把同類的對(duì)象統(tǒng)一管理,比如成績(jī)表:
高三12班的54為同學(xué)的成績(jī)是對(duì)象,對(duì)象又包括數(shù)學(xué)、語(yǔ)文、英語(yǔ)...等屬性
把混亂的54個(gè)對(duì)象放在一起,這么一排,哪個(gè)是學(xué)霸,哪個(gè)是學(xué)渣一目了然,非常方便
如果其中某個(gè)對(duì)象的成績(jī)改錯(cuò)了,可以get到對(duì)象重新set一下,也非常方便
如果中間一個(gè)人作弊了,分?jǐn)?shù)取消,直接remove掉,后面的人名詞往前排,也非常方便
如果高三12班和高三11班要比較成績(jī),兩張表contact一下,就成一張表,合并也很方便
復(fù)制代碼
3.表和數(shù)組有什么不同?
打個(gè)最恰當(dāng)?shù)谋确骄褪?#xff1a;數(shù)組相當(dāng)于打印出來(lái)的紙質(zhì)版而表結(jié)構(gòu)像是Excel中可操作版
1.數(shù)組定長(zhǎng):添加新元素,定位添加都很困難
2.拿刪除來(lái)說(shuō):數(shù)組remove掉了,后面的人名次都不變----(我還沒(méi)個(gè)空白名次高,你說(shuō)氣人不氣人...)
3.表是一種抽象數(shù)據(jù)類型(Abstract Data Type),既然是抽象就是規(guī)范或功能,表會(huì)有不同的實(shí)現(xiàn)形式
[番外]:小和尚問(wèn)老和尚:"什么是圣人?" 老和尚說(shuō):"好好學(xué)習(xí),天天向上,樂(lè)于助人,誠(chéng)信友善"
這里"圣人"便是一種抽象,"好好學(xué)習(xí),天天向上,樂(lè)于助人,誠(chéng)信友善"便是"圣人"的"條件(功能)",
小和尚按照這么做了,他就是老和尚眼中的"圣人",即小和尚實(shí)現(xiàn)了圣人。
4.同樣,表是一種抽象,也可以定義你眼中的表,并為它附上add(),get(),set(),remove()等功能
5.其實(shí)Java的ArrayList實(shí)現(xiàn)了List這個(gè)抽象接口
復(fù)制代碼
4.數(shù)組表結(jié)構(gòu):本文要?jiǎng)?wù)
一、定義自己的表結(jié)構(gòu)
由于Java用List,為了不混淆,取了個(gè)新名字叫Chart
1.定義表的接口
也就是說(shuō)說(shuō)你的表能干嘛用(接口方法最好注釋非常清晰)
/**
* 作者:張風(fēng)捷特烈
* 時(shí)間:2018/9/25 0025:8:25
* 郵箱:1981462002@qq.com
* 說(shuō)明:線性表結(jié)構(gòu)接口
*/
public interface IChart {
//region -------------添加操作------------
/**
* 定點(diǎn)添加
*
* @param index 索引
* @param el 數(shù)據(jù)元素
*/
void add(int index, T el);
/**
* 添加尾
*
* @param el 數(shù)據(jù)元素
*/
void add(T el);
//endregion
//region -------------刪除操作------------
/**
* 定位刪除
*
* @param index 索引
* @return 刪除的元素
*/
T remove(int index);
/**
* 刪除尾位
*
* @return 刪除的元素
*/
T remove();
/**
* 刪除指定元素的第一次出現(xiàn)時(shí)
*
* @param el 數(shù)據(jù)元素
* @return 元素位置
*/
int removeEl(T el);
/**
* 刪除所有指定元素
*
* @param el 數(shù)據(jù)元素
*/
boolean removeEls(T el);
/**
* 清空集合
*/
void clear();
//endregion
//region -------------改查操作------------
/**
* 設(shè)置某位置的元素新值
*
* @param index 索引
* @param el 新值
* @return 舊值
*/
T set(int index, T el);
/**
* 根據(jù)指定位置獲取元素
*
* @param index 索引
* @return 數(shù)據(jù)元素
*/
T get(int index);
/**
* 根據(jù)指定元素獲取匹配索引
*
* @param el 數(shù)據(jù)元素
* @return 索引集
*/
int[] getIndex(T el);
//endregion
//region ------------其他操作-------------
/**
* 集合是否包含某元素
*
* @param el 數(shù)據(jù)元素
* @return 是否包含
*/
public boolean contains(T el);
/**
* 連接兩個(gè)集合
*
* @param iChart 插入集合
* @return 合并后的集合
*/
public IChart contact(IChart iChart);
/**
* 定點(diǎn)連接兩個(gè)集合
*
* @param index 索引
* @param iChart 插入集合
* @return 合并后的集合
*/
IChart contact(int index, IChart iChart);
/**
* 是否為空
*
* @return 是否為空
*/
boolean isEmpty();
/**
* 返回集合大小
*
* @return 大小
*/
int size();
/**
* 獲取數(shù)組容量
* @return 數(shù)組容量
*/
int capacity();
//endregion
}
復(fù)制代碼
2.使用數(shù)組實(shí)現(xiàn)表結(jié)構(gòu):ArrayChart
實(shí)現(xiàn)接口,并實(shí)現(xiàn)接口里的所有方法
/**
* 作者:張風(fēng)捷特烈
* 時(shí)間:2018/11/21 0021:8:18
* 郵箱:1981462002@qq.com
* 說(shuō)明:數(shù)組實(shí)現(xiàn)線性表結(jié)構(gòu)
*/
public class ArrayChart implements IChart {
//空實(shí)現(xiàn)---略
}
復(fù)制代碼
3.成員變量和構(gòu)造初始化
private int size;//表中數(shù)據(jù)的個(gè)數(shù)
private T[] data;//數(shù)據(jù)核心承載體
private static final int DEFAULT_CAPACITY = 10;//默認(rèn)數(shù)組容量
private static final float GROW_RATE = 1.5f;//擴(kuò)容增長(zhǎng)率
public ArrayChart() {
this(DEFAULT_CAPACITY);//無(wú)參構(gòu)造默認(rèn)創(chuàng)建10個(gè)容量的數(shù)組
}
public ArrayChart(int capacity) {
data = (T[]) new Object[capacity];//新創(chuàng)建[數(shù)組表]時(shí)初始化數(shù)組
}
復(fù)制代碼
4.簡(jiǎn)單接口的實(shí)現(xiàn):
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public int size() {
return size;
}
@Override
public int capacity() {
return data.length;
}
復(fù)制代碼
二、主要方法的實(shí)現(xiàn)(CRUD)
1.定點(diǎn)添加元素:
看一下操作圖(將在下一篇:視圖篇完成):默認(rèn)添加到尾部
思路:定點(diǎn)后的所有元素后移一位,空出頂點(diǎn)位,讓待添加元素入駐
紫色框代表空的數(shù)組位,中間填充的是表中的實(shí)際元素
可見(jiàn)定點(diǎn)添加是在選中索引的前一位添加,所以添加到尾部是add(size,data)來(lái)添加
@Override
public void add(T el) {
add(size , el);//這里size---是因?yàn)樵趕ize之前一位添加
}
@Override
public void add(int index, T el) {
if (index < 0 || index > size) {
throw new IllegalArgumentException("Add failed! Make sure index < 0 || index > size");
}
//從最后一個(gè)元素開(kāi)始,到定點(diǎn)位置元素,元素都后移一位
for (int i = size - 1; i >= index; i--) {
data[i + 1] = data[i];
}
data[index] = el;
size++;
}
復(fù)制代碼
2.查找與設(shè)置值:get(),set():
@Override
public T set(int index, T el) {
if (index < 0 || index >= size) {
throw new IllegalArgumentException("Set failed! Make sure index < 0 || index > size");
}
T oldEl = get(index);
data[index] = el;//設(shè)置一下,很簡(jiǎn)單
return oldEl;
}
@Override
public T get(int index) {
if (index < 0 || index >= size) {
throw new IllegalArgumentException("Get failed! Make sure index < 0 || index > size");
}
return data[index];//查詢數(shù)組的對(duì)應(yīng)索引處
}
復(fù)制代碼
定值查詢獲取索引
@Override
public int[] getIndex(T el) {
int[] tempArray = new int[size];//臨時(shí)數(shù)組
int count = 0;//重復(fù)個(gè)數(shù)
for (int i = 0; i < size; i++) {//遍歷集合,獲取該元素重復(fù)個(gè)數(shù),及位置數(shù)組
if (data[i].equals(el)) {
tempArray[count] = i;
count++;
}
}
//將臨時(shí)數(shù)組壓縮---排除空位
int[] indexArray = new int[count];
for (int i = 0; i < count; i++) {
indexArray[i] = tempArray[i];
}
return indexArray;//返回查找元素的索引數(shù)組(相當(dāng)于成績(jī)表看數(shù)學(xué)80分的都有哪些人)
}
復(fù)制代碼
3.刪除元素:
@Override
public T remove() {
return remove(size - 1);
}
@Override
public T remove(int index) {
if (index < 0 || index >= size) {
throw new IllegalArgumentException("Remove failed! Make sure index < 0 || index > size");
}
T temp = get(index);
//從刪除元素索引的下一位開(kāi)始到結(jié)尾,依次左移
// 可簡(jiǎn)寫: System.arraycopy(data, index + 1, data, index + 1 - 1, size - index + 1);
for (int i = index + 1; i < size; i++) {
data[i - 1] = data[i];
}
size--;
//置空--游蕩的對(duì)象
data[size] = null;
return temp;
}
復(fù)制代碼
其他刪除:
定元素刪除單個(gè)和定元素刪除所有相當(dāng)于前面的組合操作,就不做操作演示了
@Override
public int removeEl(T el) {
int[] indexes = getIndex(el);//查找元素的索引集合,刪除首個(gè)
int index = -1;
if (indexes.length > 0) {
index = indexes[0];
remove(indexes[0]);
}
return index;
}
@Override
public boolean removeEls(T el) { //查找元素的索引集合,刪除所有
int[] indexArray = getIndex(el);
if (indexArray.length != 0) {
for (int i = 0; i < indexArray.length; i++) {
remove(indexArray[i] - i); // 注意-i
}
return true;
}
return false;
}
復(fù)制代碼
三、動(dòng)態(tài)擴(kuò)容與縮容的實(shí)現(xiàn)
也沒(méi)有什么高大上的,就是一個(gè)籃子裝不下了,裝個(gè)更大的籃子裝而已
1.擴(kuò)容與縮容方法的實(shí)現(xiàn)
/**
* 擴(kuò)容/縮容
*
* @param newCapacity 新容量
*/
private void grow(int newCapacity) {
T[] newData = (T[]) new Object[newCapacity];//創(chuàng)建個(gè)大籃子
for (int i = 0; i < size; i++) {//把原來(lái)的元素放到大籃子里
newData[i] = data[i];
}
data = newData;
}
復(fù)制代碼
2.擴(kuò)容和縮容的調(diào)用契機(jī)
什么時(shí)候擴(kuò)容----籃子不夠裝了唄---add
什么時(shí)候需要縮容----1000個(gè)容量的籃子裝1個(gè)雞蛋想想也浪費(fèi)---remove
1) add檢測(cè)擴(kuò)容時(shí)機(jī):滿了
@Override
public void add(int index, T el) {
if (size == data.length) {//籃子裝不下了---
grow((int) (GROW_RATE * data.length));//換個(gè)1.5倍的籃子
}
if (index < 0 || index > size) {
throw new IllegalArgumentException("Add failed! Make sure index < 0 || index > size");
}
//從最后一個(gè)元素開(kāi)始,到定點(diǎn)位置元素,元素都后移一位
//可簡(jiǎn)寫:System.arraycopy(data, index, data, index + 1, size - index);
for (int i = size - 1; i >= index; i--) {
data[i + 1] = data[i];
}
data[index] = el;
size++;
}
復(fù)制代碼
2)remove檢測(cè)縮容時(shí)機(jī)
這里的判斷標(biāo)志是留多點(diǎn)備用,不然有可能插入移除頻繁而導(dǎo)致重復(fù)擴(kuò)容或縮容,
籃子可能會(huì)說(shuō):"你到底縮還是放,你是不是在玩老子....,老子給你多留點(diǎn)空行了吧!"
@Override
public T remove(int index) {
if (index < 0 || index >= size) {
throw new IllegalArgumentException("Remove failed! Make sure index < 0 || index > size");
}
T temp = get(index);
//從刪除元素索引的下一位開(kāi)始到結(jié)尾,依次左移
// 可簡(jiǎn)寫: System.arraycopy(data, index + 1, data, index + 1 - 1, size - index + 1);
for (int i = index + 1; i < size; i++) {
data[i - 1] = data[i];
}
size--;
//置空--游蕩的對(duì)象
data[size] = null;
//縮容----此處限定是為了避免反復(fù)出現(xiàn)擴(kuò)容縮容---可自定義
if (size == data.length / 4 && data.length / 2 != 0 && data.length > 5) {
grow(data.length / 2);
}
return temp;
}
復(fù)制代碼
3.清空時(shí),數(shù)組縮放到初始值
@Override
public void clear() {
size = 0;
grow(DEFAULT_CAPACITY);
}
復(fù)制代碼
四、其他操作
1.是否包含某元素
@Override
public boolean contains(T el) {
return getIndex(el).length != 0;//按值查詢有數(shù)據(jù)
}
復(fù)制代碼
2.contact連接數(shù)組
@Override
public IChart contact(IChart iChart) {
return contact(size - 1, iChart);
}
@Override
public IChart contact(int index, IChart iChart) {
if (!(iChart instanceof ArrayChart)) {//必須是數(shù)組才能聯(lián)合
return null;
}
//從index處遍歷本數(shù)組,將待插入數(shù)據(jù)一個(gè)一個(gè)插入
for (int i = index; i < index + iChart.size(); i++) {
add(i + 1, iChart.get(i - index));
}
return this;
}
復(fù)制代碼
作為一個(gè)表結(jié)構(gòu),基本上就演示這么多,還有其他操作可以自定義接口,自己實(shí)現(xiàn),
不過(guò)不管多么復(fù)雜的操作都是以上操作的組合而已。
五、小結(jié):
關(guān)于復(fù)雜度的分析,等到所有表結(jié)構(gòu)講完再整體比較一下,這里先粗略感覺(jué)一下
耗時(shí)測(cè)試
方法\操作次數(shù)10001000010W100W1000Wadd首0.0063秒0.2706秒19.5379秒--------
add尾0.0004秒0.0025秒0.0141秒0.0687秒1.26014秒
remove首0.0063秒0.2771秒19.7902秒--------
remove尾0.0005秒0.0036秒0.0091秒0.02301秒:0.1607秒
可以看出往開(kāi)始添加/刪除會(huì)很困難,從代碼中可以感覺(jué)到,畢竟要讓后面所有人挪一挪
想一下如果30000人排一起,第一個(gè)人走了,后面所有人往前挪一下,是不是工程量挺大的
要是你決定插到第一個(gè),讓后面的人都往后移一下.....(大哥,活著難道不好嗎....)
所以頻繁對(duì)第一個(gè)元素進(jìn)行操作的,還是不要作死,數(shù)組表結(jié)構(gòu)(ArrayList)不適合你
本系列后續(xù)更新鏈接合集:(動(dòng)態(tài)更新)
后記:捷文規(guī)范
1.本文成長(zhǎng)記錄及勘誤表
2.更多關(guān)于我
筆名QQ微信愛(ài)好張風(fēng)捷特烈1981462002zdl1994328語(yǔ)言
3.聲明
1----本文由張風(fēng)捷特烈原創(chuàng),轉(zhuǎn)載請(qǐng)注明
2----歡迎廣大編程愛(ài)好者共同交流
3----個(gè)人能力有限,如有不正之處歡迎大家批評(píng)指證,必定虛心改正
4----看到這里,我在此感謝你的喜歡與支持
總結(jié)
以上是生活随笔為你收集整理的android 获取数组大小,看得见的数据结构Android版之数组表(数据结构篇)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: android最新版本 note8,三星
- 下一篇: android按钮防止重复点击事件,实例