JS--学习链表以及单链表合并、翻转、两两交换节点位置、单向链表和单向循环链表实现约瑟夫环问题等

JS–学习链表

一、链表结构

1、单向链表

单向链表

2、双向链表

双向链表

3、单向循环链表

单向循环链表

4、双向循环链表

双向循环链表
5、链表与数组

数组:js中数组中可以存储不同数据类型的数据,查找元素很方便(随机访问),可以根据下标快速查找;但是删除、添加都比较复杂,会是数组中元素移动。

链表:查找数据不如数组方便,但是删除、插入等操作时会比较迅速,因为链表不需要移动多个元素,使用指针直接将元素添加进来或删除掉,但是空间会有部分浪费(使用部分空间存储指针,以空间换时间)

二、封装链表

1、单向链表

class NodeOne {//每一个节点
    constructor(element) {
        this.data = element;//数据
        this.next = null;//指针
    }
}
//下标由0开始
class OneLinkList {//单向链表
    constructor() {
        this.head = null;//头指针
        this.length = 0;//链表长度
    }
    //添加节点
    append(element) {
        //创建一个新节点
        let node = new NodeOne(element);
        //this.head == null和this.length == 0都可以判断链表为空
        if (this.head == null || this.length == 0) {
            //链表为空时直接添加节点
            this.head = node;
        } else {
            //链表部位空时找到尾部节点,在尾部节点后面添加节点
            let current = this.head;
            //找到next == null,不再往后找
            while (current.next != null) {//判断条件可以换为current.next
                //next为空就继续往下找
                current = current.next;
            }
            //next为空后就将next指向刚创建的新节点
            current.next = node;
        }
        this.length++;//每添加一个节点就将链表长度+1
    }
    //在任意位置和它前一个之间插入节点
    insert(element, position) {
        if (position < 0 || position > this.length || !Number.isInteger(position)) {
            return -1;
        }
        let node = new NodeOne(element);
        let current = this.head;
        if (position == 0) {
            if (this.head == null || this.length == 0) {
                this.head = node;
            } else {
                //链表不为空时插入到头部
                current.next = this.head;//先将新的节点连接到头指针指向的节点
                this.head = node;//再将头指针指向新的节点
            }
        } else if (position == this.length) {
            this.append(node);
        } else {
            //方法一:
            let current = this.head, index = 0;
            while (index++ < position - 1) {
                current = current.next;
            }
            node.next = current.next;
            current.next = node;
            //方法二:
            // let current = this.head;
            // let previous = null;
            // let index = 0;
            // while (index < position) {
            //     previous = current;
            //     current = current.next;
            //     index++;
            // }
            // node.next = current;
            // previous.next = node;
        }
        this.length++;
    }
    //便于查看链表内容
    toString() {
        let listData = '';
        let current = this.head;
        while (current) {
            listData += '-' + current.data;
            current = current.next;
        }
        return listData.slice(1);
    }
    //根据数据查找节点
    indexOf(element) {
        let current = this.head;
        let index = 0;
        while (current) {
            if (current.data === element) {
                return index;
            }
            index++;
            current = current.next;
        }
        return -1;
    }
    //移除特定位置的节点
    removeAt(position) {
        //不合法的位置返回-1
        if (position < 0 || position > this.length || !Number.isInteger(position)) {
            return -1;
        }
        //删除第一个
        if (position == 0) {
            //只有一个节点
            if (this.length == 1) {
                this.head = null;
            } else {
                //有多个节点
                this.head = this.head.next;
            }
            // //删除最后一个
            }else if(position == this.length - 1){
                let current = this.head;
                let index = 0;
                while(index++ < position - 1){
                    current = current.next;
                }
                current.next = null;
        //移除中间部分和尾部合并    
        } else {
            let current = this.head;
            let index = 0;
            while (index++ < position) {
                current = current.next;
            }
            current.next = current.next.next;
        }
        this.length--;
    }
    isEmpty(){
        return this.length == 0;
    }
    size(){
        return this.length;
    }
    remove(element){
        return this.removeAt(this.indexOf(element));
    }

}

2、双向链表

class DoubleNode {
    constructor(element) {
        this.data = element;
        this.next = null;//下一个
        this.previous = null;//前一个
    }
}
class DoubleLinkList {
    constructor() {
        this.head = null;//头指针
        this.length = 0;
        this.tail = null;//尾指针
    }
    //添加节点
    append(element) {
        let node = new DoubleNode(element);
        if (this.head == null) {//链表为空时
            this.head = node;
            this.tail = node;
        } else {//不为空时
            //前两句可以交换位置
            this.tail.next = node;
            node.previous = this.tail;
            this.tail = node;
        }
        this.length++;
    }
    //正向遍历
    toAfterString() {
        let re = '';
        let current = this.head;
        while (current) {
            re += '-' + current.data;
            current = current.next;
        }
        return re.slice(1);
    }
    //反向遍历
    toBeforString() {
        let re = '';
        let current = this.tail;
        while (current) {
            re += '-' + current.data;
            current = current.previous;
        }
        return re.slice(1);
    }
    //特定位置插入
    insert(element, position) {
        //数据不合法
        if (position < 0 || position > this.length || !Number.isInteger(position)) {
            return -1;
        }
        //创建节点
        let node = new DoubleNode(element);
        //在头部插入
        if (position == 0) {
            //链表为空时
            if (this.head == null) {
                this.head = node;
                this.tail = node;
            } else {//不为空时
                node.next = this.head;
                this.head.previous = node;
                this.head = node;
            }
        } else if (position == this.length) {
            //在尾部插入相当于添加节点
            this.append(element);
        } else {//在中间插入
            let current = this.head;
            let index = 0;
            while (index++ < position) {
                //找到插入位置
                current = current.next;
            }
            //先将创建的节点连接上去再将之前链表上原有的连接修改
            node.next = current;
            node.previous = current.previous;
            //后面两步尽量不交换位置,交换后将会变得复杂
            current.previous.next = node;
            current.previous = node;
        }
        this.length++;
    }
    //根据数据查找元素位置(正向查找)
    indexOf(element) {
        let current = this.head;
        let index = 0;
        while (current) {
            if (current.data === element) {
                return index;
            }
            index++;
            current = current.next;
        }
        return -1;
    }
    //反向查找
    lastIndexOf(element) {
        let current = this.tail;
        let index = this.length - 1;
        while (current) {
            if (current.data === element) {
                return index;
            }
            index--;
            current = current.previous;
        }
        return -1;
    }
    //移除指定位置的节点
    removeAt(position) {
        //数据不合法
        if (position < 0 || position > this.length || !Number.isInteger(position)) {
            return -1;
        }
        //头部移除
        if (position == 0) {
            //链表为空时
            if (this.head == null) {
                this.head = null;
                this.tail = null;
            } else {//不为空时
                this.head = this.head.next;
                this.head.previous = null;
            }
            //移除尾部
        } else if (position == this.length - 1) {
            this.tail = this.tail.previous;
            this.tail.next = null;
            //移除中间节点
        } else {
            //从头部开始往后找
            let current = this.head;
            let index = 0;
            while (index++ < position) {
                current = current.next;
            }
            //可以交换位置
            current.previous.next = current.next;
            current.next.previous = current.previous;
        }
        this.length--;
    }
    //移除节点
    remove(element) {
        return this.removeAt(this.indexOf(element));
    }
    size() {
        return this.length;
    }
    isEmpty() {
        return this.length == 0;
    }
    getHead() {
        return this.head.data;
    }
    getTail() {
        return this.tail.data;
    }
    //将removeAt(position)转换为二分查找的方式
    removeAtHalf(position) {
        if (position < 0 || position > this.length || !Number.isInteger(position)) {
            return -1;
        }
        if (position == 0) {
            //链表为空时
            if (this.head == null) {
                this.head = null;
                this.tail = null;
            } else {//不为空时
                this.head = this.head.next;
                this.head.previous = null;
            }
        } else if (position == this.length - 1) {
            //移除尾部
            this.tail = this.tail.previous;
            this.tail.next = null;
        } else {
            let middle = Math.floor(this.length / 2);
            if (position < middle) {
                //从头部向后查找
                let current = this.head;
                //这里要从1开始或者while里面小于position - 1
                let index = 1;
                while (index++ < position) {
                    current = current.next;
                }
                //删除position节点
                current.previous.next = current.next;
                current.next.previous = current.previous;
            } 
            // else if (position >= middle) {
            //     //从头部开始找到中间位置为当前current
            //     let current = this.head;
            //     let index = 0;
            //     while (index++ < middle) {
            //         current = current.next;
            //     }
            //     //从中间位置开始向后查找,直到找到position的节点
            //     while (index++ < position) {
            //         current = current.next;
            //     }
            //     //删除position节点
            //     current.previous.next = current.next;
            //     current.next.previous = current.previous;
            // }
            else if(position > middle){
                //从尾部向前查找
                let current = this.tail;
                let index = this.length - 1;
                while(index-- > position){
                    current = current.previous;
                }
                current.previous.next = current.next;
                current.next.previous = current.previous;
            }
        }
    }
}

3、单向循环链表

class Node{
    constructor(element){
        this.data = element;
        this.next = null;
    }
}
class OneCycleLinkList{
    constructor(){
        this.head = null;
        this.length = 0;
    }
    append(element){
        let node = new Node(element);
        if(this.head == null || this.length == 0){
            this.head = node;
            node.next = this.head;
        }else{
            // console.log(this.head.next);
            let current = this.head;
            while(current.next != this.head){
                current = current.next;
            }
            node.next = this.head;
            current.next = node;
        }
        this.length++;
    }
    insert(element,position){
        if(position < 0 || position > this.length || !Number.isInteger(position)){
            return -1;
        }
        let node = new Node(element);
        if(position == 0){
            if(this.head == null){
                this.head = node;
                node.next = this.head;
            }else{
                node.next = this.head;
                let current = this.head;
                while(current.next != this.head){
                    current = current.next;
                }
                node.next = this.head;
                current.next = node;
                this.head = node;
            }
            this.length++;
        }else if(position == this.length){
            this.append(element);
        }else{
            let current = this.head;
            let index = 0;
            while(index++ < position - 1){
                current = current.next;
                // index++;
            }
            node.next = current.next;
            current.next = node;
            this.length++;
        }
    }
    indexOf(element){
        let current = this.head;
        let index = 0;
        while(index < this.length){
            if(current.data == element){
                return index;
            }
            current = current.next;
            index++;
        }
        return -1;
    }
    removeAt(position){
        if(position < 0 || position > this.length || !Number.isInteger(position)){
            return -1;
        }
        if(position == 0){
            if(this.length == 1){
                this.head = null;
            }else{
                let current = this.head;
                while(current.next != this.head){
                    current = current.next;
                }
                this.head = this.head.next;
                current.next = this.head;
            }
        }else{
            let current = this.head;
            let index = 0;
            while(index++ < position - 1){
                current = current.next;
            }
            current.next = current.next.next;
        }
        this.length--;
    }
    remove(element){
        return this.removeAt(this.indexOf(element));
    }
    toString(){
        let result = '';
        let current = this.head;
        let index = 0;
        while(index++ < this.length){
            result += '-' + current.data;
            current = current.next;
        }
        return result.slice(1);
    }
}

4、双向循环链表

class Node {
    constructor(element) {
        this.data = element;
        this.next = null;
        this.previous = null;
    }
}
class DoubleCycleLinkList {
    constructor() {
        this.length = 0;
        this.head = null;
        this.tail = null;
    }
    append(element) {
        let node = new Node(element);
        if (this.length == 0 || this.head == null) {
            this.head = node;
            this.tail = node;
            node.next = this.head;
            node.previous = this.tail;
        } else {
            node.next = this.head;
            node.previous = this.tail;
            this.head.previous = node;
            this.tail.next = node;
            this.tail = node;
        }
        this.length++;
    }
    insert(element, position) {
        if (position < 0 || position > this.length || !Number.isInteger(position)) {
            return -1;
        }
        let node = new Node(element);
        if (position == 0) {
            if (this.length == 0 || this.head == null) {
                this.head = node;
                this.tail = node;
                node.next = this.head;
                node.previous = this.tail;
            } else {
                node.next = this.head;
                node.previous = this.tail;
                this.head.previous = node;
                this.tail.next = node;
                this.head = node;
            }
            this.length++;
        } else if (position == this.length) {
            this.append(element);
        } else {
            let current = this.head, index = 0;
            while (index++ < position - 1) {
                current = current.next;
            }
            node.next = current.next;
            node.previous = current;
            current.next.previous = node;
            current.next = node;
            this.length++;
        }
    }
    removeAt(position) {
        if (position < 0 || position > this.length - 1 || !Number.isInteger(position)) {
            return -1;
        }
        if (position == 0) {
            if (this.length == 1) {
                this.head = null;
                this.tail = null;
            } else {
                this.tail.next = this.head.next;
                this.head.next.previous = this.tail;
                this.head = this.head.next;
            }
        }else if(position == this.length - 1){
            this.tail = this.tail.previous;
            this.tail.next = this.head;
            this.head.previous = this.tail
        } else {
            let current = this.head;
            let index = 0;
            while (index++ < position) {
                current = current.next;
            }
            current.previous.next = current.next;
            current.next.previous = current.previous;
        }
        this.length--;
    }
    indexOf(element) {
        let index = 0;
        let current = this.head;
        while (index < this.length) {
            if (current.data === element) {
                return index;
            }
            index++;
            current = current.next;
        }
        return -1;
    }
    lastIndexOf(element){
        let index = this.length - 1;
        let current = this.tail;
        while(index >= 0){
            if(current.data === element){
                return index;
            }
            index--;
            current = current.previous;
        }
        return -1;
    }
    remove(element) {
        return this.removeAt(this.indexOf(element));
    }
    toAfterString() {
        let result = '', index = 0, current = this.head;
        while (index++ < this.length) {
            result += '-' + current.data;
            current = current.next;
        }
        return result.slice(1);
    }
    toBeforString() {
        let result = '', index = this.length - 1, current = this.tail;
        while (index-- >= 0) {
            result += '-' + current.data;
            current = current.previous;
        }
        return result.slice(1);
    }
    //将removeAt方法改成首尾查找
    removeAtHalf(position) {
        if (position < 0 || position > this.length || !Number.isInteger(position)) {
            return -1;
        }
        if (position == 0) {
            if (this.length == 1) {
                this.head = null;
                this.tail = null;
            } else {
                this.tail.next = this.head.next;
                this.head.next.previous = this.tail;
                this.head = this.head.next;
            }
        } else {
            let middle = Math.floor(this.length / 2);
            let current,index;
            if (position < middle) {
                index = 0;
                current = this.head;
                while (index++ < position) {
                    current = current.next;
                }
            }else if(position >= middle){
                index = this.length - 1;
                current = this.tail;
                while(index-- > position){
                    current = current.previous;
                }
            }
            current.previous.next = current.next;
            current.next.previous = current.previous;
        }
        this.length--;
    }
}
三、链表运用

例1、使用单向链表实现约瑟夫环

//单向链表:
        function josephRingList(list, num, winNum){
            let oneList = new OneLinkList();
            //依次放入链表
            list.forEach((item)=>{
                oneList.append(item);
            });
            //当链表元素大于两个时游戏还没结束
            while(oneList.length > winNum){
                for(let i = 0; i < num - 1; i++){
                    //将链表头结点数据添加在最后(存活下来的)
                    oneList.append(oneList.head.data);
                    //添加完后将头部数据移除,保证没有重复的
                    oneList.removeAt(0);
                }
                //淘汰的人移除掉
                oneList.removeAt(0);
            }
            return oneList;
        }
        let arr = [];
        ((arr, n)=>{
            for(let i = 1; i <= n; i++){
                arr.push(i);
            }
        })(arr,41);
        console.log(josephRingList(arr,3,2).toString());
        
        

例2、使用单向循环链表实现约瑟夫环

//单向循环链表:
        function josephRingCycleList(list, num, winNum){
            let cycleList = new OneCycleLinkList();
            list.forEach((item)=>{
                cycleList.append(item);
            });
            let count = 1;
            let current = cycleList.head;
            while(cycleList.length > winNum){
                if(count == 3){
                    cycleList.remove(current.data);
                    current = current.next;
                    count = 1;
                }else{
                    current = current.next;
                    count++;
                }
            }
            return cycleList;
        }
        let arr1 = [];
        ((arr1, n)=>{
            for(let i = 1; i <= n; i++){
                arr1.push(i);
            }
        })(arr1,41);
        console.log(josephRingCycleList(arr1,3,2).toString());

例3、单向链表翻转

        function reverseList(list) {
            let previous = null;
            let current = list.head;
            while(current){
                let temp = current.next;
                current.next = previous;
                previous = current;
                current = temp;
            }
            list.head = previous;
            return list;
        }
        let list = new OneLinkList();
        for (let i = 0; i < 10; i++) {
            list.append(i);
        }
        console.log(list.toString());
        console.log(reverseList(list).toString());

例4、单向链表相邻元素交换

        function transListEle(list){
            let previous = new NodeOne(-1);
            let p = previous;
            previous.next = this.head;
            while(previous.next && previous.next.next){
                let temp = previous.next;
                let buffer = previous.next.next;
                previous.next = buffer;
                temp.next = buffer.next;
                buffer.next = temp;
                previous = temp;
            }
            list.head = p.next;
            return list;
        }
        let list = new OneLinkList();
        for(let i = 1; i <= 10; i++){
            list.append(i);
        }
        console.log(list.toString());
        console.log(transListEle(list).toString());

例5、合并单向链表

        let list1 = new OneLinkList();
        list1.append(1);
        list1.append(4);
        list1.append(9);
        list1.append(13);
        console.log('list1:' + list1.toString());
        let list2 = new OneLinkList();
        list2.append(3);
        list2.append(6);
        list2.append(10);
        list2.append(20);
        list2.append(50);
        console.log('list2:' + list2.toString());
        let newList = mergeList(list1, list2);

        function mergeList(list, otherList) {
            let mergeHead = new NodeOne("head"),
                listHead = list.head,
                otherListHead = otherList.head;
            let current = mergeHead;
            while (listHead && otherListHead) {
                if (listHead.data < otherListHead.data) {
                    current.next = listHead;
                    listHead = listHead.next;
                } else {
                    current.next = otherListHead;
                    otherListHead = otherListHead.next;
                }
                current = current.next;
            }

            current.next = listHead || otherListHead;

            return mergeHead.next;
        }
        console.log(newList);

猜你喜欢

转载自blog.csdn.net/qq_42602282/article/details/107456350