數據結構青銅到王者第三話---ArrayList與順序表(2)

續接上一話:

目錄

一、ArrayList的使用(續)

1、ArrayList的擴容機制(續)

?五、ArrayList的相關練習

1、楊輝三角

2、簡單的洗牌算法

六、ArrayList的問題及思考


一、ArrayList的使用(續)

1、ArrayList的擴容機制(續)

????????ArrayList是一個動態類型的順序表,即:在插入元素的過程中會自動擴容。以下是ArrayList源碼中擴容方式:

 Object[] elementData;   // 存放元素的空間private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};  // 默認空間private static final int DEFAULT_CAPACITY = 10;  // 默認容量大小public boolean add(E e) {ensureCapacityInternal(size + 1);  // Increments modCount!!elementData[size++] = e;return true;}private void ensureCapacityInternal(int minCapacity) {ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));}private static int calculateCapacity(Object[] elementData, int minCapacity) {if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {return Math.max(DEFAULT_CAPACITY, minCapacity);}return minCapacity;}private void ensureExplicitCapacity(int minCapacity) {modCount++;// overflow-conscious codeif (minCapacity - elementData.length > 0)grow(minCapacity);}private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;private void grow(int minCapacity) {// 獲取舊空間大小int oldCapacity = elementData.length;// 預計按照1.5倍方式擴容int newCapacity = oldCapacity + (oldCapacity >> 1);// 如果用戶需要擴容大小 超過 原空間1.5倍,按照用戶所需大小擴容if (newCapacity - minCapacity < 0)newCapacity = minCapacity;// 如果需要擴容大小超過MAX_ARRAY_SIZE,重新計算容量大小if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);// 調用copyOf擴容elementData = Arrays.copyOf(elementData, newCapacity);}private static int hugeCapacity(int minCapacity) {// 如果minCapacity小于0,拋出OutOfMemoryError異常if (minCapacity < 0)throw new OutOfMemoryError();return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;}

總結:

(1)檢測是否真正需要擴容,如果是調用grow準備擴容

(2)預估需要庫容的大小

? ? ? ? ? ? ? ? 初步預估按照1.5倍大小擴容

? ? ? ? ? ? ? ? 如果用戶所需大小超過預估1.5倍大小,則按照用戶所需大小擴容

? ? ? ? ? ? ? ? 真正擴容之前檢測是否能擴容成功,防止太大導致擴容失敗

(3)使用copyOf進行擴容

?五、ArrayList的相關練習

1、楊輝三角

(118. 楊輝三角 - 力扣(LeetCode))

????????分析:

? ?

? ? ? ? 這里就是外側全是1,其他的分別是上面緊挨著的兩個的加和。但是,顯然我們不能像左圖一樣創建順序表,可以轉換成如右圖所示的樣式!!!如右圖,最外側都為1,若位置為(i,j),則[i][j] = [i-1][j] + [i-1][j-1]

? ? ? ? 因此,我們創建一個空列表ret,用來存儲所有的行(每行是一個整數列表)。

? ? ? ? 先處理第一行,元素為1;再循環生成一共numRows行,將每行的第一個元素添加為1。????????

? ? ? ? 利用上一行計算中間元素,最后添加上尾巴(1)。

class Solution {public static List<List<Integer>> generate(int numRows) {List<List<Integer>> ret = new ArrayList<>();List<Integer> list0 = new ArrayList<>();list0.add(1);ret.add(list0);//從第2行開始 進行求每個元素for (int i = 1; i < numRows; i++) {//處理第一個元素List<Integer> curRow = new ArrayList<>();curRow.add(1);//中間List<Integer> preRow = ret.get(i-1);for (int j = 1; j < i; j++) {int val1 = preRow.get(j);int val2 = preRow.get(j-1);curRow.add(val1+val2);}//尾巴curRow.add(1);ret.add(curRow);}return ret;}
}

2、簡單的洗牌算法

(一副新牌,四種花色(?,?,?,?),數值分別為1--13,經過一系列的洗牌之后,分別發給三個人每人5張(輪流抓牌),最后展示剩余牌和三人手里的牌)

public class Card {private String suit;//花色private int rank;   //牌面值public Card(String suit, int rank) {this.suit = suit;this.rank = rank;}@Overridepublic String toString() {/*return "Card{" +"suit='" + suit + '\'' +", rank=" + rank +'}';*/return String.format("[%s %d]", suit, rank);}
}
import java.util.List;
import java.util.ArrayList;
import java.util.Random;public class CardDemo {public static final String[] suits = {"?","?","?","?"};//買來一副新牌public List<Card> buyCard() {List<Card> cardList = new ArrayList<>(52);for (int i = 1; i <= 13; i++) {for (int j = 0; j < 4; j++) {int rank = i;String suit = suits[j];Card card = new Card(suit,rank);cardList.add(card);}}return cardList;}//洗牌public void shuffle(List<Card> cardList) {Random random = new Random();for (int i = cardList.size()-1; i > 0 ; i--) {int index = random.nextInt(i);swap(cardList,i,index);}}private void swap(List<Card> cardList,int i,int j) {/*Card tmp =  cardList[i];cardList[i] = cardList[j];cardList[j] = tmp;*/Card tmp = cardList.get(i);cardList.set(i,cardList.get(j));cardList.set(j,tmp);}//分別發牌public List<List<Card>> play(List<Card> cardList) {List<Card> hand0 = new ArrayList<>();List<Card> hand1 = new ArrayList<>();List<Card> hand2 = new ArrayList<>();List<List<Card>> hand = new ArrayList<>();hand.add(hand0);hand.add(hand1);hand.add(hand2);for (int i = 0; i < 5; i++) {for (int j = 0; j < 3; j++) {Card card = cardList.remove(0);//怎么把對應的牌 放到對應的人的手里面hand.get(j).add(card);}}return hand;}
}
import java.util.*;
public class Test {public static void main(String[] args) {CardDemo cardDemo = new CardDemo();//1. 買52張牌List<Card> cardList = cardDemo.buyCard();System.out.println("剛買回來的牌:");System.out.println(cardList);//2. 洗牌cardDemo.shuffle(cardList);System.out.println("洗過的牌:");System.out.println(cardList);//3. 3個人每個人輪流發牌5張List<List<Card>> ret = cardDemo.play(cardList);for (int i = 0; i < ret.size(); i++) {System.out.println("第"+(i+1)+"個人的牌:"+ret.get(i));}System.out.println("剩下的牌:");System.out.println(cardList);}

運行程序可以得到類似的運行結果:

剛買回來的牌:
[[? 1], [? 2], [? 3], [? 4], [? 5], [? 6], [? 7], [? 8], [? 9], [? 10], [? 11], [? 12], [? 13], [? 1], [? 2], [? 3], [? 4], [? 5], [? 6], [? 7], 
[? 8], [? 9], [? 10], [? 11], [? 12], [? 13], [? 1], [? 2], [? 3], [? 4], [? 5], [? 6], [? 7], [? 8], [? 9], [? 10], [? 11], [? 12], [? 
13], [? 1], [? 2], [? 3], [? 4], [? 5], [? 6], [? 7], [? 8], [? 9], [? 10], [? 11], [? 12], [? 13]]
洗過的牌:
[[? 11], [? 6], [? 13], [? 10], [? 13], [? 2], [? 1], [? 9], [? 12], [? 5], [? 8], [? 6], [? 3], [? 5], [? 1], [? 6], [? 13], [? 12], [? 12], 
[? 5], [? 4], [? 3], [? 7], [? 3], [? 2], [? 1], [? 2], [? 4], [? 8], [? 10], [? 11], [? 10], [? 7], [? 9], [? 4], [? 8], [? 7], [? 8], [? 9], [? 
12], [? 11], [? 11], [? 10], [? 5], [? 13], [? 9], [? 7], [? 6], [? 4], [? 2], [? 1], [? 3]]
第1個人的牌:[[? 11], [? 10], [? 1], [? 5], [? 3]]
第2個人的牌:[[? 6], [? 13], [? 9], [? 8], [? 5]]
第3個人的牌:[[? 13], [? 2], [? 12], [? 6], [? 1]]
剩下的牌:
[[? 6], [? 13], [? 12], [? 12], [? 5], [? 4], [? 3], [? 7], [? 3], [? 2], [? 1], [? 2], [? 4], [? 8], [? 10], [? 11], [? 10], [? 7], [? 9], [? 
4], [? 8], [? 7], [? 8], [? 9], [? 12], [? 11], [? 11], [? 10], [? 5], [? 13], [? 9], [? 7], [? 6], [? 4], [? 2], [? 1], [? 3]]

六、ArrayList的問題及思考

1. ArrayList底層使用連續的空間,任意位置插入或刪除元素時,需要將該位置后序元素整體往前或者往后搬 移,故時間復雜度為O(N)

解決方案:

????????使用LinkedList:鏈表結構插入刪除時間復雜度為O(1)
????????分段數組:將大數組分成多個小數組塊
????????樹狀數組:使用樹形結構維護數據

鏈表+數組組合(Unrolled Linked List)
class Chunk {private static final int CHUNK_SIZE = 64;private Object[] data;private int size;private Chunk next;// 插入刪除只在當前chunk內搬移數據// 大大減少數據移動量
}

2. 增容需要申請新空間,拷貝數據,釋放舊空間。會有不小的消耗。

解決方案:

????????預分配策略:根據業務場景預估容量
????????增量式擴容:每次只擴容部分空間
????????內存池技術:預先申請大塊內存
????????使用鏈表結構:完全避免擴容問題

3. 增容一般是呈2倍的增長,勢必會有一定的空間浪費。例如當前容量為100,滿了以后增容到200,我們再繼 續插入了5個數據,后面沒有數據插入了,那么就浪費了95個數據空間。

解決方案:

????????更合理的擴容因子:1.5倍或其他經驗值
????????縮容機制:當空間利用率低于閾值時自動縮容
????????彈性數組:動態調整容量
????????內存碎片整理:定期整理內存空間

彈性數組(彈性擴容因子)
class ElasticArrayList<T> {private static final double GROW_FACTOR = 1.5;private static final double SHRINK_THRESHOLD = 0.3;private Object[] elementData;private int size;// 根據使用情況動態調整擴容因子private int calculateNewCapacity(int minCapacity) {if (size < 1000) return (int)(size * 1.8);else if (size < 10000) return (int)(size * 1.5);else return (int)(size * 1.2);}// 自動縮容機制public void trimToUsage() {if (size < elementData.length * SHRINK_THRESHOLD) {elementData = Arrays.copyOf(elementData, size);}}
}

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

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

相關文章

[Vid-LLM] docs | 視頻理解任務

鏈接&#xff1a;https://github.com/yunlong10/Awesome-LLMs-for-Video-Understanding docs&#xff1a;Vid-LLM 本項目是關于視頻大語言模型(Vid-LLMs)的全面綜述與精選列表。 探討了這些智能系統如何處理和理解視頻內容&#xff0c;詳細介紹了它們多樣的架構與訓練方法、旨…

構建高可用Agent狀態管理API:Gin+GORM全流程解析

繼寫給 Javaer 看的 Go Gin 教程 之后新寫一篇真實的go開發教程:技術棧?&#xff1a;Go 1.21 Gin 1.9 GORM 2.0 MySQL 5.7 Docker一、技術選型&#xff1a;為什么是GinGORM&#xff1f;1.?性能與簡潔性平衡???Gin?&#xff1a;基于httprouter的高性能框架&#xff0c…

[Java惡補day51] 46. 全排列

給定一個不含重復數字的數組 nums &#xff0c;返回其 所有可能的全排列 。你可以 按任意順序 返回答案。 示例 1&#xff1a; 輸入&#xff1a;nums [1,2,3] 輸出&#xff1a;[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] 示例 2&#xff1a; 輸入&#xff1a;nums …

《李沐讀論文》系列筆記:論文讀寫與研究方法【更新中】

一、如何讀論文讀三遍&#xff1a;1. 第一遍讀完標題和摘要后&#xff0c;直接跳到結論&#xff0c;這幾個部分讀完就大概知道文章在講什么東西了&#xff0c;之后還可以看一下正文中的圖表&#xff0c;判斷一下這篇文章是否適合自己&#xff0c;是否要繼續讀&#xff1b;2. 第…

使用 gemini 來分析 github 項目

https://github.com/bravenewxyz/agent-c角色扮演&#xff1a; 你是一位頂級的軟件架構師和代碼審查專家&#xff0c;擁有超過20年的復雜系統設計和分析經驗。你尤其擅長快速洞察一個陌生代碼庫的核心設計思想、關鍵實現和創新之處。我的目標&#xff1a; 我正在研究以下這個 G…

20.15 Hugging Face Whisper-large-v2中文微調實戰:LoRA+混合精度單卡訓練指南,3倍效率省90%顯存

Hugging Face Whisper-large-v2中文微調實戰:LoRA+混合精度單卡訓練指南,3倍效率省90%顯存 from transformers import Seq2SeqTrainingArguments, Seq2SeqTrainer# 訓練參數配置(以中文語音識別任務為例) training_args = Seq2SeqTrainingArguments(output_dir="./wh…

GitGithub相關(自用,持續更新update 8/23)

文章目錄Git常見命令1. 推送空提交2. 提交Clean-PR3. 回退add操作4. 交互式rebase4.1 切換模式4.2 保存與退出4.3 注意Rebase5. 合并多個commit問題一&#xff1a;Clone Github報錯The TLS connection was non-properly terminated.TLS握手報錯原因解決問題二&#xff1a;Faile…

改華為智能插座為mqtt本地控制

華為插座1. 打開插座后蓋板&#xff0c;取出主板2.取下主板上的82663焊上esp32c3 supermini,熱熔膠粘上&#xff0c;焊接電源正負極&#xff0c;及第5腳4.取下電源板阻容降壓全部。因此電路不能提供足夠電流給esp32工作。5.外接小型ac-dc電源5v6.刷代碼Mqtt插座成品特別提醒&am…

2.4G和5G位圖說明列表,0xff也只是1-8號信道而已

根據你提供的 SDK 代碼&#xff0c;0xFF 僅表示啟用 1 到 8 號信道&#xff08;即 2.4GHz 頻段的信道&#xff09;。這是因為每個 BIT(x) 是一個位標志&#xff0c;0xFF 在二進制中對應的是 11111111&#xff0c;即啟用信道 1 至 8。對于 5GHz 信道&#xff0c;你需要確保傳輸的…

【網絡運維】Shell 腳本編程: for 循環與 select 循環

Shell 腳本編程&#xff1a; for 循環與 select 循環 循環語句命令常用于重復執行一條指令或一組指令&#xff0c;直到條件不再滿足時停止&#xff0c;Shell腳本語言的循環語句常見的有while、until、for及select循環語句。 本文將詳細介紹Shell編程中for循環和select循環的各種…

線性回歸入門:從原理到實戰的完整指南

線性回歸入門&#xff1a;從原理到實戰的完整指南線性回歸是機器學習中最基礎、最實用的算法之一 —— 它通過構建線性模型擬合數據&#xff0c;不僅能解決回歸預測問題&#xff0c;還能為復雜模型&#xff08;如神經網絡、集成算法&#xff09;提供基礎思路。今天我們從 “直線…

積分排行樣式

這個排名需要考慮不同child的位置<view class"pm-top"><!--背景 podiumtree 或 podium--><image class"podium-bg" :src"podium" mode"widthFix"></image><view class"podium-list"><vi…

【機器學習入門】1.1 緒論:從數據到智能的認知革命

引言&#xff1a;什么是機器學習&#xff1f;想象一下&#xff0c;當你在郵箱中看到一封郵件時&#xff0c;系統能自動識別出它是垃圾郵件&#xff1b;當你在購物網站瀏覽商品時&#xff0c;平臺能精準推薦你可能感興趣的物品&#xff1b;當自動駕駛汽車行駛在道路上時&#xf…

iptables 防火墻技術詳解

目錄 前言 1 iptables概述 1.1 Netfilter與iptables關系 1.1.1 Netfilter 1.1.2 iptables 1.1.3 兩者關系 2 iptables的表、鏈結構 2.1 四表五鏈結構介紹 2.1.1 基本概念 2.1.2 四表功能*** 2.1.3 五鏈功能*** 2.2 數據包過濾的匹配流程*** 2.2.1 規則表應用順序*…

SOME/IP-SD報文中 Entry Format(條目格式)-理解筆記3

&#x1f3af; 一、核心目標&#xff1a;解決“找服務”的問題 想象一下&#xff0c;一輛現代汽車里有上百個智能設備&#xff08;ECU&#xff09;&#xff0c;比如&#xff1a; 自動駕駛控制器&#xff08;需要“車速”服務&#xff09;中控大屏&#xff08;需要“導航”和“音…

AAA服務器技術

一、AAA認證架構理解AAA基本概念與架構先介紹&#xff1a; AAA是什么&#xff08;認證、授權、計費&#xff09;重點理解&#xff1a; 為什么需要AAA&#xff1f;它的三大功能分別解決什么問題&#xff1f;關聯后續&#xff1a; 這是所有后續協議&#xff08;RADIUS/TACACS&…

客戶生命周期價值幫助HelloFresh優化其營銷支出

1 引言 了解客戶的長期價值對HelloFresh至關重要。客戶生命周期價值&#xff08;CLV&#xff09;代表了客戶與公司關系的整個過程中所產生的總價值。通過預測這一指標&#xff0c;我們可以更明智地決定如何分配營銷資源&#xff0c;以獲得最大的影響。 在本文中&#xff0c;我…

Vue 2 中的 v-model和Vue3中的v-model

你問的是 v-model&#xff08;不是 v-modal 吧 &#x1f604;&#xff09;&#xff0c;我來幫你梳理一下 Vue2 和 Vue3 的 v-model 區別。&#x1f539; Vue 2 中的 v-model語法<input v-model"msg">v-model 本質上是 語法糖&#xff0c;等價于&#xff1a;<…

樸素貝葉斯算法學習總結

一、貝葉斯理論基礎 1. 貝葉斯思想的核心 貝葉斯算法由 18 世紀英國數學家托馬斯?貝葉斯提出&#xff0c;其核心是解決 “逆概” 問題 —— 區別于 “正向概率” 已知條件求結果概率的思路&#xff0c;逆概是通過觀測到的結果&#xff0c;反推導致該結果的原因概率。比如在日常…

【Protues仿真】基于AT89C52單片機的舵機和直流電機控制

目錄 1 PWM信號 1.1 三個最基本的量 1.1.1 周期 T&#xff08;Period&#xff09; 1.1.2脈沖寬度 Th&#xff08;High Time&#xff09; 1.1.3占空比 D&#xff08;Duty Cycle&#xff09; 1.2 為什么要用 PWM 1.3 關鍵參數對照表 1.4單片機里產生 PWM 的四種套路 1.4…