JavaScript数据结构与算法 -- 链表(单向链表)

1.链表

  • 链表和数组一样,可以用于存储一系列的元素,但是链表和数组的实现机制完全不同。
  • 要存储多个元素,另外一个选择就是链表。
  • 但不同于数组,链表中的元素在内存中不必是连续的空间。
  • 链表的每个元素由一个存储元素本身的接概念和一个指向下一个元素的引用(c语言指针)组成。

2.数组的局限性

  • 数组是我们常用的最常用的存储多个元素的闲心结构。
  • 数组的创建通常需要盛情一段连续的内存空间,并且大小是滚顶的,所有当前数组不能满足需求时,就要进行扩容。
  • 而且数组中进行插入元素和删除元素,需要大量的元素进行位移。
  • 但是数组在查找元素的时候可以直接通过下标值查找,效率很高。

3.链表和数组的对比

  • 内存空间不必时来内需的,可以充分利用计算机的内存,实现灵活的内存动态管理。
  • 链表不必再创建时就确定大小,并且大小可以无限的延伸下去。
  • 链表在插入和删除数据的时候,时间复杂度可以达到O(1),相对数组小效率很高。
  • 链表在访问元素的时候效率较数组低。(因为链表是一个个相连的,所以访问元素需要从头一个个访问,性能较低)

4.如何选择

  • 当我们频繁插入删除元素的时候使用链表。
  • 当我们频繁访问元素的时候则使用数组更好。

5.链表的常见操作

  • append(element):向链表尾部添加一个新的项
  • insert(position,element):向链表的特定位置插入一个新的项
  • get(position): 获取对应位置的元素
  • indexOf(element): 返回元素在列表中的索引,没有返回-1
  • updata(postion): 修改某个位置的元素
  • removeAt(position):从列表的特定位置移除一项
  • remove(element):从列表中移除一项
  • isEmpty()
  • size()
  • toString()
    一般数组里面有的操作,链表也有

5.封装链表

1.链表里面要有哪些属性?

  • head 属性,指向下一个节点
  • node 属性,一个个节点
  • 节点里面有 data 和 指向下一个节点的引用 next

2.链表操作的实现

  • 1.append(element)方法:在链表末尾添加一个新的节点
    • 创建一个节点(如果是第一个节点,将head指针指向这个节点)
    • 插入第二个节点,创建一个新的节点,找到这个节点的上一个节点,然后将他的next指向新的节点。
    • 第三个…都一样
//1.追加方法 append
    LinkedList.prototype.append = function (data) {
        // 先判断是否添加的是第一个节点
        //先创建一个新的节点
        let newNode = new Node(data);
        if (this.length == 0) {
            this.head = newNode;
        } else {
            //当前指针指向的是第上一个节点,将他赋给变量current
            let current = this.head;
            //判断current的next是不是为空,要是为空就是最后一个节点了 
            while (current.next) {
                current = current.next
            }
            //让最后一个节点的next等于新的节点
            current.next = newNode;
        }
        //3.让链表的长度+1
        this.length += 1;
    }

在这里插入图片描述

  • 2.toString()方法
    • 主要是获取链表中每个元素
    • 从head开始
    • 循环遍历每一个节点,并且去除里面的element,拼接成字符串
    • 返回最终字符串
//2.toString方法
    LinkedList.prototype.toString = function(){
        //1.先定义一个变量
        let current = this.head;
        //定义一个接受字符串
        let resultString = '';
        //2.循环获取一个个的节点
        while(current){
            resultString += current.data + ' ';
            current = current.next;
        }

        return resultString;
    }

在这里插入图片描述

  • 3.insert()
    • 传入position
    • 传入data
//3.insert方法
LinkedList.prototype.insert = function(position, data){
    //1.对position进行越界判断
    //2.长度判断
    if(position < 0 || position > this.length){
        return false;
    }

    //3.根据data创建节点
    let newNode = new Node(data);

    //4.插入数据
    //判断插入的位置是否是第一个
    if(position == 0){
        newNode.next = this.head;
        this.head = newNode;
    } else {
        let index = 0;
        let current = this.head;
        let previous = null;
        while(index ++ < position){
            previous = current;
            current = current.next;
        }
        newNode.next = current;
        previous.next = newNode;
    }

    //5.length ++
    this.length += 1;
    return true;
}

在这里插入图片描述

  • 4.get方法
    • 传入一个position信息
    • 找到相应的数据并且返回
//4.get方法
    LinkedList.prototype.get = function(position){
        //1.越界判断
        if(position < 0 || position >= this.length){
            return false;
        }

        //2.获取对应的data
        let current = this.head;
        let index = 0;
        while(index++ < position){
            current = current.next;
        }
        return current.data;
    }

在这里插入图片描述

  • 5.indexOf方法
    • 传入某个元素data
    • 返回元素在链表中的位置,没有的话返回-1
 //5.indexOf方法
    LinkedList.prototype.indexOf = function(element){
        //1.定义变量
        let current = this.head;
        let index = 0;

        //2.开始查找
        while(current){
            if(current.data == element){
                return index;
            }
            current = current.next;
            index += 1
        }

        //3.找到最后没有找到,返回-1
    }

在这里插入图片描述

  • 6.updata方法
//6.updata方法
    LinkedList.prototype.updata = function(position, newDate){
        //1.越界判断
        if(position < 0 || position >= this.length){
            return false;
        }

        //2.先查找到正确的节点
        let current = this.head;
        let index = 0;
        while(index ++ < position){
            current = current.next;
        }

        //3.修改数据
        current.data = newDate;
        return true;
    }

在这里插入图片描述

  • 7.removeAt()方法
    • 传入一个参数position
    • 返回被删除的节点信息
 //7.removeAt
    LinkedList.prototype.removeAt = function(position){
        //1.越界判断
        if(position < 0 || position >= this.length){
            return null;
        }
        let current = this.head;
        //2.判断是否删除的是第一个节点
        if(position == 0){
            this.head = this.head.next;
        } else {
            //3.先根据position找到元素
            let index = 0;
            let previous = null;
            while(index++ < position){
                previous = current;
                current = current.next;
            }
            //前一个节点的next指向下一个节点的next
            previous.next = current.next;
        }
        //4.length -1 
        this.length -= 1;
        return current.data;
    }

在这里插入图片描述

  • 8.remove方法
    • 传入数据data
    • 删除节点返回被删除节点的data
 //8.remove方法
    LinkedList.prototype.remove = function (data) {
        //1.获取data在列表中的位置
        let position = this.indexOf(data);

        //2.根据位置信息,删除节点

        //3.length - 1
        //this.length -= 1;
        return this.removeAt(position);
    }

6.链表完美封装 和 相应测试代码

 function LinkedList() {
            //属性:至少包含一个head属性,默认指向null
            this.head = null;
            //记录链表的长度
            this.length = 0;
            //封装node内部类
            function Node(data) {
                this.data = data;
                this.next = null;
            }

            //1.追加方法 append
            LinkedList.prototype.append = function (data) {
                // 先判断是否添加的是第一个节点
                //先创建一个新的节点
                let newNode = new Node(data);
                if (this.length == 0) {
                    this.head = newNode;
                } else {
                    //当前指针指向的是第上一个节点,将他赋给变量current
                    let current = this.head;
                    //判断current的next是不是为空,要是为空就是最后一个节点了 
                    while (current.next) {
                        current = current.next
                    }
                    //让最后一个节点的next等于新的节点
                    current.next = newNode;
                }
                //3.让链表的长度+1
                this.length += 1;
            }

            //2.toString方法
            LinkedList.prototype.toString = function () {
                //1.先定义一个变量
                let current = this.head;
                //定义一个接受字符串
                let resultString = '';
                //2.循环获取一个个的节点
                while (current) {
                    resultString += current.data + ' ';
                    current = current.next;
                }

                return resultString;
            }
            //3.insert方法
            LinkedList.prototype.insert = function (position, data) {
                //1.对position进行越界判断
                //2.长度判断
                if (position < 0 || position > this.length) {
                    return false;
                }

                //3.根据data创建节点
                let newNode = new Node(data);

                //4.插入数据
                //判断插入的位置是否是第一个
                if (position == 0) {
                    newNode.next = this.head;
                    this.head = newNode;
                } else {
                    let index = 0;
                    let current = this.head;
                    let previous = null;
                    while (index++ < position) {
                        previous = current;
                        current = current.next;
                    }
                    newNode.next = current;
                    previous.next = newNode;
                }

                //5.length ++
                this.length += 1;
                return true;
            }

            //4.get方法
            LinkedList.prototype.get = function (position) {
                //1.越界判断
                if (position < 0 || position >= this.length) {
                    return false;
                }

                //2.获取对应的data
                let current = this.head;
                let index = 0;
                while (index++ < position) {
                    current = current.next;
                }
                return current.data;
            }

            //5.indexOf方法
            LinkedList.prototype.indexOf = function (element) {
                //1.定义变量
                let current = this.head;
                let index = 0;

                //2.开始查找
                while (current) {
                    if (current.data == element) {
                        return index;
                    }
                    current = current.next;
                    index += 1
                }

                //3.找到最后没有找到,返回-1
            }

            //6.updata方法
            LinkedList.prototype.updata = function (position, newDate) {
                //1.越界判断
                if (position < 0 || position >= this.length) {
                    return false;
                }

                //2.先查找到正确的节点
                let current = this.head;
                let index = 0;
                while (index++ < position) {
                    current = current.next;
                }

                //3.修改数据
                current.data = newDate;
                return true;
            }


            //7.removeAt
            LinkedList.prototype.removeAt = function (position) {
                //1.越界判断
                if (position < 0 || position >= this.length) {
                    return null;
                }
                let current = this.head;
                //2.判断是否删除的是第一个节点
                if (position == 0) {
                    this.head = this.head.next;
                } else {
                    //3.先根据position找到元素
                    let index = 0;
                    let previous = null;
                    while (index++ < position) {
                        previous = current;
                        current = current.next;
                    }
                    //前一个节点的next指向下一个节点的next
                    previous.next = current.next;
                }
                //4.length -1 
                this.length -= 1;
                return current.data;
            }

            //8.remove方法
            LinkedList.prototype.remove = function (data) {
                //1.获取data在列表中的位置
                let position = this.indexOf(data);

                //2.根据位置信息,删除节点

                //3.length - 1
                this.length -= 1;
                return this.removeAt(position);
            }
        }


        //测试代码
        //创建一个LinkList
        let list = new LinkedList();
        list.append('abc');
        list.append('123');
        list.append('nba');
        list.append('NBA');
        list.insert(2, 'KJH')
        console.log(list);
        console.log(list.get(2)); //KJH
        console.log(list.indexOf('KJH')); //2
        list.updata(0, '000');
        list.updata(2, '111');
        list.removeAt(2)
        console.log(list.removeAt(1)) //123
        console.log(list.remove('NBA'))
        console.log(list)
  • 每个人生下来都是小人,而大人就是一点点积累起来的。
发布了85 篇原创文章 · 获赞 16 · 访问量 6094

猜你喜欢

转载自blog.csdn.net/qq_43955202/article/details/104508369