Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
不管是在前端還是后端開發面試過程中,關于數據結構部分的問題是必不可少的,比如像鏈表,棧,隊列,圖等等。今天這篇文章,我們站在前端開發人員的角度,看看如何使用Javascript來實現數據結構中的鏈表結構。
今天這篇文章中的代碼已經放到Github上了,感興趣的可以自取,Github地址為:
https://github.com/zhouxiongking/article-pages/blob/master/articles/LinkedList/LinkedList.js
Javascript
鏈表和數組是數據結構中用于存儲多個元素,比較常用的數據結構。數組中的元素在內存中占用連續的內存空間,而在鏈表中各個元素不是占有連續的內存空間,元素之間通過引用關系連接。
通過下面這張圖可以很容易看清鏈表結構。
鏈表結構
相比于數組,鏈表在添加或移除元素時不會移動元素,只需要改變引用指向即可。但是如果想要訪問鏈表中的某個元素時,必須從表頭開始尋找,這是在使用上比數組劣勢的地方。
下面我們看看如何通過代碼來實現一個鏈表結構,由于我們會采用類的結構來組織代碼,因此采用ES6的語法來寫。
鏈表節點
首先我們需要如上圖所示的鏈表節點。
鏈表節點
追加元素
追加元素是在鏈表的末尾添加元素,動態的修改next引用的指向并修改鏈表的長度。
追加元素
任意位置插入元素
在任意位置插入元素時,我們需要建立一個臨時索引,從表頭開始往后迭代,直到臨時變量值等于插入位置,即改變插入點的next引用指向。
任意位置插入元素
移除指定位置元素
在移除指定位置元素時,首先需要檢查值是否越界,同樣需要建立一個臨時索引,從表頭向后迭代時,動態修改索引值,直到索引值與指定位置值相等,最后修改元素的next引用指向。
移除指定位置元素
尋找元素索引
在尋找元素索引時,建立一個臨時變量,從表頭開始向后遍歷,在遍歷過程中動態修改臨時變量值,直到找到需要的元素,返回這個臨時變量即可。
尋找元素索引
刪除指定元素
在刪除指定元素時,可以借助上述的尋找元素索引方法,先找到索引再通過移除指定位置元素的方法來刪除。
刪除指定元素
判空和鏈表長度
判斷鏈表是否為空以及獲取鏈表的長度,都只需要通過length屬性即可。
判空和鏈表長度
自定義輸出
打印鏈表時,我們可以自定義toString()方法,以我們想要的方式進行輸出。
自定義輸出
用Javascript編寫完鏈表結構后,我們通過以下的代碼進行測試。
測試代碼
我們可以得到以下結果。
測試結果
這也證明了我們實現鏈表結構的正確性。
今天這篇文章主要利用Javascript實現了數據結構中的鏈表,大家學會了嗎?
不管是在前端還是后端開發面試過程中,關于數據結構部分的問題是必不可少的,比如像鏈表,棧,隊列,圖等等。今天這篇文章,我們站在前端開發人員的角度,看看如何使用Javascript來實現數據結構中的鏈表結構。
今天這篇文章中的代碼已經放到Github上了,感興趣的可以自取,Github地址為:
https://github.com/zhouxiongking/article-pages/blob/master/articles/LinkedList/LinkedList.js
Javascript
鏈表和數組是數據結構中用于存儲多個元素,比較常用的數據結構。數組中的元素在內存中占用連續的內存空間,而在鏈表中各個元素不是占有連續的內存空間,元素之間通過引用關系連接。
通過下面這張圖可以很容易看清鏈表結構。
鏈表結構
相比于數組,鏈表在添加或移除元素時不會移動元素,只需要改變引用指向即可。但是如果想要訪問鏈表中的某個元素時,必須從表頭開始尋找,這是在使用上比數組劣勢的地方。
下面我們看看如何通過代碼來實現一個鏈表結構,由于我們會采用類的結構來組織代碼,因此采用ES6的語法來寫。
鏈表節點
首先我們需要如上圖所示的鏈表節點。
鏈表節點
追加元素
追加元素是在鏈表的末尾添加元素,動態的修改next引用的指向并修改鏈表的長度。
追加元素
任意位置插入元素
在任意位置插入元素時,我們需要建立一個臨時索引,從表頭開始往后迭代,直到臨時變量值等于插入位置,即改變插入點的next引用指向。
任意位置插入元素
移除指定位置元素
在移除指定位置元素時,首先需要檢查值是否越界,同樣需要建立一個臨時索引,從表頭向后迭代時,動態修改索引值,直到索引值與指定位置值相等,最后修改元素的next引用指向。
移除指定位置元素
尋找元素索引
在尋找元素索引時,建立一個臨時變量,從表頭開始向后遍歷,在遍歷過程中動態修改臨時變量值,直到找到需要的元素,返回這個臨時變量即可。
尋找元素索引
刪除指定元素
在刪除指定元素時,可以借助上述的尋找元素索引方法,先找到索引再通過移除指定位置元素的方法來刪除。
刪除指定元素
判空和鏈表長度
判斷鏈表是否為空以及獲取鏈表的長度,都只需要通過length屬性即可。
判空和鏈表長度
自定義輸出
打印鏈表時,我們可以自定義toString()方法,以我們想要的方式進行輸出。
自定義輸出
用Javascript編寫完鏈表結構后,我們通過以下的代碼進行測試。
測試代碼
我們可以得到以下結果。
測試結果
這也證明了我們實現鏈表結構的正確性。
今天這篇文章主要利用Javascript實現了數據結構中的鏈表,大家學會了嗎?
篇文章給大家帶來的內容是關于JavaScript中鏈表的詳細介紹,有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。
鏈表和數組
大家都用過js中的數組,數組其實是一種線性表的順序存儲結構,它的特點是用一組地址連續的存儲單元依次存儲數據元素。而它的缺點也正是其特點而造成,比如對數組做刪除或者插入的時候,可能需要移動大量的元素。
這里大致模擬一下數組的插入操作:
insert(arr, index, data){
for(let i=index + 1; i < arr.length; i++){
arr[i]=arr[i - 1];
}
arr[index]=data;
}
從上面的代碼可以看出數組的插入以及刪除都有可能會是一個O(n)的操作。從而就引出了鏈表這種數據結構,鏈表不要求邏輯上相鄰的元素在物理位置上也相鄰,因此它沒有順序存儲結構所具有的缺點,當然它也失去了數組在一塊連續空間內隨機存取的優點。
單向鏈表
單向鏈表的特點:
鏈表中的幾個主要操作
初始化節點
class Node {
constructor(key) {
this.next=null;
this.key=key;
}
}
初始化單向鏈表
class List {
constructor() {
this.head=null;
}
}
創建節點
static createNode(key) {
return new createNode(key);
}
這里說明一下,這一塊我是向外暴露了一個靜態方法來創建節點,而并非直接把它封裝進插入操作里去,因為我感覺這樣的邏輯會更加正確一些。 從創建一個鏈表 -> 創建一個節點 -> 將節點插入進鏈表中。可能你會遇到一些文章介紹的方式是直接將一個數據作為參數去調用insert操作,在insert內部做了一個創建節點。
插入節點(插入到頭節點之后)
插入操作只需要去調整節點的指針即可,兩種情況:
insert(node) {
// 如果head有指向的節點
if(this.head){
node.next=this.head;
}else {
node.next=null;
}
this.head=node;
}
搜索節點
find(key) {
let node=this.head;
while(node !==null && node.key !==key){
node=node.next;
}
return node;
}
刪除節點
這里分三種情況:
delete(node) {
// 第一種情況
if(node===this.head){
this.head=node.next;
return;
}
// 查找所要刪除節點的上一個節點
let prevNode=this.head;
while (prevNode.next !==node) {
prevNode=prevNode.next;
}
// 第二種情況
if(node.next===null) {
prevNode.next=null;
}
// 第三種情況
if(node.next) {
prevNode.next=node.next;
}
}
單向鏈表整體的代碼
class ListNode {
constructor(key) {
this.next=null;
this.key=key;
}
}
class List {
constructor() {
this.head=null;
this.length=0;
}
static createNode(key) {
return new ListNode(key);
}
// 往頭部插入數據
insert(node) {
// 如果head后面有指向的節點
if (this.head) {
node.next=this.head;
} else {
node.next=null;
}
this.head=node;
this.length++;
}
find(key) {
let node=this.head;
while (node !==null && node.key !==key) {
node=node.next;
}
return node;
}
delete(node) {
if (this.length===0) {
throw 'node is undefined';
}
if (node===this.head) {
this.head=node.next;
this.length--;
return;
}
let prevNode=this.head;
while (prevNode.next !==node) {
prevNode=prevNode.next;
}
if (node.next===null) {
prevNode.next=null;
}
if (node.next) {
prevNode.next=node.next;
}
this.length--;
}
}
雙向鏈表
如果你把上面介紹的單向列表都看明白了,那么這里介紹的雙向列表其實差不多。
從上面的圖可以很清楚的看到雙向鏈表和單向鏈表的區別。雙向鏈表多了一個指向上一個節點的指針。
初始化節點
class ListNode {
this.prev=null;
this.next=null;
this.key=key;
}
初始化雙向鏈表
class List {
constructor(){
this.head=null;
}
}
創建節點
static createNode(key){
return new ListNode(key);
}
插入節點((插入到頭節點之后)
insert(node) {
node.prev=null;
node.next=this.head;
if(this.head){
this.head.prev=node;
}
this.head=node;
}
搜索節點
這里和單向節點一樣,就直接貼代碼了
search(key) {
let node=this.head;
while (node !==null && node.key !==key) {
node=node.next;
}
return node;
}
刪除節點
和之前單向鏈表一樣,分三種情況去看:
delete(node) {
const {prev,next}=node;
delete node.prev;
delete node.next;
if(node===this.head){
this.head=next;
}
if(next){
next.prev=prev;
}
if(prev){
prev.next=next;
}
}
雙向鏈表整體代碼
class ListNode {
constructor(key) {
// 指向前一個節點
this.prev=null;
// 指向后一個節點
this.next=null;
// 節點的數據(或者用于查找的鍵)
this.key=key;
}
}
/**
* 雙向鏈表
*/
class List {
constructor() {
this.head=null;
}
static createNode(key) {
return new ListNode(key);
}
insert(node) {
node.prev=null;
node.next=this.head;
if (this.head) {
this.head.prev=node;
}
this.head=node;
}
search(key) {
let node=this.head;
while (node !==null && node.key !==key) {
node=node.next;
}
return node;
}
delete(node) {
const { prev, next }=node;
delete node.prev;
delete node.next;
if (node===this.head) {
this.head=next;
}
if (prev) {
prev.next=next;
}
if (next) {
next.prev=prev;
}
}
}
總結
這里做一個小總結吧,可能有一部分人讀到這里還不是特別的明白,我的建議是先好好看懂上面的單向鏈表。 其實只要你明白了鏈表的基礎概念,就是有一個head,然后在有好多的節點(Node),然后用一個指針把他們串起來就好了,至于里面的插入操作也好,刪除也好,其實都是在調整節點中指針的指向。
以上就是JavaScript中鏈表的詳細介紹的詳細內容,更多請關注其它相關文章!
更多技巧請《轉發 + 關注》哦!
*請認真填寫需求信息,我們會在24小時內與您取得聯系。