我的树类:
public class BT<E>{
E value;
BT<E> left, right;
public BT(E value)
{
this.value=value;
}
public BT (E value, BT left, BT right)
{
this.value = value;
this.left = left;
this.right = right;
}
在生成树后,如何从树中返回随机节点?我知道我生成的每棵树的节点的深度和数量。
答案 0 :(得分:6)
因此,使用Random Integer方法并返回0和树大小之间的整数。
然后在树上进行广度/深度优先遍历,使用计数器,当节点到达随机整数时返回该节点。
Random rand = new Random();
int randomNum = rand.nextInt(treesize);
int count = -1;
Node randNode;
public static void getRandomTraversal(Node root){
count++;
if(count == randomNum)
randNode = root;
if(root.leftChild != null)
getRandomTraversal(root.leftChild);
if(root.rightChild != null)
getRandomTraversal(root.rightChild);
}
或者,您可以将count删除为全局,并将其作为参数添加到递归函数中。虽然当树有多个孩子时,二元树就不那么容易了。
答案 1 :(得分:4)
Dennis和Jeroen的算法很容易实现,但O(n)
。我相信我的O(log n)
算法稍微复杂一些。
每个节点都需要有相同的选择机会。因此,在某个树T
,让LN(T)
为左树中的节点数,RN(T)
为右树中的节点数,N(T)
为数字总节点数,包括这个节点(所以N(T) = 1 + LN(T) + RN(T)
)。从R
中选择一个随机数0 to N(T) - 1
。如果R == 0
,则返回此节点。如果是1 <= R <= LT(N)
,请在左子树上递归此方法。否则,请在右子树上递归此方法。
未经测试的代码(假设BT
的{{1}}方法适用于.size()
):
O(1)
当然,您可以执行诸如将public BT randomNode() {
int r = new Random().nextInt(this.size());
if (r == 0) {
return this;
} else if (left != null && 1 <= r && r <= left.size()) {
return left.randomNode();
} else {
return right.randomNode();
}
}
提升出方法之类的操作,但算法是相同的。
编辑:当左子树为空时修复空指针异常。
答案 2 :(得分:3)
new Random().nextInt(numberOfNodes)
)答案 3 :(得分:0)
问题也出在书<Cracking the coding interview 6th>
的{{1}}部分| IX Interview Questions
| 4. Trees and graphs
。
(这是Google的一位软件工程师Question 4.11
写的一本好书,他采访了很多人。)
(A)决定随机数,并记录子树大小。
逻辑:
Impl二叉树节点。
简单的二叉树,最好是BST。
BSTNode getRandomNode(BSTNode当前,整数兰特)
比较rand与子树大小:
Gayle Laakmann McDowell
Node<T> left = current.getLeft(); // left,
int leftSize = (left == null ? 0 : left.getSize()); // get size of left subtree,
if (rand == leftSize) return current; // current is chosen,
if (rand < leftSize) return randomNode(current.getLeft(), rand); // call on left subtree recursively,
else return randomNode(current.getRight(), rand - leftSize - 1); // call on right subtree recursively,
。[0, size)
,并获得随机节点。复杂度:
getRandomNode(tree.getRoot(), rand)
O(h)
,(方法堆栈使用O(1)
)位置:
O(h)
是树高。(B)放入列表,可通过随机索引访问。
逻辑:
h
范围内的随机索引,然后在给定索引处获取节点。复杂度:
时间:[0, size)
(如果树是静态的)
空格:O(1)
位置:
O(n)
是树的大小。提示:
n
。O(n)
,但是在数组调整大小时,它是O(1)
。比较2种算法:
O(n)
使用较少的内存,并且运行速度更快。肯定是赢家。A
,在建立数组之后,在循环时它可能会更快。 (以下是在B
中使用上述算法Java
和测试用例的实现。)
RandomBST.java
A
RandomBSTTest.java (部分)
(单元测试,通过import java.util.concurrent.ThreadLocalRandom;
/**
* Random BST impl.
*
* @param <T>
* @author eric
* @date 2/10/19 5:02 PM
*/
public class RandomBST<T extends Comparable> extends BST<T> implements RandomBSTDesign<T> {
@Override
public void add(T v) {
root = add((RandomBSTNode<T>) root, v, (RandomBSTNode<T>) root);
}
/**
* Add to a subtree start from given node.
*
* @param current root of a subtree to add node to,
* @param currentParent parent of current,
* @param v
* @return the new root of subtree,
*/
protected RandomBSTNode<T> add(RandomBSTNode<T> current, T v, RandomBSTNode<T> currentParent) {
if (current == null) { // subtree is empty,
RandomBSTNode<T> newNode = new RandomBSTNode<>(v, currentParent); // create new node,
newNode.incSizeOfParents(); // increase size of parents,
size++;
return newNode;
}
// compare,
int compareFlag = v.compareTo(current.value);
// check this or subtree,
if (compareFlag < 0) { // smaller, go to left subtree,
current.left = add(current.getLeft(), v, current);
} else if (compareFlag > 0) { // larger, go to right subtree,
current.right = add(current.getRight(), v, current);
} else { // equals, ignore it,
}
return current;
}
@Override
protected RandomBSTNode<T> delete(BSTNode<T> current, T v) {
return delete((RandomBSTNode<T>) current, v); // cast to subtype to call another method,
}
/**
* Delete given value in subtree, if any.
*
* @param current
* @param v
* @return new root of the subtree
*/
protected RandomBSTNode<T> delete(RandomBSTNode<T> current, T v) {
if (current == null) return null;
// compare,
int compareFlag = v.compareTo(current.value);
// check this or subtree,
if (compareFlag < 0) { // smaller, go to left subtree,
current.left = delete(current.left, v);
} else if (compareFlag > 0) { // larger, go to right subtree,
current.right = delete(current.right, v);
} else { // equals, delete it,
// no child,
if (current.left == null && current.right == null) {
current.decSizeOfParents(); // decrease size of parents,
size--;
return null;
}
// one child - right,
if (current.left == null) {
current.decSizeOfParents(); // decrease size of parents,
size--;
RandomBSTNode<T> randomRight = current.getRight(); // cast to subtype,
randomRight.parent = current.parent;
return randomRight;
}
// one child - left,
if (current.right == null) {
current.decSizeOfParents(); // decrease size of parents,
size--;
RandomBSTNode<T> randomLeft = (RandomBSTNode<T>) current.left; // cast to subtype,
randomLeft.parent = current.parent;
return randomLeft;
}
// 2 child,
T smallestInRight = findSmallestValue(current.right);
current.value = smallestInRight; // replace current with smallest in right subtree,
current.right = delete(current.right, smallestInRight); // delete original smallest value in right subtree,
}
return current;
}
@Override
public RandomBSTNode<T> getRoot() {
return (RandomBSTNode<T>) root;
}
@Override
public T randomValue() {
if (size == 0) return null; // empty tree,
int rand = ThreadLocalRandom.current().nextInt(size); // random value,
RandomBSTNode rnode = randomNode(getRoot(), rand); // get random node,
// System.out.printf("rand = %d, random node: %s\n", rand, rnode);
return rnode == null ? null : (T) rnode.value;
}
protected RandomBSTNode randomNode(RandomBSTNode<T> current, int rand) {
RandomBSTNode<T> left = current.getLeft(); // left,
int leftSize = (left == null ? 0 : left.getSize()); // get size of left subtree,
if (rand == leftSize) return current; // current is chosen,
if (rand < leftSize) return randomNode(current.getLeft(), rand); // call on left subtree recursively,
else return randomNode(current.getRight(), rand - leftSize - 1); // call on right subtree recursively,
}
/**
* Random BST node impl.
*
* @param <T>
*/
static class RandomBSTNode<T extends Comparable> extends BSTNode<T> implements RandomBSTNodeDesign<T> {
protected int size; // size of subtree which has this node as root,
protected RandomBSTNode<T> parent; // parent of this node, or null if this is root,
public RandomBSTNode(T value, RandomBSTNode<T> parent) {
this(value, 1, parent); // on creation, got size 1,
}
public RandomBSTNode(T value, int size, RandomBSTNode<T> parent) {
super(value);
this.size = size;
this.parent = parent;
}
@Override
public int incSize() {
return ++size;
}
@Override
public int decSize() {
return --size;
}
@Override
public void incSizeOfParents() {
RandomBSTNode<T> pn = parent;
while (pn != null) {
pn.incSize();
pn = pn.parent;
}
}
@Override
public void decSizeOfParents() {
RandomBSTNode<T> pn = parent;
while (pn != null) {
pn.decSize();
pn = pn.parent;
}
}
@Override
public boolean isRoot() {
return parent == null;
}
@Override
public RandomBSTNode<T> getLeft() {
return (RandomBSTNode<T>) left;
}
@Override
public RandomBSTNode<T> getRight() {
return (RandomBSTNode<T>) right;
}
@Override
public int getSize() {
return size;
}
@Override
public RandomBSTNode getParent() {
return parent;
}
@Override
protected void appendMoreToString(StringBuilder sb) {
sb.append(", size = ").append(size); // size,
sb.append(", parent value = ").append(parent == null ? null : parent.getValue()); // parent,
}
/*------ unsupported methods ------*/
@Override
void setLeft(BSTNode<T> left) {
throw new UnsupportedOperationException("Should not set subtree directly, because size is difficult to maintain.");
}
@Override
void setRight(BSTNode<T> right) {
throw new UnsupportedOperationException("Should not set subtree directly, because size is difficult to maintain.");
}
}
}
)
TestNG
(所有测试用例都会通过。)
测试方法import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Consumer;
/**
* RandomBST test.
*
* @author eric
* @date 2/10/19 5:50 PM
*/
public class RandomBSTTest {
private int n = 100;
private int avgRound = (1 << 18); // avg round for each node, when get random value,
private RandomBST<Integer> mbst; // minimal BST,
private RandomBST<Integer> ebst; // empty BST,
@BeforeMethod
public void init() {
// init minimal BST,
mbst = CreateMinimalBST.createRandomFromNumRange(0, n);
// init empty BST,
ebst = new RandomBST<>();
}
// other non-random related test cases are removed,
// randomValue()
@Test
public void testRandomValue() {
int round = n * avgRound; // total round,
System.out.printf("tree size: %d, total round: %d, result:\n", n, round);
Map<Integer, Integer> freqMap = new LinkedHashMap<>();
// init map,
for (int i = 0; i < n; i++) {
freqMap.put(i, 0);
}
// get random value & count frequency,
for (int i = 0; i < round; i++) {
int rv = mbst.randomValue();
freqMap.put(rv, freqMap.get(rv) + 1);
}
double avgPercentage = 100 / n; // average percentage,
// print result,
for (int x : freqMap.keySet()) {
int freq = freqMap.get(x);
double percentage = freq * 100.0 / round;
double diffPercentage = percentage - avgPercentage;
System.out.printf("\trandom value: %2d, chosen count: %d, percentage: %.4f %%, differ: %.4f %%\n", x, freq, percentage, diffPercentage);
Assert.assertTrue(Math.abs((freq - avgRound) * 1.0 / avgRound) <= 0.01); // differ <= 0.01, means <= 1 / 100,
}
// empty tree,
Assert.assertNull(ebst.randomValue());
}
}
的输出:
tree size: 100, total round: 26214400, result: random value: 0, chosen count: 262162, percentage: 1.0001 %, differ: 0.0001 % random value: 1, chosen count: 262166, percentage: 1.0001 %, differ: 0.0001 % random value: 2, chosen count: 262897, percentage: 1.0029 %, differ: 0.0029 % random value: 3, chosen count: 261887, percentage: 0.9990 %, differ: -0.0010 % random value: 4, chosen count: 262428, percentage: 1.0011 %, differ: 0.0011 % random value: 5, chosen count: 262094, percentage: 0.9998 %, differ: -0.0002 % random value: 6, chosen count: 261662, percentage: 0.9982 %, differ: -0.0018 % random value: 7, chosen count: 262034, percentage: 0.9996 %, differ: -0.0004 % random value: 8, chosen count: 261218, percentage: 0.9965 %, differ: -0.0035 % random value: 9, chosen count: 262054, percentage: 0.9997 %, differ: -0.0003 % random value: 10, chosen count: 261821, percentage: 0.9988 %, differ: -0.0012 % random value: 11, chosen count: 262401, percentage: 1.0010 %, differ: 0.0010 % random value: 12, chosen count: 262056, percentage: 0.9997 %, differ: -0.0003 % random value: 13, chosen count: 262119, percentage: 0.9999 %, differ: -0.0001 % random value: 14, chosen count: 261878, percentage: 0.9990 %, differ: -0.0010 % random value: 15, chosen count: 262191, percentage: 1.0002 %, differ: 0.0002 % random value: 16, chosen count: 261224, percentage: 0.9965 %, differ: -0.0035 % random value: 17, chosen count: 262471, percentage: 1.0012 %, differ: 0.0012 % random value: 18, chosen count: 261906, percentage: 0.9991 %, differ: -0.0009 % random value: 19, chosen count: 262752, percentage: 1.0023 %, differ: 0.0023 % random value: 20, chosen count: 262762, percentage: 1.0024 %, differ: 0.0024 % random value: 21, chosen count: 262245, percentage: 1.0004 %, differ: 0.0004 % random value: 22, chosen count: 261942, percentage: 0.9992 %, differ: -0.0008 % random value: 23, chosen count: 262339, percentage: 1.0007 %, differ: 0.0007 % random value: 24, chosen count: 262266, percentage: 1.0005 %, differ: 0.0005 % random value: 25, chosen count: 261584, percentage: 0.9979 %, differ: -0.0021 % random value: 26, chosen count: 263036, percentage: 1.0034 %, differ: 0.0034 % random value: 27, chosen count: 261412, percentage: 0.9972 %, differ: -0.0028 % random value: 28, chosen count: 262305, percentage: 1.0006 %, differ: 0.0006 % random value: 29, chosen count: 261236, percentage: 0.9965 %, differ: -0.0035 % random value: 30, chosen count: 261681, percentage: 0.9982 %, differ: -0.0018 % random value: 31, chosen count: 262829, percentage: 1.0026 %, differ: 0.0026 % random value: 32, chosen count: 262411, percentage: 1.0010 %, differ: 0.0010 % random value: 33, chosen count: 263766, percentage: 1.0062 %, differ: 0.0062 % random value: 34, chosen count: 262448, percentage: 1.0012 %, differ: 0.0012 % random value: 35, chosen count: 262074, percentage: 0.9997 %, differ: -0.0003 % random value: 36, chosen count: 261986, percentage: 0.9994 %, differ: -0.0006 % random value: 37, chosen count: 261971, percentage: 0.9993 %, differ: -0.0007 % random value: 38, chosen count: 262403, percentage: 1.0010 %, differ: 0.0010 % random value: 39, chosen count: 261510, percentage: 0.9976 %, differ: -0.0024 % random value: 40, chosen count: 262020, percentage: 0.9995 %, differ: -0.0005 % random value: 41, chosen count: 262410, percentage: 1.0010 %, differ: 0.0010 % random value: 42, chosen count: 261910, percentage: 0.9991 %, differ: -0.0009 % random value: 43, chosen count: 262240, percentage: 1.0004 %, differ: 0.0004 % random value: 44, chosen count: 261923, percentage: 0.9992 %, differ: -0.0008 % random value: 45, chosen count: 261856, percentage: 0.9989 %, differ: -0.0011 % random value: 46, chosen count: 262708, percentage: 1.0022 %, differ: 0.0022 % random value: 47, chosen count: 262695, percentage: 1.0021 %, differ: 0.0021 % random value: 48, chosen count: 262882, percentage: 1.0028 %, differ: 0.0028 % random value: 49, chosen count: 262596, percentage: 1.0017 %, differ: 0.0017 % random value: 50, chosen count: 262872, percentage: 1.0028 %, differ: 0.0028 % random value: 51, chosen count: 262343, percentage: 1.0008 %, differ: 0.0008 % random value: 52, chosen count: 261969, percentage: 0.9993 %, differ: -0.0007 % random value: 53, chosen count: 261301, percentage: 0.9968 %, differ: -0.0032 % random value: 54, chosen count: 262206, percentage: 1.0002 %, differ: 0.0002 % random value: 55, chosen count: 261923, percentage: 0.9992 %, differ: -0.0008 % random value: 56, chosen count: 262577, percentage: 1.0017 %, differ: 0.0017 % random value: 57, chosen count: 262308, percentage: 1.0006 %, differ: 0.0006 % random value: 58, chosen count: 262600, percentage: 1.0017 %, differ: 0.0017 % random value: 59, chosen count: 261682, percentage: 0.9982 %, differ: -0.0018 % random value: 60, chosen count: 261983, percentage: 0.9994 %, differ: -0.0006 % random value: 61, chosen count: 262450, percentage: 1.0012 %, differ: 0.0012 % random value: 62, chosen count: 263582, percentage: 1.0055 %, differ: 0.0055 % random value: 63, chosen count: 261755, percentage: 0.9985 %, differ: -0.0015 % random value: 64, chosen count: 262773, percentage: 1.0024 %, differ: 0.0024 % random value: 65, chosen count: 261581, percentage: 0.9979 %, differ: -0.0021 % random value: 66, chosen count: 262071, percentage: 0.9997 %, differ: -0.0003 % random value: 67, chosen count: 262053, percentage: 0.9997 %, differ: -0.0003 % random value: 68, chosen count: 261491, percentage: 0.9975 %, differ: -0.0025 % random value: 69, chosen count: 261840, percentage: 0.9988 %, differ: -0.0012 % random value: 70, chosen count: 261837, percentage: 0.9988 %, differ: -0.0012 % random value: 71, chosen count: 262293, percentage: 1.0006 %, differ: 0.0006 % random value: 72, chosen count: 261928, percentage: 0.9992 %, differ: -0.0008 % random value: 73, chosen count: 260978, percentage: 0.9956 %, differ: -0.0044 % random value: 74, chosen count: 262260, percentage: 1.0004 %, differ: 0.0004 % random value: 75, chosen count: 262151, percentage: 1.0000 %, differ: 0.0000 % random value: 76, chosen count: 262981, percentage: 1.0032 %, differ: 0.0032 % random value: 77, chosen count: 261602, percentage: 0.9979 %, differ: -0.0021 % random value: 78, chosen count: 261938, percentage: 0.9992 %, differ: -0.0008 % random value: 79, chosen count: 262335, percentage: 1.0007 %, differ: 0.0007 % random value: 80, chosen count: 262213, percentage: 1.0003 %, differ: 0.0003 % random value: 81, chosen count: 262336, percentage: 1.0007 %, differ: 0.0007 % random value: 82, chosen count: 262356, percentage: 1.0008 %, differ: 0.0008 % random value: 83, chosen count: 261782, percentage: 0.9986 %, differ: -0.0014 % random value: 84, chosen count: 262610, percentage: 1.0018 %, differ: 0.0018 % random value: 85, chosen count: 261772, percentage: 0.9986 %, differ: -0.0014 % random value: 86, chosen count: 261874, percentage: 0.9990 %, differ: -0.0010 % random value: 87, chosen count: 262319, percentage: 1.0007 %, differ: 0.0007 % random value: 88, chosen count: 262144, percentage: 1.0000 %, differ: 0.0000 % random value: 89, chosen count: 261808, percentage: 0.9987 %, differ: -0.0013 % random value: 90, chosen count: 261980, percentage: 0.9994 %, differ: -0.0006 % random value: 91, chosen count: 261742, percentage: 0.9985 %, differ: -0.0015 % random value: 92, chosen count: 261994, percentage: 0.9994 %, differ: -0.0006 % random value: 93, chosen count: 262365, percentage: 1.0008 %, differ: 0.0008 % random value: 94, chosen count: 261954, percentage: 0.9993 %, differ: -0.0007 % random value: 95, chosen count: 261660, percentage: 0.9982 %, differ: -0.0018 % random value: 96, chosen count: 263220, percentage: 1.0041 %, differ: 0.0041 % random value: 97, chosen count: 261049, percentage: 0.9958 %, differ: -0.0042 % random value: 98, chosen count: 262000, percentage: 0.9995 %, differ: -0.0005 % random value: 99, chosen count: 262692, percentage: 1.0021 %, differ: 0.0021 % =============================================== Default Suite Total tests run: 1, Failures: 0, Skips: 0 ===============================================
相关的类和界面:
testRandomValue()
是一个简单的二叉树实现。 BST
是BSTNode
的节点隐含,包含字段:BST
/ value
/ left
。
right
是RandomBSTDesign
的界面。
RandomBST
是RandomBSTDesign$RandomBSTNodeDesign
的界面。
RandomBST$RandomBSTNode
是随机的隐含实现,扩展了RandomBST
,主要覆盖了add()/ delete()方法以维护BST
/ parent
字段。 / p>
size
是RandomBST$RandomBSTNode
的节点隐含,扩展RandomBST
并添加字段:BSTNode
/ parent
。
size
是一个工具,可帮助构建最小高度的二进制搜索树。