JS資料結構和演算法 --- 連結串列
概念:性質類似於陣列,是計算機的一種儲存結構。連結串列由一系列結點組成,每個結點裡包含了本結點的資料域和指向下一個結點的指標(裡面儲存著下一個結點)。
作用:按一定順序儲存資料,允許在任意位置插入和刪除結點。
分類:雙向連結串列、迴圈連結串列
應用場景:對線性表的長度或者規模難以估計;頻繁做插入和刪除操作;構建動態性比較強的線性表。
操作方法:
1、append(element) 尾部插入元素
1)連結串列為空時,即插入的元素作為連結串列頭(直接賦值)
2)連結串列不為空時,從連結串列頭開始查詢,若當前查詢項的指標不為null,繼續查詢下一項;直到當前查詢項的指標等於null(最後一項),把新元素賦值當前項的指標(尾部插入)
2、insert(position,element) 向連結串列插入元素
1)頭部插入(下標等於0),即插入的元素作為連結串列頭
2)非頭部插入,從頭部開始查詢,當前查詢項的下標不等於position時,繼續向後查詢,直到查詢項下標等於position,使當前查詢的前一項的指標指向插入項,插入項的指標指向當前項,完成插入。
3、removeAt(position) 根據下標移除元素
1)移除第1項(下標等於0),即使原連結串列頭的指標作為新連結串列頭
2)移除非第一項(下標大於0),即跳過當前結點,使前一個結點的指標 指向 當前節點的指標
4、indexOf(element) 查詢某元素的下標
1)從頭部開始查詢,如果當前查詢項等於目標項就返回對應的下標,否則繼續往後查詢;
2)若連結串列迴圈結束了還沒找到,則返回-1(不存在)
5、remove(element) 直接移除某項元素(程式碼複用)
1)呼叫indexOf(element)方法找到目標項的下標;
2)呼叫removeAt(position)方法根據目標項的下標移除目標項
6、isEmpty() 判斷連結串列是否為空
7、size() 查詢連結串列的大小
例項:js實現各操作方法的詳解
/* 一個連結串列類 */
function LinkedList(element){
// 列表頭
let head = null;
// 連結串列長度
let length = 0;
// 輔助類:結點
function NodeItem(element){
this.element = element; // 資料域
this.next = null; // 指標
}
/*
append(element) 連結串列尾新增元素
1)連結串列為空時,即插入的元素作為連結串列頭(直接賦值)
2)連結串列不為空時,從連結串列頭開始查詢,若當前查詢項的指標不為null,繼續查詢下一項;直到當前查詢項的指標等於null(最後一項),把新增項賦值給當前項的指標(尾部插入)
*/
this.append = (element)=>{
let node = new NodeItem(element); // 呼叫輔助類建立一個新結點
// 連結串列為空
if(head == null){
head = node; // 把第一個新增的結點作為連結串列頭
}
// 已存在結點
else{
let current = head; // 定義一個current變數,儲存head連結串列頭的值,代表當前正在查詢的值(從頭部開始查詢)
while(current.next!==null){ // 當前查詢項的指標不為null(即不是最後一項),繼續往後找,直到next=null迴圈結束
current = current.next; // 把下一項賦值給當前查詢項,即查詢下一項(迴圈的經典方法)
}
// while迴圈結束後,current已經到了最後一項(current.next=null)
current.next = node; // 插入新元素
}
length++;
};
/*
insert(position,element) 向連結串列插入元素
1)頭部插入(下標等於0),即插入的元素作為連結串列頭
2)非頭部插入,從頭部開始查詢,當前查詢項的下標不等於position時,繼續向後查詢,直到查詢項下標等於position,使當前查詢的前一項的指標指向插入項,插入項的指標指向當前項,完成插入。
*/
this.insert = (position, element)=>{
let node = new NodeItem(element); // 呼叫輔助類建立一個新元素結點(即插入的元素)
// 越界
if(position>-1 && position<length){
// 連結串列頭插入
if(position==0){
let current = head; // 先把原表頭儲存在current變數裡
head = node; // 把插入項賦值給表頭(即插入連結串列頭)
head.next = current; // 使插入項的指標指向原表頭(連結起來)
}
// 非連結串列頭插入
else{
let index = 0; // 當前查詢項的下標
let previous = null; // 查詢項的前一項
let current = head; // 從連結串列頭開始查詢,先把它儲存在current變數裡
while(index < position){ // 查詢的當前項下標小於目標項下標時,繼續往後找
previous = current; // 當前項賦值給前一項
current = current.next; // 當前項的指標賦值給當前項,即查詢項往後移動一項
index++; // 下標加一
}
// 直到index=position時,即找到了目標項
previous.next = node; // 前一項的指標指向插入項
node.next = current; // 插入項的指標指向當前找到的目標項
// 完成上面兩步,即完成插入
}
length++;
}
};
/*
removeAt(position) 根據下標移除元素
1)移除第1項(下標等於0),即使原連結串列頭(第一項)的指標作為新連結串列的表頭
2)移除非第一項(下標大於0),即跳過當前結點,使前一個結點的指標 指向 當前節點的指標
*/
this.removeAt = (position)=>{
if(position>-1 && position<length){
let current = head;
// 移除第一項
if(position==0){
head = current.next; // 使原表頭的指標變成新表頭,到達移除原表頭的目的
}
// 移除非第一項
else{
let index = 0; // 當前項的下標
let previous = null; // 當前查詢項的前一個結點
// let current = head; // 從頭部開始查詢
while(index<position){ // 當前結點的下標小於指定結點下標時,往後移動一項,繼續查詢
previous = current; // 往後移動一項的方法就是,把後一項賦值給前一項
current = current.next;
index++;
}
// 當index = position 時跳出迴圈,即找到了要移除的那一項
previous.next = current.next; // 跳過當前項,使前一項的指標指向當前項的指標
}
length--; //長度減1
return current;
}
};
/*
indexOf(element) 查詢某元素的下標
1)從頭部開始查詢,如果當前查詢項等於目標項就返回對應的下標,否則繼續往後查詢;
2)若連結串列迴圈結束了還沒找到,則返回-1(不存在)
*/
this.indexOf = (element)=>{
let index = 0; // 下標
let current = head; // 從頭部開始查詢
while(current !== null){ // 當前項不等於null,表示還不是最後一項,繼續迴圈
if(element === current.element){ // 當前項的值等於目標項
return index; // 返回對應下標
}
current = current.next; // 否則繼續往後查詢
index++; // 下標加一
}
return -1; // 若迴圈結束還沒找到,返回-1,連結串列裡不存在該元素
};
/*
remove(element) 直接移除某項元素(程式碼複用)
1)呼叫indexOf(element)方法找到目標項的下標;
2)呼叫removeAt(position)方法根據目標項的下標移除目標項
*/
this.remove = (element)=>{
return this.removeAt(this.indexOf(element));
};
/* isEmpty() 判斷連結串列是否為空 */
this.isEmpty = ()=>{
return length == 0;
};
/* size() 查詢連結串列的大小 */
this.size = ()=>{
return length;
};
/* 檢視連結串列 */
this.getHead = ()=>{
return head;
};
}
(完)