【從蛋殼到滿天飛】JS 數據結構解析和算法實現,所有文章大概的內容以下: Arrays(數組)、Stacks(棧)、Queues(隊列)、LinkedList(鏈表)、Recursion(遞歸思想)、BinarySearchTree(二分搜索樹)、Set(集合)、Map(映射)、Heap(堆)、PriorityQueue(優先隊列)、SegmentTree(線段樹)、Trie(字典樹)、UnionFind(並查集)、AVLTree(AVL 平衡樹)、RedBlackTree(紅黑平衡樹)、HashTable(哈希表)html
源代碼有三個:ES6(單個單個的 class 類型的 js 文件) | JS + HTML(一個 js 配合一個 html)| JAVA (一個一個的工程)git
所有源代碼已上傳 github,點擊我吧,光看文章可以掌握兩成,動手敲代碼、動腦思考、畫圖才能夠掌握八成。github
本文章適合 對數據結構想了解而且感興趣的人羣,文章風格一如既往如此,就以爲手機上看起來比較方便,這樣顯得比較有條理,整理這些筆記加源碼,時間跨度也算將近半年時間了,但願對想學習數據結構的人或者正在學習數據結構的人羣有幫助。算法
把數據碼成一排進行存放數組
數組名[索引]
來訪問數組中的元素。js 中的數組是有侷限性的。數據結構
'use strict';
// 輸出
console.log('Array');
// 定義數組
let arr = new Array(10);
for (var i = 0; i < arr.length; i++) {
arr[i] = i;
}
// 定義數組
let scores = new Array(100, 99, 98);
// 遍歷輸出
for (var i = 0; i < scores.length; i++) {
console.log(scores[i]);
}
// 修改數組中某個元素
scores[1] = 60;
// foreach 遍歷數組
for (let index in scores) {
console.log(scores[index]);
}
複製代碼
scores[2]
表明一個班級中第三個學生。scores[2]
arr[110103198512112312]
,將本來 js 中的數組封裝到一個類中,ide
數據結構的本質也是存儲數據,函數
針對不一樣的數據結構,性能
數組自己是靜態的,必須在建立的時候指定他的大小,學習
代碼示例(class: MyArray)
class MyArray {
// 構造函數,傳入數組的容量capacity構造Array 默認數組的容量capacity=10
constructor(capacity = 10) {
this.data = new Array(10);
this.size = 0;
}
// 獲取數組中的元素實際個數
getSize() {
return this.size;
}
// 獲取數組的容量
getCapacity() {
return this.data.length;
}
// 判斷數組是否爲空
isEmpty() {
return this.size === 0;
}
}
複製代碼
(class: MyArray)
class MyArray {
// 構造函數,傳入數組的容量capacity構造Array 默認數組的容量capacity=10
constructor(capacity = 10) {
this.data = new Array(10);
this.size = 0;
}
// 獲取數組中的元素實際個數
getSize() {
return this.size;
}
// 獲取數組的容量
getCapacity() {
return this.data.length;
}
// 判斷數組是否爲空
isEmpty() {
return this.size === 0;
}
// 在指定索引處插入元素
insert(index, element) {
// 先判斷數組是否已滿
if (this.size == this.getCapacity()) {
throw new Error('add error. Array is full.');
}
// 而後判斷索引是否符合要求
if (index < 0 || index > size) {
throw new Error('insert error. require index < 0 or index > size');
}
// 最後 將指定索引處騰出來
// 從指定索引處開始,全部數組元素所有日後移動一位
// 從後往前移動
for (let i = size - 1; i >= index; i--) {
this.data[i + 1] = this.data[i];
}
// 在指定索引處插入元素
this.data[index] = element;
// 維護一下size
size++;
}
// 擴展 在數組最前面插入一個元素
unshift(element) {
insert(0, element);
}
// 擴展 在數組最後面插入一個元素
push(element) {
insert(size, element);
}
// 其實在數組中添加元素 就至關於在數組最後面插入一個元素
add(element) {
if (this.size == getCapacity()) {
throw new Error('add error. Array is full.');
}
// size其實指向的是 當前數組最後一個元素的 後一個位置的索引。
this.data[size] = element;
// 維護size
size++;
}
}
複製代碼
// @Override: 方法名 日期-開發人員
(class: MyArray, class: Main)
MyArray
class MyArray {
// 構造函數,傳入數組的容量capacity構造Array 默認數組的容量capacity=10
constructor(capacity = 10) {
this.data = new Array(capacity);
this.size = 0;
}
// 獲取數組中的元素實際個數
getSize() {
return this.size;
}
// 獲取數組的容量
getCapacity() {
return this.data.length;
}
// 判斷數組是否爲空
isEmpty() {
return this.size === 0;
}
// 在指定索引處插入元素
insert(index, element) {
// 先判斷數組是否已滿
if (this.size == this.getCapacity()) {
throw new Error('add error. Array is full.');
}
// 而後判斷索引是否符合要求
if (index < 0 || index > this.size) {
throw new Error('insert error. require index < 0 or index > size');
}
// 最後 將指定索引處騰出來
// 從指定索引處開始,全部數組元素所有日後移動一位
// 從後往前移動
for (let i = this.size - 1; i >= index; i--) {
this.data[i + 1] = this.data[i];
}
// 在指定索引處插入元素
this.data[index] = element;
// 維護一下size
this.size++;
}
// 擴展 在數組最前面插入一個元素
unshift(element) {
this.insert(0, element);
}
// 擴展 在數組最後面插入一個元素
push(element) {
this.insert(this.size, element);
}
// 其實在數組中添加元素 就至關於在數組最後面插入一個元素
add(element) {
if (this.size == this.getCapacity()) {
throw new Error('add error. Array is full.');
}
// size其實指向的是 當前數組最後一個元素的 後一個位置的索引。
this.data[this.size] = element;
// 維護size
this.size++;
}
// get
get(index) {
// 不能訪問沒有存放元素的位置
if (index < 0 || index >= this.size) {
throw new Error('get error. index < 0 or index >= size');
}
return this.data[index];
}
// set
set(index, newElement) {
// 不能修改沒有存放元素的位置
if (index < 0 || index >= this.size) {
throw new Error('set error. index < 0 or index >= size');
}
this.data[index] = newElement;
}
// @Override toString 2018-10-17-jwl
toString() {
let arrInfo = `Array: size = ${this.getSize()},capacity = ${this.getCapacity()},\n`;
arrInfo += `data = [`;
for (var i = 0; i < this.size - 1; i++) {
arrInfo += `${this.data[i]}, `;
}
arrInfo += `${this.data[this.size - 1]}`;
arrInfo += `]`;
// 在頁面上展現
document.body.innerHTML += `${arrInfo}<br /><br /> `;
return arrInfo;
}
}
複製代碼
Main
class Main {
constructor() {
let ma = new MyArray(20);
for (let i = 1; i <= 10; i++) {
ma.add(i);
}
console.log(ma.toString());
ma.insert(1, 200);
console.log(ma.toString());
ma.unshift(-1);
console.log(ma.toString());
ma.push(9999);
console.log(ma.toString());
ma.set(5, 8888);
console.log(ma.get(5));
this.show(ma.get(5));
}
// 將內容顯示在頁面上
show(content) {
document.body.innerHTML += `${content}<br /><br />`;
}
}
window.onload = function() {
// 執行主函數
new Main();
};
複製代碼
(class: MyArray, class: Main)
MyArray
class MyArray {
// 構造函數,傳入數組的容量capacity構造Array 默認數組的容量capacity=10
constructor(capacity = 10) {
this.data = new Array(capacity);
this.size = 0;
}
// 獲取數組中的元素實際個數
getSize() {
return this.size;
}
// 獲取數組的容量
getCapacity() {
return this.data.length;
}
// 判斷數組是否爲空
isEmpty() {
return this.size === 0;
}
// 在指定索引處插入元素
insert(index, element) {
// 先判斷數組是否已滿
if (this.size == this.getCapacity()) {
throw new Error('add error. Array is full.');
}
// 而後判斷索引是否符合要求
if (index < 0 || index > this.size) {
throw new Error(
'insert error. require index < 0 or index > size.'
);
}
// 最後 將指定索引處騰出來
// 從指定索引處開始,全部數組元素所有日後移動一位
// 從後往前移動
for (let i = this.size - 1; i >= index; i--) {
this.data[i + 1] = this.data[i];
}
// 在指定索引處插入元素
this.data[index] = element;
// 維護一下size
this.size++;
}
// 擴展 在數組最前面插入一個元素
unshift(element) {
this.insert(0, element);
}
// 擴展 在數組最後面插入一個元素
push(element) {
this.insert(this.size, element);
}
// 其實在數組中添加元素 就至關於在數組最後面插入一個元素
add(element) {
if (this.size == this.getCapacity()) {
throw new Error('add error. Array is full.');
}
// size其實指向的是 當前數組最後一個元素的 後一個位置的索引。
this.data[this.size] = element;
// 維護size
this.size++;
}
// get
get(index) {
// 不能訪問沒有存放元素的位置
if (index < 0 || index >= this.size) {
throw new Error('get error. index < 0 or index >= size.');
}
return this.data[index];
}
// set
set(index, newElement) {
// 不能修改沒有存放元素的位置
if (index < 0 || index >= this.size) {
throw new Error('set error. index < 0 or index >= size.');
}
this.data[index] = newElement;
}
// contain
contain(element) {
for (var i = 0; i < this.size; i++) {
if (this.data[i] === element) {
return true;
}
}
return false;
}
// find
find(element) {
for (var i = 0; i < this.size; i++) {
if (this.data[i] === element) {
return i;
}
}
return -1;
}
// findAll
findAll(element) {
// 建立一個自定義數組來存取這些 元素的索引
let myarray = new MyArray(this.size);
for (var i = 0; i < this.size; i++) {
if (this.data[i] === element) {
myarray.push(i);
}
}
// 返回這個自定義數組
return myarray;
}
// 刪除指定索引處的元素
remove(index) {
// 索引合法性驗證
if (index < 0 || index >= this.size) {
throw new Error('remove error. index < 0 or index >= size.');
}
// 暫存即將要被刪除的元素
let element = this.data[index];
// 後面的元素覆蓋前面的元素
for (let i = index; i < this.size - 1; i++) {
this.data[i] = this.data[i + 1];
}
this.data[this.size - 1] = undefined;
this.size--;
return element;
}
// 擴展:刪除數組中第一個元素
shift() {
return this.remove(0);
}
// 擴展: 刪除數組中最後一個元素
pop() {
return this.remove(this.size - 1);
}
// 擴展: 根據元素來進行刪除
removeElement(element) {
let index = this.find(element);
if (index !== -1) {
this.remove(index);
}
}
// 擴展: 根據元素來刪除全部元素
removeAllElement(element) {
let index = this.find(element);
while (index != -1) {
this.remove(index);
index = this.find(element);
}
// let indexArray = this.findAll(element);
// let cur, index = 0;
// for (var i = 0; i < indexArray.getSize(); i++) {
// // 每刪除一個元素 原數組中就少一個元素,
// // 索引數組中的索引值是按照大小順序排列的,
// // 因此 這個cur記錄的是 原數組元素索引的偏移量
// // 只有這樣纔可以正確的刪除元素。
// index = indexArray.get(i) - cur++;
// this.remove(index);
// }
}
// @Override toString 2018-10-17-jwl
toString() {
let arrInfo = `Array: size = ${this.getSize()},capacity = ${this.getCapacity()},\n`;
arrInfo += `data = [`;
for (var i = 0; i < this.size - 1; i++) {
arrInfo += `${this.data[i]}, `;
}
arrInfo += `${this.data[this.size - 1]}`;
arrInfo += `]`;
// 在頁面上展現
document.body.innerHTML += `${arrInfo}<br /><br /> `;
return arrInfo;
}
}
複製代碼
Main
class Main {
constructor() {
let ma = new MyArray(20);
for (let i = 1; i <= 10; i++) {
ma.add(i);
}
/* * Array: size = 10,capacity = 20 * [1,2,3,4,5,6,7,8,9,10] */
console.log(ma.toString());
/* * Array: size = 11,capacity = 20 * [1,200,2,3,4,5,6,7,8,9,10] */
ma.insert(1, 200);
console.log(ma.toString());
/* * Array: size = 12,capacity = 20 * [-1,1,200,2,3,4,5,6,7,8,9,10] */
ma.unshift(-1);
console.log(ma.toString());
/* * Array: size = 13,capacity = 20 * [-1,1,200,2,3,4,5,6,7,8,9,10,9999] */
ma.push(9999);
console.log(ma.toString());
/* * 8888 */
ma.set(5, 8888);
console.log(ma.get(5));
this.show(ma.get(5));
/* * Array: size = 13,capacity = 20 * [-1,1,200,2,3,8888,5,6,7,8,9,10,9999] * true * 6 */
console.log(ma.toString());
this.show(ma.contain(5));
this.show(ma.find(5));
/* * Array: size = 12,capacity = 20 * [-1,1,200,2,3,8888,6,7,8,9,10,9999] */
ma.remove(ma.find(5));
console.log(ma.toString());
/* * -1 * 9999 * Array: size = 10,capacity = 20 * [1,200,2,3,8888,6,7,8,9,10] */
this.show(ma.shift());
this.show(ma.pop());
console.log(ma.toString());
/* * Array: size = 9,capacity = 20 * [1,200,2,3,6,7,8,9,10] */
ma.removeElement(8888);
console.log(ma.toString());
/* * Array: size = 3,capacity = 20 * [9,10,11] * Array: size = 12,capacity = 20 * [1,200,2,3,6,7,8,9,10,123456,123456,123456] */
ma.add(123456);
ma.add(123456);
ma.add(123456);
this.show(ma.findAll(123456));
console.log(ma.toString());
/* * Array: size = 9,capacity = 20 * [1,200,2,3,6,7,8,9,10] */
ma.removeAllElement(123456);
console.log(ma.toString());
}
// 將內容顯示在頁面上
show(content) {
document.body.innerHTML += `${content}<br /><br />`;
}
}
window.onload = function() {
// 執行主函數
new Main();
};
複製代碼
size == capcity
時建立新數組,容量翻倍,size == capcity / 2
時建立新數組,容量縮小一倍,(class: MyArray, class: Main)
Myarray
class MyArray {
// 構造函數,傳入數組的容量capacity構造Array 默認數組的容量capacity=10
constructor(capacity = 10) {
this.data = new Array(capacity);
this.size = 0;
}
// 獲取數組中的元素實際個數
getSize() {
return this.size;
}
// 獲取數組的容量
getCapacity() {
return this.data.length;
}
// 判斷數組是否爲空
isEmpty() {
return this.size === 0;
}
// 給數組擴容
resize(capacity) {
let newArray = new Array(capacity);
for (var i = 0; i < this.size; i++) {
newArray[i] = this.data[i];
}
// let index = this.size - 1;
// while (index > -1) {
// newArray[index] = this.data[index];
// index --;
// }
this.data = newArray;
}
// 在指定索引處插入元素
insert(index, element) {
// 先判斷數組是否已滿
if (this.size == this.getCapacity()) {
// throw new Error("add error. Array is full.");
this.resize(this.size * 2);
}
// 而後判斷索引是否符合要求
if (index < 0 || index > this.size) {
throw new Error(
'insert error. require index < 0 or index > size.'
);
}
// 最後 將指定索引處騰出來
// 從指定索引處開始,全部數組元素所有日後移動一位
// 從後往前移動
for (let i = this.size - 1; i >= index; i--) {
this.data[i + 1] = this.data[i];
}
// 在指定索引處插入元素
this.data[index] = element;
// 維護一下size
this.size++;
}
// 擴展 在數組最前面插入一個元素
unshift(element) {
this.insert(0, element);
}
// 擴展 在數組最後面插入一個元素
push(element) {
this.insert(this.size, element);
}
// 其實在數組中添加元素 就至關於在數組最後面插入一個元素
add(element) {
if (this.size == this.getCapacity()) {
// throw new Error("add error. Array is full.");
this.resize(this.size * 2);
}
// size其實指向的是 當前數組最後一個元素的 後一個位置的索引。
this.data[this.size] = element;
// 維護size
this.size++;
}
// get
get(index) {
// 不能訪問沒有存放元素的位置
if (index < 0 || index >= this.size) {
throw new Error('get error. index < 0 or index >= size.');
}
return this.data[index];
}
// set
set(index, newElement) {
// 不能修改沒有存放元素的位置
if (index < 0 || index >= this.size) {
throw new Error('set error. index < 0 or index >= size.');
}
this.data[index] = newElement;
}
// contain
contain(element) {
for (var i = 0; i < this.size; i++) {
if (this.data[i] === element) {
return true;
}
}
return false;
}
// find
find(element) {
for (var i = 0; i < this.size; i++) {
if (this.data[i] === element) {
return i;
}
}
return -1;
}
// findAll
findAll(element) {
// 建立一個自定義數組來存取這些 元素的索引
let myarray = new MyArray(this.size);
for (var i = 0; i < this.size; i++) {
if (this.data[i] === element) {
myarray.push(i);
}
}
// 返回這個自定義數組
return myarray;
}
// 刪除指定索引處的元素
remove(index) {
// 索引合法性驗證
if (index < 0 || index >= this.size) {
throw new Error('remove error. index < 0 or index >= size.');
}
// 暫存即將要被刪除的元素
let element = this.data[index];
// 後面的元素覆蓋前面的元素
for (let i = index; i < this.size - 1; i++) {
this.data[i] = this.data[i + 1];
}
this.size--;
this.data[this.size] = null;
// 若是size 爲容量的一半時 就能夠縮容了
// 防止 size 爲 0 時 data.length 爲1 那麼縮容時也爲 0
if (
Math.floor(this.getCapacity() / 2) === this.size &&
Math.floor(this.getCapacity() / 2) !== 0
) {
// 縮容一半
this.resize(Math.floor(this.getCapacity() / 2));
}
return element;
}
// 擴展:刪除數組中第一個元素
shift() {
return this.remove(0);
}
// 擴展: 刪除數組中最後一個元素
pop() {
return this.remove(this.size - 1);
}
// 擴展: 根據元素來進行刪除
removeElement(element) {
let index = this.find(element);
if (index !== -1) {
this.remove(index);
}
}
// 擴展: 根據元素來刪除全部元素
removeAllElement(element) {
let index = this.find(element);
while (index != -1) {
this.remove(index);
index = this.find(element);
}
// let indexArray = this.findAll(element);
// let cur, index = 0;
// for (var i = 0; i < indexArray.getSize(); i++) {
// // 每刪除一個元素 原數組中就少一個元素,
// // 索引數組中的索引值是按照大小順序排列的,
// // 因此 這個cur記錄的是 原數組元素索引的偏移量
// // 只有這樣纔可以正確的刪除元素。
// index = indexArray.get(i) - cur++;
// this.remove(index);
// }
}
// @Override toString 2018-10-17-jwl
toString() {
let arrInfo = `Array: size = ${this.getSize()},capacity = ${this.getCapacity()},\n`;
arrInfo += `data = [`;
for (var i = 0; i < this.size - 1; i++) {
arrInfo += `${this.data[i]}, `;
}
if (!this.isEmpty()) {
arrInfo += `${this.data[this.size - 1]}`;
}
arrInfo += `]`;
// 在頁面上展現
document.body.innerHTML += `${arrInfo}<br /><br /> `;
return arrInfo;
}
}
複製代碼
Main
class Main {
constructor() {
this.alterLine('MyArray Area');
let ma = new MyArray();
for (let i = 1; i <= 10; i++) {
ma.add(i);
}
/* * Array: size = 10,capacity = 20 * [1,2,3,4,5,6,7,8,9,10] */
console.log(ma.toString());
/* * Array: size = 11,capacity = 20 * [1,2,3,4,5,6,7,8,99999,9,10] */
ma.insert(8, 9999);
console.log(ma.toString());
/* * Array: size = 10,capacity = 20 * [1,2,3,4,5,6,7,8,9,10] */
ma.remove(8);
console.log(ma.toString());
/* * Array: size = 11,capacity = 20 * [1,2,3,4,5,6,7,8,9,10,9999] */
ma.push(9999);
console.log(ma.toString());
}
// 將內容顯示在頁面上
show(content) {
document.body.innerHTML += `${content}<br /><br />`;
}
// 展現分割線
alterLine(title) {
let line = `--------------------${title}----------------------`;
console.log(line);
document.body.innerHTML += `${line}<br /><br />`;
}
}
window.onload = function() {
// 執行主函數
new Main();
};
複製代碼
O(1)、O(n)、O(lgn)、O(nlogn)、O(n^2)
等等O(n)
,O(n)
。O(n)
?
T = c1*n + c2
,function calcSum(nums) {
let sum = 0;
for (let num of nums) {
sum += num;
}
return sum;
}
複製代碼
T = 2*n + 2
、算法二:T = 2000*n + 10000
,O(n)
,T = 1*n*n + 0
O(n^2)
級別的一個算法,O(n^2)
要比O(n)
性能差不少,由於前者是 N 的平方級別的,漸進的時間複雜度
O(n^2)
要比O(n)
的執行時間差的愈來愈大,O(n^2)
要比O(n)
快。T = 2*n*n + 300n + 10
,O(n^2)
,T = 2*n*n + 300n + 10
的時間複雜度仍是O(n^2)
。O(1)
,O(n)
。push(e)
:向數組末尾添加一個元素
data[size]
賦值,O(1)
O(1)
的時間複雜度表示這個操做所消耗的時間O(n)
(操做 n 個元素),O(1)
(操做 1 個元素)。unshift(e)
:向數組頭部添加一個元素
O(n)
(操做 n 個元素),O(1)
(操做 1 個元素)的操做 ,O(n)
狀況時,O(1)
會被忽略掉。insert(index, e)
:在 index 索引這個位置插入一個元素
unshift(e)
同樣要向後移動 n 個元素,push(e)
同樣data[size]
賦值,O(n/2)
,O(n)
O(1)
,O(n)
,O(n/2)
。O(n)
級別的算法
push(e)
:O(1)
,unshift(e)
:O(n)
,insert(index, e)
:O(n/2)=O(n)
。O(n)
,removeLast()
:在數組末尾刪除一個元素
size--
,O(1)
O(1)
的時間複雜度表示這個操做所消耗的時間removeFirst()
:在數組頭部刪除一個元素
O(n)
(操做 n 個元素),O(1)
(操做 1 個元素)的操做 ,size--
,O(n)
狀況時,O(1)
會被忽略掉。remove(index)
:刪除指定索引位置處的元素並返回
O(1)
,O(n)
,O(n/2)
,O(n)
。O(n)
級別的算法
removeLast()
:O(1)
,removeFirst()
:O(n)
,remove(index)
:O(n/2)=O(n)
。O(n)
,set(index, e)
:指定索引修改一個元素的值
O(1)
。get(index)
:指定索引查找一個元素的值
O(1)
。contains(e)
:指定元素來查找,判斷元素是否存在
O(n)
。O(1)
,第一個,O(n)
,最後一個或者沒找到,O(n/2)
,在中間,O(n)
,find(e)
:指定元素來查找,返回該元素對應的索引
O(n)
。O(1)
,第一個,O(n)
,最後一個或者沒找到,O(n/2)
,在中間,O(n)
,removeElement(e)
:根據指定元素來進行刪除第一相同的元素
O(n^2)
。removeAll(e)
::根據指定元素來進行刪除全部相同的元素
removeElement(e)
,因而有三輪循環了,O(n^3)
。findAll(e)
:根據指定元素來進行查找,找到全部的元素
O(n)
。O(n)
級別的,O(1)
級別的,O(1)
。O(1)
的,O(n)
級別的,O(1)
級別的。O(n)
的時間,O(n)
的時間,O(n)
的時間,O(n)
的複雜度
O(1)
的級別,O(n)
的級別,size == capcity / 4
時,纔將 capacity 減半,size == capcity / 2
時,纔將 capacity 減半,data.length / 2 爲 0
,那樣縮容的容量就爲 0 了,(class: MyArray, class: Main)
Myarray
class MyArray {
// 構造函數,傳入數組的容量capacity構造Array 默認數組的容量capacity=10
constructor(capacity = 10) {
this.data = new Array(capacity);
this.size = 0;
}
// 獲取數組中的元素實際個數
getSize() {
return this.size;
}
// 獲取數組的容量
getCapacity() {
return this.data.length;
}
// 判斷數組是否爲空
isEmpty() {
return this.size === 0;
}
// 給數組擴容
resize(capacity) {
let newArray = new Array(capacity);
for (var i = 0; i < this.size; i++) {
newArray[i] = this.data[i];
}
// let index = this.size - 1;
// while (index > -1) {
// newArray[index] = this.data[index];
// index --;
// }
this.data = newArray;
}
// 在指定索引處插入元素
insert(index, element) {
// 先判斷數組是否已滿
if (this.size == this.getCapacity()) {
// throw new Error("add error. Array is full.");
this.resize(this.size * 2);
}
// 而後判斷索引是否符合要求
if (index < 0 || index > this.size) {
throw new Error(
'insert error. require index < 0 or index > size.'
);
}
// 最後 將指定索引處騰出來
// 從指定索引處開始,全部數組元素所有日後移動一位
// 從後往前移動
for (let i = this.size - 1; i >= index; i--) {
this.data[i + 1] = this.data[i];
}
// 在指定索引處插入元素
this.data[index] = element;
// 維護一下size
this.size++;
}
// 擴展 在數組最前面插入一個元素
unshift(element) {
this.insert(0, element);
}
// 擴展 在數組最後面插入一個元素
push(element) {
this.insert(this.size, element);
}
// 其實在數組中添加元素 就至關於在數組最後面插入一個元素
add(element) {
if (this.size == this.getCapacity()) {
// throw new Error("add error. Array is full.");
this.resize(this.size * 2);
}
// size其實指向的是 當前數組最後一個元素的 後一個位置的索引。
this.data[this.size] = element;
// 維護size
this.size++;
}
// get
get(index) {
// 不能訪問沒有存放元素的位置
if (index < 0 || index >= this.size) {
throw new Error('get error. index < 0 or index >= size.');
}
return this.data[index];
}
// set
set(index, newElement) {
// 不能修改沒有存放元素的位置
if (index < 0 || index >= this.size) {
throw new Error('set error. index < 0 or index >= size.');
}
this.data[index] = newElement;
}
// contain
contain(element) {
for (var i = 0; i < this.size; i++) {
if (this.data[i] === element) {
return true;
}
}
return false;
}
// find
find(element) {
for (var i = 0; i < this.size; i++) {
if (this.data[i] === element) {
return i;
}
}
return -1;
}
// findAll
findAll(element) {
// 建立一個自定義數組來存取這些 元素的索引
let myarray = new MyArray(this.size);
for (var i = 0; i < this.size; i++) {
if (this.data[i] === element) {
myarray.push(i);
}
}
// 返回這個自定義數組
return myarray;
}
// 刪除指定索引處的元素
remove(index) {
// 索引合法性驗證
if (index < 0 || index >= this.size) {
throw new Error('remove error. index < 0 or index >= size.');
}
// 暫存即將要被刪除的元素
let element = this.data[index];
// 後面的元素覆蓋前面的元素
for (let i = index; i < this.size - 1; i++) {
this.data[i] = this.data[i + 1];
}
this.size--;
this.data[this.size] = null;
// 若是size 爲容量的一半時 就能夠縮容了
// 防止 size 爲 0 時 data.length 爲1 那麼縮容時也爲 0
if (
Math.floor(this.getCapacity() / 2) === this.size &&
Math.floor(this.getCapacity() / 2) !== 0
) {
// 縮容一半
this.resize(Math.floor(this.getCapacity() / 2));
}
return element;
}
// 擴展:刪除數組中第一個元素
shift() {
return this.remove(0);
}
// 擴展: 刪除數組中最後一個元素
pop() {
return this.remove(this.size - 1);
}
// 擴展: 根據元素來進行刪除
removeElement(element) {
let index = this.find(element);
if (index !== -1) {
this.remove(index);
}
}
// 擴展: 根據元素來刪除全部元素
removeAllElement(element) {
let index = this.find(element);
while (index != -1) {
this.remove(index);
index = this.find(element);
}
// let indexArray = this.findAll(element);
// let cur, index = 0;
// for (var i = 0; i < indexArray.getSize(); i++) {
// // 每刪除一個元素 原數組中就少一個元素,
// // 索引數組中的索引值是按照大小順序排列的,
// // 因此 這個cur記錄的是 原數組元素索引的偏移量
// // 只有這樣纔可以正確的刪除元素。
// index = indexArray.get(i) - cur++;
// this.remove(index);
// }
}
// @Override toString 2018-10-17-jwl
toString() {
let arrInfo = `Array: size = ${this.getSize()},capacity = ${this.getCapacity()},\n`;
arrInfo += `data = [`;
for (var i = 0; i < this.size - 1; i++) {
arrInfo += `${this.data[i]}, `;
}
if (!this.isEmpty()) {
arrInfo += `${this.data[this.size - 1]}`;
}
arrInfo += `]`;
// 在頁面上展現
document.body.innerHTML += `${arrInfo}<br /><br /> `;
return arrInfo;
}
}
複製代碼
Main
class Main {
constructor() {
this.alterLine('MyArray Area');
let ma = new MyArray();
for (let i = 1; i <= 10; i++) {
ma.add(i);
}
/* * Array: size = 10,capacity = 20 * [1,2,3,4,5,6,7,8,9,10] */
console.log(ma.toString());
/* * Array: size = 11,capacity = 20 * [1,2,3,4,5,6,7,8,99999,9,10] */
ma.insert(8, 9999);
console.log(ma.toString());
/* * Array: size = 10,capacity = 20 * [1,2,3,4,5,6,7,8,9,10] */
ma.remove(8);
console.log(ma.toString());
/* * Array: size = 11,capacity = 20 * [1,2,3,4,5,6,7,8,9,10,9999] */
ma.push(9999);
console.log(ma.toString());
for (let i = 1; i <= 11; i++) {
ma.remove(0);
}
/* * Array: size = 6,capacity = 10 * [1,7,8,9,10,9999] */
console.log(ma.toString());
}
// 將內容顯示在頁面上
show(content) {
document.body.innerHTML += `${content}<br /><br />`;
}
// 展現分割線
alterLine(title) {
let line = `--------------------${title}----------------------`;
console.log(line);
document.body.innerHTML += `${line}<br /><br />`;
}
}
window.onload = function() {
// 執行主函數
new Main();
};
複製代碼