算法基礎篇-雙向鏈表

在上篇文章中廉丽,我們以及詳細說過了鏈表,但是現(xiàn)實生活中我們不僅僅需要單項的鏈表衷戈,也就是單向的關系呵曹,我們可能需要雙向的關系,那么我們就引出了我們下一個鏈表围苫,雙向鏈表

雙向鏈表

雙向鏈表與單向鏈表的區(qū)別在于,在單向鏈表中我們只有一個next指向他的下一個節(jié)點撤师,但是在雙向鏈表中多添加了一個元素pre剂府,用來指向他的上一個節(jié)點。因此雙向鏈表的具體構成應該為下圖

雙向鏈表的構成

同普通鏈表一樣我們將上圖進行拆分剃盾,我們可以很明確的得到一個雙向鏈表應該有的數(shù)據(jù)結構腺占,如下圖:
雙向鏈表數(shù)據(jù)結構拆分

我們先來實現(xiàn)這兩個類
Node類

import LinkNode from './LinkNode'
export default class DlinkNode extends LinkNode {
    public pre: any;
    constructor(node: any, next?: any, pre?: any) {
        super(node);
        this.pre = pre;
    }
}

List類

import LinkList from './LinkList'
import DLinkNode from './DLinkNode'
export default class DLinklist extends LinkList {
    public tail: any;
    constructor(node?: any) {
        super();
        this.tail = undefined;
    }
}

同普通鏈表一樣,實際上痒谴,雙向鏈表所需要的方法同普通的鏈表方法一樣衰伯。皆為下表方法

方法名 描述
push(item) 添加一個元素到鏈表中
insert(item,index) 添加一個元素到鏈表指定位置中
getItemAt(index) 獲取鏈表指定位置元素
remove() 移除最后一項
clear() 清除鏈表
size() 返回鏈表大小
removeAt(index) 移除指定位置元素并返回
indexOf(item) 獲取指定元素所在的位置

由于雙向鏈表與普通鏈表相比可以看到多了一個pre以及一個tail,所以我們對于增刪處理就需要相對于雙向鏈表多做一些處理积蔚,因此我們只需要修改insert以及removeAt方法即可

insert(item,index)

在指定位置插入元素嚎研。我們選擇插入元素,依舊是只有三個位置库倘,頭部临扮,尾部以及中間,這點和單項鏈表的方式是一樣教翩,
首先頭部插入杆勇,如果頭部插入元素的話,那么也就是當前head指向的為插入的元素饱亿,插入元素的next指向head以前指向的元素蚜退,這點和原有的一樣,但是對于pre彪笼,則需要將當前插入節(jié)點的pre指向一個undefined钻注,將原有的head指向的節(jié)點的pre指向插入的節(jié)點


頭部插入

第二種情況,從尾部插入配猫,也就是將當前尾部元素的next指向我們插入的元素幅恋,我們插入的元素的next指向原有元素next指向的位置這點不變,增加當前插入元素的pre指向原有最后一個節(jié)點泵肄,同時tail指向插入的節(jié)點


尾部插入

第三種情況插入中間位置捆交,那么也就是說假設我們將數(shù)據(jù)插入第二個位置,我們只需要將第一個位置節(jié)點的next指向插入的元素腐巢,插入的元素的next指向當前元素即可品追,和單向的一直,增加對pre處理冯丙,將第二個位置的pre指向插入的元素肉瓦,插入元素的pre指向第二個節(jié)點前一個節(jié)點即可
中間插入

因此我們可以實現(xiàn)insert方法如下
public insert(item: any, index: number): boolean {
        if (index >= 0 && index <= this.count) {
            let node = new DLinkNode(item);
            if (index === 0) {
                if (this.head) {
                    node.next = this.head;
                    this.head = node;
                    this.head.pre = node;
                } else {
                    this.head = node;
                    this.tail = node;
                }
            } else if (index >= this.count) {
                let currentTail = this.getItemAt(this.count - 1);
                this.tail = node;
                node.pre = currentTail;
                currentTail.next = node;
            } else {
                let currentNode = this.getItemAt(index);
                let preNode = this.getItemAt(index - 1);
                node.pre = preNode;
                node.next = currentNode;
                preNode.next = node;
                currentNode.pre = node;
            }
            this.count++;
            return true;
        }
        return false;
    }
removeAt(index)

從任意位置移除元素,我們來分析分析,我們選擇插入元素泞莉,那么同移除有三個位置洁墙,頭部,尾部以及中間戒财,這點和單項鏈表的方式是一樣热监,
首先頭部插入,如果頭部移除元素的話饮寞,那么也就是當前head指向的為插入的元素孝扛,插入元素的next指向head以前指向的元素,這點和原有的一樣幽崩,但是對于pre苦始,則需要將當前插入節(jié)點的pre指向一個undefined,將原有的head指向的節(jié)點的pre指向插入的節(jié)點慌申,也就是


頭部移除

第二種情況陌选,從尾部移除,只需要將tail指向當前尾部的pre節(jié)點蹄溉,同時將pre節(jié)點的next設置為undefined即可


尾部移除

第三種情況插入中間位置咨油,只需要將插入位置的前面節(jié)點的next指向插入位置后面節(jié)點,同時將插入位置后面節(jié)點的pre指向插入位置前面節(jié)點即可
中間位置移除

因此移除的方法實現(xiàn)為
public removeAt(index: number) {
        if (index >= 0 && index < this.size()) {
            let current = this.head;
            if (index == 0) {
                this.head = current.next;
                if (this.size() === 1) {
                    this.tail = undefined;
                } else {
                    this.head.next.pre = undefined;
                }
            } else if (index === this.size() - 1) {
                current = this.tail;
                this.tail = current.pre;
                this.tail.next = undefined;
            } else {
                current = this.getItemAt(index);
                let preNode = current.pre;
                preNode.next = current.next;
                current.next.pre = preNode;
            }
            this.count--;
            return current.node;
        } else {
            return undefined;
        }
    }

至此柒爵,雙向鏈表的說明結束了役电,當然鏈表遠遠不止這兩種,下一章我們將說循環(huán)鏈表以及有序鏈表棉胀。
最后附上雙向鏈表的全部實現(xiàn)

import LinkList from './LinkList'
import DLinkNode from './DLinkNode'
export default class DLinklist extends LinkList {
    public tail: any;
    constructor(node?: any) {
        super();
        this.tail = undefined;
    }
    public insert(item: any, index: number): boolean {
        if (index >= 0 && index <= this.count) {
            let node = new DLinkNode(item);
            if (index === 0) {
                if (this.head) {
                    node.next = this.head;
                    this.head = node;
                    this.head.pre = node;
                } else {
                    this.head = node;
                    this.tail = node;
                }
            } else if (index >= this.count) {
                let currentTail = this.getItemAt(this.count - 1);
                this.tail = node;
                node.pre = currentTail;
                currentTail.next = node;
            } else {
                let currentNode = this.getItemAt(index);
                let preNode = this.getItemAt(index - 1);
                node.pre = preNode;
                node.next = currentNode;
                preNode.next = node;
                currentNode.pre = node;
            }
            this.count++;
            return true;
        }
        return false;
    }
    public push(item: any) {
        let node = new DLinkNode(item);
        if (!this.head) {
            this.head = node;
            this.tail = node;
        } else {
            let currentTail = this.tail;
            currentTail.next = node;
            node.pre = currentTail;
            this.tail = node;
        }
        this.count++;
    }
    public removeAt(index: number) {
        if (index >= 0 && index < this.size()) {
            let current = this.head;
            if (index == 0) {
                this.head = current.next;
                if (this.size() === 1) {
                    this.tail = undefined;
                } else {
                    this.head.next.pre = undefined;
                }
            } else if (index === this.size() - 1) {
                current = this.tail;
                this.tail = current.pre;
                this.tail.next = undefined;
            } else {
                current = this.getItemAt(index);
                let preNode = current.pre;
                preNode.next = current.next;
                current.next.pre = preNode;
            }
            this.count--;
            return current.node;
        } else {
            return undefined;
        }
    }
}
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末法瑟,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子唁奢,更是在濱河造成了極大的恐慌霎挟,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件麻掸,死亡現(xiàn)場離奇詭異酥夭,居然都是意外死亡,警方通過查閱死者的電腦和手機论笔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進店門采郎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人狂魔,你說我怎么就攤上這事∫担” “怎么了最楷?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我籽孙,道長烈评,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任犯建,我火速辦了婚禮讲冠,結果婚禮上,老公的妹妹穿的比我還像新娘适瓦。我一直安慰自己竿开,他們只是感情好,可當我...
    茶點故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布玻熙。 她就那樣靜靜地躺著否彩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪嗦随。 梳的紋絲不亂的頭發(fā)上列荔,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天,我揣著相機與錄音枚尼,去河邊找鬼贴浙。 笑死,一個胖子當著我的面吹牛署恍,可吹牛的內容都是我干的悬而。 我是一名探鬼主播,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼锭汛,長吁一口氣:“原來是場噩夢啊……” “哼笨奠!你這毒婦竟也來了?” 一聲冷哼從身側響起唤殴,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤般婆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后朵逝,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蔚袍,經...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年配名,在試婚紗的時候發(fā)現(xiàn)自己被綠了啤咽。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,650評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡渠脉,死狀恐怖宇整,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情芋膘,我是刑警寧澤鳞青,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布霸饲,位于F島的核電站,受9級特大地震影響臂拓,放射性物質發(fā)生泄漏厚脉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一胶惰、第九天 我趴在偏房一處隱蔽的房頂上張望傻工。 院中可真熱鬧,春花似錦孵滞、人聲如沸中捆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽轨香。三九已至,卻和暖如春幼东,著一層夾襖步出監(jiān)牢的瞬間臂容,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工根蟹, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留脓杉,地道東北人。 一個月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓简逮,卻偏偏與公主長得像球散,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子散庶,可洞房花燭夜當晚...
    茶點故事閱讀 43,527評論 2 349

推薦閱讀更多精彩內容