我可以在没有公式的情况下完成此任务,但我正在努力创建一个数组选择方法,可以选择我称之为几乎随机的方法。原因是当数组以2的幂增长时,我需要选择一个。数组索引的内容无关紧要。
[0] // select index 0
[0,1] // select index 1 then 0
[0,1,2,3] // 3, 1, 2, 0
[0,1,2,3,4,5,6,7] // 7, 3, 5, 1, 6, 2, 4, 0
[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15] // 15,7,11,3,13,5,9,1,14,6,12,4,10,2,8
我终于想出了这个模式,因为当数组扩展超过2的幂时它不会降级。选择保持不变。这与排序数组无关,而只是按特定顺序选择预排序数组。我已经看了很多可能的解决方案但是已经有一段时间了,因为我已经做了认真的数学运算,我确信这需要。
我能看到的模式并不明显,但我会尝试解释一下。它与二叉树有关。在root上你有[0]
。
[0]
[0,1]
[0,1,2,3]
[0,1,2,3,4,5,6,7]
// for example
___ 20 ___
/ \
10 30
/ \ / \
5 15 25 35
/ \ / \ / \ / \
1 7 12 18 23 27 31 37
我需要创建一个第三个数组,该数组具有正确的插入顺序而不会导致重新平衡。
[20,30,10,35,15,25,5,37,18,27,7,31,12,23,1]
此选择模型继续与Btree一起增长,这会导致树不能通过在自平衡树中插入这些值来重新平衡。
答案 0 :(得分:1)
如果另一个数组实际上是一个AVL树,下面的函数会将一个已排序的数组按顺序推送到另一个数组中。它不是最有效的,但它显示了如何完成它的一个例子。
var sorted = [1, 5, 7, 10, 12, 15, 18, 20, 23, 25, 27, 30, 31, 35, 37];
console.log("sorted: ", sorted)
function insertBalanced(sortedArray, avlTree) {
var size = sortedArray.length;
var result = avlTree;
var indexesUsed = [];
function halfIndexes(depth) {
var slices = Math.pow(2, depth);
for(var i = 1; i < slices;i++) {
var nextIndex = Math.floor(size * i / slices);
if (!indexesUsed.includes(nextIndex)) {
indexesUsed.push(nextIndex);
result.push(sortedArray[nextIndex]);
}
}
if (indexesUsed.length < size) {
halfIndexes(depth + 1);
}
};
return halfIndexes(1);
}
var someEmptyAvlTree = [];
insertBalanced(sorted, someEmptyAvlTree);
console.log("avlTree", someEmptyAvlTree);
答案 1 :(得分:0)
我最终找到了一个更好的休闲模式,这在代码中更容易实现。它也不会降低。我会说DMoses方法也同样重要。我最终发现赔率甚至指数轮换的模式有所帮助。
root 40
/ \
20 60
/ \ / \
10 30 50 70
/ \ / \ / \ / \
5 15 25 35 45 55 65 75
/ \ / \ / \ / \ / \ / \ / \ / \
3 7 12 17 23 27 33 37 43 47 52 57 62 67 72 77
首先将每一行分成一个数组。如果从平衡的BTree中拉出,则阵列已经被排序为最小到最大。
这是我使用的实际代码。
// array holding all elements
const allArray = [[40],[20,60],[10,30,50,70],[5,15,25,35,45,55,65,75],
[3,7,12,17,23,27,33,37,43,47,52,57,62,67,72,77]];
// create sorted reverse index array
const refA = [];
for (let i = 0; i < allArray.length; i++) {
refA.push([]);
for(let j = allArray[i].length - 1; j >= 0; j--) {
refA[i].push(j);
}
}
const fillRefA = (prev: number[], current: number[]): number[] => {
const a = [];
const prefAOdds = prev.filter((val: number) => (val % 2) !== 0);
const prefAEvens = prev.filter((val: number) => (val % 2) === 0);
const currentAOdds = current.filter((val: number) => (val % 2) !== 0);
const currentAEvens = current.filter((val: number) => (val % 2) === 0);
const newAOdds = currentAOdds.filter((val: number) => !prefAOdds.includes(val));
const newAEvens = currentAEvens.filter((val: number) => !prefAEvens.includes(val));
for (let i = 0; i < prefAOdds.length; i++) {
a.push(newAOdds[i]);
a.push(prefAOdds[i]);
}
for (let i = 0; i < prefAOdds.length; i++) {
a.push(newAEvens[i]);
a.push(prefAEvens[i]);
}
return a;
};
for (let i = 2; i < refA.length; i++) {
refA[i] = fillRefA(refA[i - 1], refA[i]);
}
// Then finally put all the arrays into a master array in order of proper insertion.
const final = [];
for (let i = 0; i < allArray.length; i++) {
for (let j = 0; j < allArray[i].length; j++) {
final.push(a[i][refA[i][j]]);
}
}
//为了解释这里发生了什么,我可以展示一个简短的索引路径。
//first you cannot work this method on the first item so you need to start at index of 2
// second you have to break evens and odds up but keep the order of previous insertion
[1,0] // odds [1], evens [0]
[3,2,1,0] // odds [3,1], evens [1,0];
// but extract previous array odds and evens
// so [3], [2]. and you have the previous odds and evens [1], [0]
// and insert them in order, odds then evens.
[3,1,2,0]
// again with the next row
[7,5] [6,4] [3,1] [2,0]
[7,3,5,1,6,2,4,0] // first you take the current then the previous
// and the next row.
[15,13,11,9] [14,12,10,8] [7,3,5,1] [6,2,4,0]
[15,7,13,3,11,5,9,1,14,6,12,4,10,2,8,0]
// This way no same node is on a branch is filled up before all nodes
// on the row at least have 1 filled then continue filling the leftovers.
// final insertion array
[40,60,20,70,30,50,10,75,35,55,15,65,25,45,5,77,37,67,17,57,27,47,
7,72,33,62,23,52,12,43,3]