数据结构-链表<Typescript>

链表

什么是链表?

链表是一种动态的数据结构,不同于数组的是,链表分配内存空间的灵活性,它不会像数组一样被分配一块连续的内存。当你想在数组的任意位置,插入一个
新值的时候,必须对数组中的各个元素进行相应的位置移动才能达到目标,开销显然是很大的。然而链表的灵活性在于它的每个元素节点分为两部分,一部分
是存储元素本身,另一部分是指向下一个节点元素的引用,也可以称为指针,当你要插入数据时,把上一个节点的向下指针指向新数据节点,新数据节点的向
下指针指向原有数据。但是链表不像数组那样可以直接通过索引立刻定位,只能通过遍历。

 

 定义个node类

/*节点*/
class Node<T>{
    public element:T;//节点数据
    public next:Node<T> = null;//指向下一个节点 
    constructor(element:T){
        this.element = element;
    }
}

链表的实现

class LinkList<T>{
    private head:Node<T> = null;//链表头
    private tail:Node<T> = null;//链表尾
    private length:number = 0;//链表长度
    /* 向链表添加新节点 */
    public append(element:T):void{
        let node:Node<T> = new Node<T>(element);
        if(this.length <= 0){//如果当前链表为空,则将head,tail指向node
            this.head = node;
            this.tail = node;
        }else{//否则在链表尾添加新元素
            this.tail.next = node;
            this.tail = node;
        }
        this.length++;//链表长度+1
    }
    /* 在链表某位置插入节点 */
    public insert(position:number,element:T):boolean{
        if(position < 1 || position > this.length + 1){
            return false;
        }
        let node:Node<T> = new Node<T>(element);
        if(position == 1){//如果插在第一个位置,将head指向该节点
            node.next = this.head;
            this.head = node;
            if(this.length == 0){
                this.tail = node;
            }
        }else if(position == this.length + 1){//如果插在最后,将tail指向该节点
            this.tail.next = node;
            this.tail = node;
        }else{//剩余是插在链表中间
            let prevNode:Node<T> = this.getNodeAt(position - 1);
            let currentNode:Node<T> = prevNode.next;
            prevNode.next = node;
            node.next = currentNode;
        }
        this.length++;//链表长度+1
    }
    /* 查找某个元素所在的节点位置 */
    public positionOf(element:T):number{
        let currentNode:Node<T> = this.head;
        let currentPosition:number = 1;
        while(currentNode){
            if(currentNode.element == element){
                return currentPosition;
            }
            currentPosition++;
            currentNode = currentNode.next;
        }
        return -1;
    }
    /* 删除某元素节点 */
    public remove(element:T):boolean{
        let position:number = this.positionOf(element);
        if(position < 1 || position > this.length){//越界
            return false;
        }
        let isSuccess:boolean = this.removeAt(position);
        return isSuccess;
    }
    /* 删除某个位置的节点 */
    public removeAt(position:number):boolean{
        if(position < 1 || position > this.length){//越界
            return false;
        }
        let currentNode:Node<T> = this.head;
        if(position == 1){//删除第一个节点
            this.head = currentNode.next;
            if(this.length == 1){
                this.tail = null;
            }
        }else{
            let prevNode:Node<T> = this.getNodeAt(position - 1);
            prevNode.next = prevNode.next.next;
            if(position == this.length){
                this.tail = prevNode;
            }
        }
        this.length--;//链表长度减一
        return true;
    }
    /*  返回某位置的节点*/
    public getNodeAt(position:number):Node<T>{
        if(position < 1 || position > this.length){//越界
            return null;
        }
        let currentNode:Node<T> = this.head;
        let currentPositon:number = 1;
        while(currentPositon < position){//遍历链表,找到节点
            currentNode = currentNode.next;
            currentPositon++;
        }
        return currentNode;
    }
    /* 链表是否为空 */
    public isEmpty():boolean{
        return this.length == 0;
    }
    /*  返回链表长度 */
    public size():number{
        return this.length;
    }
    /* 返回链表头 */
    public getHead():Node<T>{
        return this.head;
    }
    /* 返回链表尾 */
    public getTail():Node<T>{
        return this.tail;
    }
    /* 清空链表 */
    public clear():void{
        this.head = null;
        this.tail = null;
        this.length = 0;
    }
    /* 打印链表 */
    public print():string{
        let currentNode:Node<T> = this.head;
        let str:string = "";
        let currentPostion:number = 1;
        while(currentNode){
            if(currentPostion < this.length){
                str += `element:${currentNode.element} ---- `;
            }else{
                str += `element:${currentNode.element}`;
            }
            currentNode = currentNode.next;
            currentPostion++;
        }
        return str;
    }
}

测试

let list:LinkList<string> = new LinkList<string>();
list.append("电视剧");
list.append("天地男儿");
list.append("刑事侦缉档案");
list.append("西游记");
list.print();
list.remove("电视剧");
list.print();
list.insert(1,"TVB");
list.print();
list.removeAt(2);
list.print();

 双向链表

上面链表称为单链表,每一个元素有一个next指针,指向下一个节点,我们只能从链表的头部开始遍历整个链表,任何一个节点只能找到它的下一个节点,
而不能找到它的上一个节点。双向链表中的每一个元素拥有两个指针,一个用来指向下一个节点,一个用来指向上一个节点。在双向链表中,除了可以像
单向链表一样从头部开始遍历之外,还可以从尾部进行遍历。

 //节点

/* 节点 */
 class Node<T>{
    public element:T;
    public next:Node<T>;
    public prev:Node<T>;
    constructor(element:T){
        this.element = element;
    }
}

//实现

/* 双向链表 */
class DoubleList<T>{
    private length:number = 0;
    private head:Node<T> = null;
    private tail:Node<T> = null;
    /* 向链表添加元素为element的节点 */
    public append(element:T):void{
        let node:Node<T> = new Node<T>(element); 
        if(this.length <= 0){
            this.head = node;
            this.tail = node;
        }else{
            this.tail.next = node;
            node.prev = this.tail;
            this.tail = node;
        }
        this.length++;//链表长度+1
    }
    /* 在链表某位置插入节点 */
    public insert(position:number,element:T):boolean{
        if(position < 1 || position > this.length + 1){
            return false;
        }
        let node:Node<T> = new Node<T>(element);
        if(position == 1){//如果插在第一个位置,将head指向该节点
            node.next = this.head;
            this.head.prev = node;
            this.head = node;
            if(this.length == 0){
                this.tail = node;
            }
        }else if(position == this.length + 1){//如果插在最后,将tail指向该节点
            this.tail.next = node;
            node.prev = this.tail;
            this.tail = node;
        }else{//剩余是插在链表中间
            let prevNode:Node<T> = this.getNodeAt(position - 1);
            let currentNode:Node<T> = prevNode.next;
            prevNode.next = node;
            node.prev = prevNode;
            node.next = currentNode;
            currentNode.prev = node;
        }
        this.length++;//链表长度+1
    }
    /* 查找某个元素所在的节点位置 */
    public positionOf(element:T):number{
        let currentNode:Node<T> = this.head;
        let currentPosition:number = 1;
        while(currentNode){
            if(currentNode.element == element){
                return currentPosition;
            }
            currentPosition++;
            currentNode = currentNode.next;
        }
        return -1;
    } 
    /* 删除某元素节点 */
    public remove(element:T):boolean{
        let position:number = this.positionOf(element);
        if(position < 1 || position > this.length){//越界
            return false;
        }
        let isSuccess:boolean = this.removeAt(position);
        return isSuccess;
    }
    /* 删除某个位置的节点 */
    public removeAt(position:number):boolean{
        if(position < 1 || position > this.length){//越界
            return false;
        }
        let currentNode:Node<T> = this.head;
        let prevNode:Node<T>;
        if(position == 1){//删除第一个节点
            this.head = currentNode.next;
            if(this.head){
                this.head.prev = null;
            }
            if(this.length == 1){
                this.tail = null;
            }
        }else if(position == this.length){//删除最后一个节点
            prevNode = this.tail;
            prevNode.next = null;
            this.tail = prevNode;
        }else{
            prevNode = this.getNodeAt(position - 1);
            prevNode.next = prevNode.next.next;
            prevNode.next.prev = prevNode;
        }
        this.length--;//链表长度减一
        return true;
    }
    /* 返回某个位置的节点 */
    public getNodeAt(position:number):Node<T>{
        if(position < 1 || position > this.length){
            return null;
        }
        let currentNode:Node<T>;
        let currentPosition:number = 1;
        //从后往前遍历
        if(position > Math.floor(this.length / 2)){
            currentNode = this.tail;
            while(currentPosition < this.length - position + 1){
                currentNode = currentNode.prev;
                currentPosition++;
            }
            return currentNode;
        }else{//从前往后
            currentNode = this.head;
            while(currentPosition >= this.length){
                currentNode = currentNode.prev;
                currentPosition++;
            }
            return currentNode;
        }
    }
     /* 链表是否为空 */
     public isEmpty():boolean{
        return this.length == 0;
    }
    /*  返回链表长度 */
    public size():number{
        return this.length;
    }
    /* 返回链表头 */
    public getHead():Node<T>{
        return this.head;
    }
    /* 返回链表尾 */
    public getTail():Node<T>{
        return this.tail;
    }
    /* 清空链表 */
    public clear():void{
        this.head = null;
        this.tail = null;
        this.length = 0;
    }
    /* 打印链表 */
    public print():string{
        let currentNode:Node<T> = this.head;
        let str:string = "";
        let currentPostion:number = 1;
        let prevElement:T;
        let nextElement:T;
        while(currentNode){
            prevElement = currentNode.prev ? currentNode.prev.element : null;
            nextElement = currentNode.next ? currentNode.next.element : null;
            str += `[prev:${prevElement},element:${currentNode.element},next:${nextElement}]  `;
            currentNode = currentNode.next;
            currentPostion++;
        }
        console.log(str + "\n");
        return str;
    }
}

//测试

let list:DoubleList<string> = new DoubleList<string>();
list.append("寻秦记");
list.append("大唐双龙传");
list.append("四大名捕");
list.append("笑傲江湖");
list.append("圆月弯刀");
list.append("布衣神相");    
list.print();
list.removeAt(1);
list.print();
list.removeAt(5);
list.print();

posted on 2020-12-28 00:33  行运茶快乐水  阅读(217)  评论(0编辑  收藏  举报

导航