js数据结构学习双链表 集合

Posted lin-fighting

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了js数据结构学习双链表 集合相关的知识,希望对你有一定的参考价值。

双链表

单链表明显的缺点就是寻找上一个节点的时候太麻烦,需要从头遍历。
双向链表既可以从头遍历到尾也可以从尾遍历到头,也可以解决单向链表的缺点。
缺点:
插入和删除的时候需要处理四个指针,比较复杂。
比起单向链表,占用内存肯定稍微大一点。
但是其与方便程度相比,是微不足道的。

特点:
有头指针和尾指针指向链表的第一个和最后一个节点
每个节点有三部分,data,pre,next
第一个节点的pre为null
最后一个节点的next为null。
实现:

class Node {
    constructor(data) {
        this.data = data;
        this.next = null;
        this.prev = null;
    }
}
class LinkedList {
    constructor() {
        //头指针
        this.head = null;
        //尾指针
        this.tail = null;
        //链表的长度
        this.length = 0;
    }

    append(data) {
        const element = new Node(data);
        if (this.head) {
            let current = this.head;
            while (current.next) {
                current = current.next;
            }
            //双向连接
            element.prev = current;
            current.next = element;
            this.tail = element;
        } else {
            //第一个
            this.head = element;
            this.tail = element;
        }

        this.length++;
    }

    // //特定位置插入
    insert(position, data) {
        const element = new Node(data);
        if (
            typeof position !== "number" ||
            position < 0 ||
            position > this.length
        ) {
            return false;
        }

        if (this.length === 0) {
            //链表原来为空
            this.head = element;
            this.tail = element;
        } else if (position === 0) {
            //第一位
            this.head.prev = element;
            element.next = this.head;
            this.head = element;
        } else if (position === this.length) {
            //最后一个
            this.tail.next = element
            element.prev = this.tail
            this.tail = element
        } else {
            let index = 0;
            let current = this.head;
            //找到插入位置的上一个节点,如postion为2,这个位置的上个节点就是1
            while (index++ < position - 1) {
                current = current.next;
            }
            //修改四个节点
            let nextElement = current.next; //把原来的第二的节点保存起来
            nextElement.prev = element;
            element.next = nextElement;
            element.prev = current;
            current.next = element;
        }

        this.length++;
        return true
    }

    // //获取对应位置的元素
    get(position) {
        if (
            typeof position !== "number" ||
            position < 0 ||
            position >= this.length
        ) {
            return false;
        }
        let index = 0
        let current = this.head
        while (index++ < position) {
            current = current.next
        }
        return current.data
    }

    // //返回元素在列表中的索引
    indexOf(data) {
        let index = 0
        let current = this.head
        while (current) {
            if (current.data === data) {
                return index
            }
            current = current.next
            index++
        }

        return -1
    }

    // //修改某个位置的元素
    update(position, data) {
        if (
            typeof position !== "number" ||
            position < 0 ||
            position >= this.length
        ) {
            return false;
        }
        let index = 0
        let current = this.head
        while (index++ < position) {
            current = current.next
        }
        current.data = data
        return true
    }

    // //从列表的特定位置移除一项
    removeAt(position) {
        if (
            typeof position !== "number" ||
            position < 0 ||
            position >= this.length
        ) {
            return false;
        }
        if (this.length === 1) {
            //只有一个
            this.head = null
            this.tail = null
        } else if (position === 0) {
            //删除第一个
            this.head.next.prev = null
            this.head = this.head.next
        } else if (position === this.length - 1) {
            //删最后一个
            this.tail.prev.next = null
            this.tail = this.tail.prev
        } else {
            let index = 0
            let current = this.head
            while (index++ < position) { //找到当前位置的节点
                current = current.next
            }
            current.prev.next = current.next
            current.next.prev = current.prev
        }
        this.length--

        return true
    }

    // 从列表移除一项
    remove(element) {
        if (!this.length) {
            return false
        } else if (this.length === 1) {
            //列表只有一个,且相等
            if (this.head.data === element) {
                this.head = null
                this.tail = null
            } else {
                return false
            }
        } else if (this.tail.data === element) {
            //最后一个相等
            this.tail.prev.next = null
            this.tail = this.tail.prev
        } else {
            let current = this.head
            let isRemove = false
            while (current) {
                if (current.data === element) {
                    current.prev.next = current.next
                    current.next.prev = current.next
                    isRemove = true
                    break;
                }
                current = current.next
            }
            if (!isRemove) {
                return false
            }
        }
        this.length--
        return true
    }
    isEmpty() {
        return !!this.length;
    }

    size() {
        return this.length;
    }

    forwardString() {
        let current = this.head;
        let str = "";
        while (current) {
            str += `,${current.data.toString()}`;
            current = current.next;
        }
        return str.slice(1);
    }
    backwardString() {
        let current = this.tail;
        let str = "";
        while (current) {
            str += `,${current.data.toString()}`;
            current = current.prev;
        }
        return str.slice(1);
    }
}

const test = new LinkedList();
test.append("FBA");
test.append("CBA");
test.insert(0, "NBA");
test.insert(0, "DDD");
test.insert(0, "EEE");
test.remove('CBA')
test.remove('NBA')
console.log(test.forwardString());

跟单链表的实现流程差不多,不同的是要兼顾this.tail的处理,如增加或者删除的时候,要注意this.tail是否需要变化。而且处理的指针也多了两个左右。但是实现思路不是很难,如上。

集合

集合是由一组无序的,不能重复的元素构成。
es6其实已经实现了Set集合类。(js中的Set是有序集合)
具体可以了解:集合
这里我们从头简单封装下Set集合类。
这里基于object封装。

class Set{
    constructor(){
        this.items = {}
    }


    add(val){
        if(this.has(val)){
            return false
        }
        this.items[val] = val
        return true
    }

    remove(val){
        if(!this.has(val)){
            return  false
        }
        delete this.items[val]
        return true
    }



    has(val){
        return this.items.hasOwnProperty(val)
    }

    clear(){
        this.items = {}
        return true
    }

    size(){
        return Object.keys(this.items).length
    }

    values(){
        return Object.values(this.items)
    }
}


const test = new Set()
test.add('NBA')
test.add('CBA')
test.add('FBA')
console.log(test.values());
test.remove('CBA')
test.add('MBA')
console.log(test.items);

set的封装完成。这里是基于对象封装的。

集合间操作

并集 A+B
交集 A跟B共有
差集 A有B没有
子集

实现

 //并集
  //并集
    union(otherSet){
        const newSet = new Set()

        //将老集合的加到新集合中
        this.values().forEach(item=>{
            newSet.add(item)
        })

        console.log(newSet);

        // 将其他集合加到集合中
        otherSet.values().forEach(item=>{
            if(!newSet.has(item)){
                newSet.add(item)
            }
        })
        return newSet
    }

    //交集
    intersection(otherSet){
        const newSet = new Set()

        //  遍历1,判断存在2吗,存在即交集
        this.values().forEach(item=>{
            if(otherSet.has(item)){
                newSet.add(item)
            }
        })

        return newSet
    }

    //差集
    difference(otherSet){
        const newSet = new Set()
          //  遍历1,判断存在2吗,存在即交集
          this.values().forEach(item=>{
            if(!otherSet.has(item)){
                newSet.add(item)
            }
        })

        return newSet
    }

    son(otherSet){
        let isSon = true
        //遍历子集合,判断是否有一个没在父集合中
        otherSet.values().forEach(item=>{
                if(!this.has(item)){
                    isSon = false
                }
        })

        return isSon
    }



集合就实现完毕了。

以上是关于js数据结构学习双链表 集合的主要内容,如果未能解决你的问题,请参考以下文章

Go 语言学习数据结构:双链表

双链集合添加删除算法

双链集合添加删除算法

一百万个结构数组,根据其中一项值排序,用双链表还是数组排序效率更好,请给出最快C或C++算法代码。

js封装一个双链表

基础数据结构---双链表go语言的代码实现