W3Cschool
恭喜您成為首批注冊(cè)用戶(hù)
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
數(shù)組長(zhǎng)度不可變導(dǎo)致實(shí)用性降低。在實(shí)際中,我們可能事先無(wú)法確定需要存儲(chǔ)多少數(shù)據(jù),這使數(shù)組長(zhǎng)度的選擇變得困難。若長(zhǎng)度過(guò)小,需要在持續(xù)添加數(shù)據(jù)時(shí)頻繁擴(kuò)容數(shù)組;若長(zhǎng)度過(guò)大,則會(huì)造成內(nèi)存空間的浪費(fèi)。
為解決此問(wèn)題,出現(xiàn)了一種被稱(chēng)為「動(dòng)態(tài)數(shù)組 dynamic array」的數(shù)據(jù)結(jié)構(gòu),即長(zhǎng)度可變的數(shù)組,也常被稱(chēng)為「列表 list」。列表基于數(shù)組實(shí)現(xiàn),繼承了數(shù)組的優(yōu)點(diǎn),并且可以在程序運(yùn)行過(guò)程中動(dòng)態(tài)擴(kuò)容。我們可以在列表中自由地添加元素,而無(wú)須擔(dān)心超過(guò)容量限制。
我們通常使用“無(wú)初始值”和“有初始值”這兩種初始化方法。
list.cpp
/* 初始化列表 */
// 需注意,C++ 中 vector 即是本文描述的 list
// 無(wú)初始值
vector<int> list1;
// 有初始值
vector<int> list = { 1, 3, 2, 5, 4 };
列表本質(zhì)上是數(shù)組,因此可以在 O(1) 時(shí)間內(nèi)訪問(wèn)和更新元素,效率很高。
list.cpp
/* 訪問(wèn)元素 */
int num = list[1]; // 訪問(wèn)索引 1 處的元素
/* 更新元素 */
list[1] = 0; // 將索引 1 處的元素更新為 0
相較于數(shù)組,列表可以自由地添加與刪除元素。在列表尾部添加元素的時(shí)間復(fù)雜度為
list.cpp
/* 清空列表 */
list.clear();
/* 尾部添加元素 */
list.push_back(1);
list.push_back(3);
list.push_back(2);
list.push_back(5);
list.push_back(4);
/* 中間插入元素 */
list.insert(list.begin() + 3, 6); // 在索引 3 處插入數(shù)字 6
/* 刪除元素 */
list.erase(list.begin() + 3); // 刪除索引 3 處的元素
與數(shù)組一樣,列表可以根據(jù)索引遍歷,也可以直接遍歷各元素。
list.cpp
/* 通過(guò)索引遍歷列表 */
int count = 0;
for (int i = 0; i < list.size(); i++) {
count++;
}
/* 直接遍歷列表元素 */
count = 0;
for (int n : list) {
count++;
}
給定一個(gè)新列表 list1 ,我們可以將該列表拼接到原列表的尾部。
list.cpp
/* 拼接兩個(gè)列表 */
vector<int> list1 = { 6, 8, 7, 10, 9 };
// 將列表 list1 拼接到 list 之后
list.insert(list.end(), list1.begin(), list1.end());
完成列表排序后,我們便可以使用在數(shù)組類(lèi)算法題中經(jīng)??疾斓摹岸植檎摇焙汀半p指針”算法。
list.cpp
/* 排序列表 */
sort(list.begin(), list.end()); // 排序后,列表元素從小到大排列
許多編程語(yǔ)言都提供內(nèi)置的列表,例如 Java、C++、Python 等。它們的實(shí)現(xiàn)比較復(fù)雜,各個(gè)參數(shù)的設(shè)定也非常有考究,例如初始容量、擴(kuò)容倍數(shù)等。感興趣的讀者可以查閱源碼進(jìn)行學(xué)習(xí)。
為了加深對(duì)列表工作原理的理解,我們嘗試實(shí)現(xiàn)一個(gè)簡(jiǎn)易版列表,包括以下三個(gè)重點(diǎn)設(shè)計(jì)。
/* 列表類(lèi)簡(jiǎn)易實(shí)現(xiàn) */
class MyList {
private:
int *nums; // 數(shù)組(存儲(chǔ)列表元素)
int numsCapacity = 10; // 列表容量
int numsSize = 0; // 列表長(zhǎng)度(即當(dāng)前元素?cái)?shù)量)
int extendRatio = 2; // 每次列表擴(kuò)容的倍數(shù)
public:
/* 構(gòu)造方法 */
MyList() {
nums = new int[numsCapacity];
}
/* 析構(gòu)方法 */
~MyList() {
delete[] nums;
}
/* 獲取列表長(zhǎng)度(即當(dāng)前元素?cái)?shù)量)*/
int size() {
return numsSize;
}
/* 獲取列表容量 */
int capacity() {
return numsCapacity;
}
/* 訪問(wèn)元素 */
int get(int index) {
// 索引如果越界則拋出異常,下同
if (index < 0 || index >= size())
throw out_of_range("索引越界");
return nums[index];
}
/* 更新元素 */
void set(int index, int num) {
if (index < 0 || index >= size())
throw out_of_range("索引越界");
nums[index] = num;
}
/* 尾部添加元素 */
void add(int num) {
// 元素?cái)?shù)量超出容量時(shí),觸發(fā)擴(kuò)容機(jī)制
if (size() == capacity())
extendCapacity();
nums[size()] = num;
// 更新元素?cái)?shù)量
numsSize++;
}
/* 中間插入元素 */
void insert(int index, int num) {
if (index < 0 || index >= size())
throw out_of_range("索引越界");
// 元素?cái)?shù)量超出容量時(shí),觸發(fā)擴(kuò)容機(jī)制
if (size() == capacity())
extendCapacity();
// 將索引 index 以及之后的元素都向后移動(dòng)一位
for (int j = size() - 1; j >= index; j--) {
nums[j + 1] = nums[j];
}
nums[index] = num;
// 更新元素?cái)?shù)量
numsSize++;
}
/* 刪除元素 */
int remove(int index) {
if (index < 0 || index >= size())
throw out_of_range("索引越界");
int num = nums[index];
// 索引 i 之后的元素都向前移動(dòng)一位
for (int j = index; j < size() - 1; j++) {
nums[j] = nums[j + 1];
}
// 更新元素?cái)?shù)量
numsSize--;
// 返回被刪除元素
return num;
}
/* 列表擴(kuò)容 */
void extendCapacity() {
// 新建一個(gè)長(zhǎng)度為原數(shù)組 extendRatio 倍的新數(shù)組
int newCapacity = capacity() * extendRatio;
int *tmp = nums;
nums = new int[newCapacity];
// 將原數(shù)組中的所有元素復(fù)制到新數(shù)組
for (int i = 0; i < size(); i++) {
nums[i] = tmp[i];
}
// 釋放內(nèi)存
delete[] tmp;
numsCapacity = newCapacity;
}
/* 將列表轉(zhuǎn)換為 Vector 用于打印 */
vector<int> toVector() {
// 僅轉(zhuǎn)換有效長(zhǎng)度范圍內(nèi)的列表元素
vector<int> vec(size());
for (int i = 0; i < size(); i++) {
vec[i] = nums[i];
}
return vec;
}
};
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話(huà):173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: