百度百科:克拉茨问题
bilibili:【数学狂】最容易理解的数学未解之谜 – 克拉茨猜想
实现目标
使用echarts展示树形结构,用户输入某个自然数,将该自然数的树形分支绘制出来。
实现思路
echart需要的树形数据结构
export interface EchartTree {
name: number;
children: EchartTree[];
}
实现一个获取数列的方法,该方法传入一个自然数
type getSequence = (n: number) => number[]
还要再实现一个方法,把获得的数列放到树形结构中。compare是一个引用,根据数列逐层比对树形数据,在需要更新数据的树形节点更新数据。
type setData = (sequence: number[], compare: EchartTree): void
具体实现
export interface EchartTree {
name: number;
children: EchartTree[];
}
export default class CollatzConjectureService {
// 树形数据存到data里
protected data: EchartTree = {
name: 1,
children: [],
};
/**
* 直接将序列放到当前EcharTree节点
* @param s 序列
* @param data 比对的EcharTree节点
*/
protected setDataDirectly(s: number[], data: EchartTree): void {
if (s.length) {
const tmp: EchartTree = {
name: s.shift() as number,
children: [],
};
data.children.push(tmp);
this.setDataDirectly(s, tmp);
}
}
/**
* 将新的数列添加到树中
* @param sequence 序列
* @param compare 和EcharTree节点比对
* @returns
*/
protected setData(sequence: number[], compare: EchartTree): void {
const num = sequence.shift();
if (!num) {
return;
}
// 最多找到一个
const find = compare.children.find((v) => v.name === num);
if (find) {
// 如果找到了就继续往深处找
this.setData(sequence, find);
} else {
// 如果没找到,直接将剩下的序列放到当前节点
sequence.unshift(num);
this.setDataDirectly(sequence, compare);
}
}
getData(): EchartTree {
return this.data;
}
/**
* 获取数列,并将新的数列添加到树中
* @param n 传入自然数
* @returns
*/
getSequence(n: number): number[] {
if (!isNaN(n) && n > 0 && n % 1 === 0) {
let result = n;
const sequence: number[] = [n];
// 直到算到1为止
while (result !== 1) {
if (result % 2 === 0) {
result = result / 2;
} else {
result = result * 3 + 1;
}
sequence.unshift(result);
}
// 更新树形结构
this.setData(sequence.slice(0), { name: 0, children: [this.data] });
return sequence;
} else {
throw new Error("请传入自然数");
}
}
}
<template>
<div>
<input v-model="value" />
<button @click="setData">set</button>
<div id="main" />
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import CollatzConjectureService, {
EchartTree,
} from "@/service/CollatzConjectureService";
import * as echarts from "echarts";
const service = new CollatzConjectureService();
export default defineComponent({
name: "Test",
data() {
return {
value: 1,
};
},
mounted() {
// 设置一些初始数据
console.log(service.getSequence(32));
console.log(service.getSequence(5));
console.log(service.getSequence(20));
console.log(service.getSequence(3));
console.log(service.getSequence(80));
console.log(service.getSequence(13));
this.draw(service.getData());
},
methods: {
setData() {
let n = Number(this.value);
service.getSequence(n);
this.draw(service.getData());
},
draw(data: EchartTree) {
// 基于准备好的dom,初始化echarts实例
const myChart = echarts.init(
document.getElementById("main") as HTMLElement
);
// 绘制图表
myChart.setOption({
tooltip: {
trigger: "item",
triggerOn: "mousemove",
},
series: [
{
type: "tree",
data: [data],
initialTreeDepth: -1,
left: "2%",
right: "2%",
top: "20%",
bottom: "8%",
symbol: "emptyCircle",
orient: "BT",
expandAndCollapse: true,
label: {
position: "bottom",
rotate: 90,
verticalAlign: "middle",
align: "right",
},
leaves: {
label: {
position: "top",
rotate: 90,
verticalAlign: "middle",
align: "left",
},
},
emphasis: {
focus: "descendant",
},
animationDurationUpdate: 750,
},
],
});
},
},
});
</script>
<style scoped>
#main {
width: 100%;
height: 600px;
}
</style>
输出效果