约瑟夫环问题--javasciprt 使用数组和链表实现

约瑟夫环问题,这是个很经典的算法题,这算法来历大家可以查百度百科就清楚。

问题描述:N个人围成一圈,从第一个(K=1)开始报数,第M个将被杀掉,最后剩下一个,其余人都将被杀掉。例如N=6,M=5,被杀掉的顺序是:5,4,6,2,3,最后就剩下1

1. 使用数组 

 1 /**
 2  * 
 3  * @param {*} n : 总数 n
 4  * @param {*} k : 起始位置,默认从第一个k=1开始,每一轮结束,下一位从1开始算起
 5  * @param {*} m :第m 个为一次结束
 6  * 
 7  */
 8 function YueSeFuHuan(n=39,k=1,m=3){
 9    let arr = [];
10    for(let i =1;i<=n;i++){
11        arr.push(i)
12    }
13    let index = k-1;//k默认为1,即从第一个人开始,索引为从0开始,所以要减一
14    let size = n;
15    while(size>1){
16     index = (index + m - 1) % size;//关键是这个取模,解决如何找到要删除的那个值的索引
17     let delRes = arr.splice(index,1)
18     // console.log("index",index)
19     console.log( '=>'+delRes)
20     size--
21    }
22    console.log("index",index)
23    console.log("last:"+arr[0])
24 }
25 //1234 =>3  124=>2  14=>4 1=>1
26 console.time("YueSeFuHuan")
27 YueSeFuHuan(4,1,3)
28 console.timeEnd('YueSeFuHuan')
29 console.log("-------------")

2. 使用链表,单向环形链表

(1). 特点: 每一个节点的结构,有属于自己数据的属性,还有一个指向下一个节点的指针标志,这是单向链表,最后一个节点的下一个节点指向第一个节点(头节点),我们称这是一个环形链表,链表的查询性能非常低,但是插入数据和修改数据很快

(2). 约瑟夫环问题 的正符合我们这环形链表的数据结构

 定义一个节点类

class TNode{
    constructor(data){
        this.data = data;//节点的数据
        this.next = null// 指向下一个节点,默认null
    }
}

构建链表

class LoopOneWayList{
    constructor(n=39,k=1,m=3){
        this.n = n;
        this.k = k;
        this.m = m;
        this.init();
    }
    init(){
        let headNode = new TNode(1);//初始首节点
        let currentNode = headNode;
        let p = headNode;//默认开始为首节点
        for(let i=2;i<=this.n;i++){
            let newNode = new TNode(i);
            currentNode.next = newNode;//把当前的节点的下一节点指向新增的节点
            currentNode = newNode;// 把新增的节点重新指向当前节点,依次循环添加节点
            if(i===this.k){//这里是计算出第一次从k(k=1)个开始
                p = currentNode
            }
        }
        currentNode.next = headNode;//最后一个节点的下一个节点指向头节点(首尾相接,形成环形)
        while(p.next!=p){
            for(let i=1;i<this.m-1;i++){
                p = p.next;
            }
            //当 指针已经移动了m次,将改节点移除,直接修改指向
            console.log("=>"+p.next.data) 
            p.next = p.next.next;
            p = p.next;
        }
        console.log(p.next==p)
        console.log("last=>:"+p.data) 
    }

}
//1234 =>4 123=>3 12=>1 2=>2
console.time("LoopOneWayList")
let listNode = new LoopOneWayList(41,1,3)
console.timeEnd('LoopOneWayList')

上面在测试的时候,用了console.time() 方法来测试,在数据量非常大的时候,使用数组的方法比链表的性能要高很多,实际应用中,使用建议使用数组方法,但是链表的这种个人觉得更容易理解,本身它就是一种数据结构和编程思想在里面

原文地址:https://www.cnblogs.com/beyonds/p/13691641.html