TypeScript数据结构与算法(5)最基础的数据结构-链表-LinkedList

链表的概念,使用文字描述过于苍白,用一张图解释:

从图中可以看出链表的特性:

1.存储在链表中元素时无顺序的,图中我故意打乱了排列的情况,就是为了说明这一点,如果仍然无法理解这点,可以对比下数组来看看链表中的各个元素的关系

2.链表中的各个元素之前的关联关系,由每个元素中的next这个属性来进行链接,也就是说,每个元素中next这个属性就是存储的下一个节点(这里开始涉及递归的概念了)

3.存储链表元素的叫做节点Node,它的设计如下:

class Node<T>{
    e: T;
    next: Node<T>;
    constructor(e: T, next: Node<T>) {
        this.e = e;
        this.next = next;
    }
}

这里,我先实现了一个普通的链表DataStruct_LinkedList_Normal<T>,源码如下:

class Node<T>{
    e: T;
    next: Node<T>;
    constructor(e: T, next: Node<T>) {
        this.e = e;
        this.next = next;
    }
}

/**
* Autor: Created by 李清风 on 2020-12-19.
* Desc: 不采用虚拟头节点的链表,慢慢引入虚拟头节点,解决index==0的情况
*/

export class DataStruct_LinkedList_Normal<T> {

    private head: Node<T>;//指向linked第一个节点
    private size: number;

    constructor() {
        this.head = null;
        this.size = 0;
    }

    //获取size
    public getSize(): number {
        return this.size;
    }

    //是否为空
    public isEmpty(): boolean {
        return this.size == 0;
    }

    //在链表头部添加元素
    public addFirst(e: T) {
        this.head = new Node(e, this.head);
        this.size++;
    }

    //在链表指定索引(0-based)处添加新元素
    //注:在真实使用链表的环境中,并不存在索引的概念
    public add(index: number, e: T) {
        if (index < 0 || index > this.size) {
            throw new Error("LogError:Add failed.Require index >=0 and index<size.");
        }
        if (index == 0) {
            this.addFirst(e);
        } else {
            let prev: Node<T> = this.head;
            for (let i = 0; i < index - 1; i++) {  // index - 1表示遍历链表结构树寻找插入位置之前的那个索引元素
                prev = prev.next;
            }
            prev.next = new Node(e, prev.next);
            this.size++;
        }
    }

    public addLast(e: T) {
        this.add(this.size, e);
    }

}

 引入虚拟头节点dummyHead,对上述实现的简单的链表数据结构类进行优化,源码如下:

/**
* Autor: Created by 李清风 on 2020-12-19.
* Desc: 链表,在内存中无序的,通过next把一个一个node链接起来,构建关系
*/

class Node<T>{
    public e: T;
    public next: Node<T>;//这里就有递归的意思了
    constructor(e: T, next: Node<T>) {
        this.e = e;
        this.next = next;
    }
}

export class DataStruct_LinkedList<T>{
    private dummyHead: Node<T>;//虚拟头节点
    private size: number; //链表中实际存储了多少个元素

    constructor() {
        this.dummyHead = new Node(null, null);
        this.size = 0;
    }

    public getSize(): number {
        return this.size;
    }

    public isEmpty(): boolean {
        return this.size == 0;
    }

    //往链表中添加元素
    public add(index: number, e: T) {
        if (index < 0 || index > this.size) {
            throw new Error("LogError:Add failed.Require index >=0 and index<size.");
        }
        let p: Node<T> = this.dummyHead;
        for (let i = 0; i < index; i++) {
            p = p.next;
        }
        p.next = new Node<T>(e, p.next);
        this.size++;
    }

    //头部插入元素
    public addFirst(e: T) {
        this.add(0, e);
    }

    //尾部插入元素
    public addLast(e: T) {
        this.add(this.size, e);
    }

    //根据index获取元素
    public getElement(index: number): T {
        if (index < 0 || index >= this.size) {
            throw new Error("LogError:Add failed.Require index >=0 and index<size.");
        }
        let cur = this.dummyHead.next;
        for (let i = 0; i < index; i++) {
            cur = cur.next;
        }
        return cur.e;
    }

    //获取首元素
    public getFirst(): T {
        return this.getElement(0);
    }

    //获取尾元素
    public getLast(): T {
        return this.getElement(this.size - 1);
    }

    //设置index处的元素为e
    public setElement(index: number, e: T) {
        if (index < 0 || index >= this.size) {
            throw new Error("LogError:Add failed.Require index >=0 and index<size.");
        }
        let cur = this.dummyHead.next;
        for (let i = 0; i < index; i++) {
            cur = cur.next;
        }
        cur.e = e;
    }

    //链表是否包含元素e
    public contains(e: T): boolean {
        let cur = this.dummyHead;
        while (cur.next != null) {
            if (cur.e == e) { //Equals更好
                return true;
            }
            cur = cur.next;
        }
        return false;
    }

    //移除index处的元素
    public remove(index: number) {
        if (index < 0 || index >= this.size) {
            throw new Error("LogError:Add failed.Require index >=0 and index<size.");
        }
        let p = this.dummyHead;
        for (let i = 0; i < index; i++) {
            p = p.next;
        }
        let retNode = p.next;
        p.next = retNode.next;
        retNode.next = null;//与链表脱离
        this.size--;
        return retNode.e;
    }

    //移处链表中某个元素
    public removeElement(e: T) {
        let prev = this.dummyHead;
        while (prev.next != null) {
            if (prev.next.e == e) { //可以自己封装一个equals
                break;
            }
            prev = prev.next;
        }

        if (prev.next != null) {
            let delNode = prev.next;
            prev.next = delNode.next;
            delNode.next = null;//与链表脱离
        }
    }

    //移除首元素
    public removeFirst() {
        return this.remove(0);
    }

    //移除尾元素
    public removeLast() {
        return this.remove(this.size - 1);
    }
}

 

posted @ 2021-01-21 15:48  CYNLINQ  阅读(311)  评论(0)    收藏  举报