最近楼主在看麦克米伦的《数据结构与算法JavaScript描述》一书,其中链表有个习题挺有趣,内容是这样的:
传说在公元1世纪的犹太战争中,犹太历史学家弗拉维奥·约瑟夫斯和他的40个同胞被罗马士兵包围。犹太士兵决定宁可自杀也不做俘虏,于是商量出了一个自杀方案。他们围成一个圈,从一个人开始,数到第三个人时将第三个人杀死,然后再数,直到杀光所有人。约瑟夫和另外一个人决定不参加这个疯狂的游戏,他们快速地计算出了两个位置,站在那里得以幸存。写一段程序将n个人围成一圈,并且第m个人会被杀掉,计算一圈人中哪两个人最后会存活。使用循环链表解决该问题
于是决定实现一下:全文源码如下
<template> <div id="testActivity" class="main"> <el-form :model="form" class="demo-form-inline"> <el-form-item label=""> <el-input v-model="form.value" placeholder="请输入要排队的序列,以逗号分隔" clearable @input="inputChange" /> </el-form-item> <el-form-item label=""> <el-input v-model="form.delValue" placeholder="请输入从第几个开始删" clearable @input="delValueChange" /> </el-form-item> <el-form-item> <el-button type="primary" @click="onSubmit">计算</el-button> </el-form-item> <p v-if="result">剩下的是:{{ result }}</p> </el-form> </div> </template> <script> var person = [] // 存放队列 var len = 3 // 从第几个开始删,默认第3个 // 替换中文逗号 function ReplaceChina(obj) { while (obj.indexOf(',') !== -1) { obj = obj.replace(/,/ig, ',') } return obj } // LList类提供了对链表进行操作的方法。该类的功能包括插入删除节点、在列表中查找给定的值 function LList() { this.head = new Node('head') this.head.next = this.head this.find = find this.insert = insert this.display = display this.findPrevious = findPrevious this.remove = remove } // Node类包含两个属性:element用来保存节点上的数据,next用来保存指向下一个节点的链接 function Node(element) { this.element = element this.next = null } // 从链表中删除节点时,需要先找到待删除节点前面的节点。找到这个节点后,修改它的next属性,使其不再指向待删除节点,而是指向待删除节点的下一个节点。 function findPrevious(item) { var currNode = this.head while (currNode.next.element !== item) { currNode = currNode.next } return currNode } // 显示结果 function display() { var currNode = this.head const arr = [] while (currNode.next.element !== 'head') { arr.push(currNode.next.element) currNode = currNode.next } return arr } // 辅助方法find(),该方法遍历链表,查找给定数据 function find(item) { var currNode = this.head while (currNode.element !== item) { currNode = currNode.next } return currNode } // 插入一个节点 // 将新节点的next属性设置为“后面”节点的next属性对应的值。然后设置“后面”节点的next属性指向新节点 function insert(newElement, item) { var newNode = new Node(newElement) var current = this.find(item) newNode.next = current.next current.next = newNode } // 删除方法 function remove(item) { var prevNode = this.findPrevious(item) // 上一个节点 let nextDel = prevNode.next // 下一个需要删除的节点 prevNode.next = prevNode.next.next // 删除item节点(把item上一个节点的指针指向item的下一个节点,即删除了item) let i = 0 while (i < len) { // 找到第len个的元素,即下次要删除的节点 if (nextDel.next.element === 'head') { // 如果到了最开头,则向后移一位,并退出此次循环,并不累计i的值 nextDel = nextDel.next continue } nextDel = nextDel.next i++ } return nextDel // 返回下次要删除的节点 } export default { name: 'TestActivity', data() { return { form: { value: '', delValue: '' }, result: '', person: [] } }, mounted() { }, methods: { delValueChange(val) { len = Number(val) // 格式化为数值类型 }, inputChange(val) { person = val.split(',')// 把字符串存入队列数组 }, // 点击计算按钮,开始计算 onSubmit() { // 一些校验 if (!this.form.value || !this.form.delValue) { this.$alertMessage('error', '请输入必填项') return } const timesString = ReplaceChina(this.form.value) // 替换中文分号 person = timesString.split(',') if (this.form.delValue > person.length) { this.$alertMessage('error', '开始删除的位置不能大于队列总数') return } const first = 'head' let i = 0 const cities = new LList() // 实例化一个实例 // 把person数组放入cities链表 while (i < person.length) { if (i === 0) { cities.insert(person[0], first) } else { const j = i - 1 cities.insert(person[i], person[j]) } i++ } // 显示当前排队情况 cities.display() const length = len - 1 let delName = person[length] // 当前要删掉的节点 // 循环去删掉节点,留下最后2个 while (person.length > 2) { delName = cities.remove(delName).element person = cities.display() this.result = person.join(',')// 最后的结果 } } } } </script> <style scoped> .main{ padding: 20px ; } </style>
因为只是简单实现一下功能,所以代码还有很多不完善的地方,大佬轻喷哈~