一点一点前进...

0%

利用二叉查找树快速查询x的排位

问题:你正在读一个整数数据流。在读的过程中,你可能需要要知道某个值x在已读数据的排位,实现这个功能。也就是说,你需要实现一个方法track(int x),每读入一个整数,就会调用一次该方法。实现方法getRankOfNumber(int x),返回小于等于x的值的数量。

简单的方式,维护一个有序的数组。getRankOfNumber方法很高效,二分查找就好了。但是track方法很慢,插入到合适的地方,可能要移动很多元素。

换种数据结构,二分查找树。track复杂度是log(n),平均情况,而且我们可以假设数据流是随机的,树大致平衡。getRankOfNumber方法的效率就不高了,需要中序遍历,得到x的排序。
想一想,如果x比某个节点的值还小的话,其实就不用去遍历左边的子树了,因为左边的都比x小。所以,我们往节点里面添加一个值,记录该节点左边有多少个节点。这样就不用遍历左边的子树,直接加上这个值就可以了。

下面是完整的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
private static RankNode root = null;

public static void Track(int number)
{
if (root == null)
{
root = new RankNode(number);
}
else
{
root.Insert(number);
}
}

public static int GetRankOfNumber(int number)
{
return root.GetRank(number);
}

class RankNode
{
public int LeftSize { get; set; }
public RankNode Left { get; set; }
public RankNode Right { get; set; }
public int Data { get; set; }

public RankNode(int d)
{
this.Data = d;
}


public int GetRank(int d)
{
if (d == this.Data)
{
return this.LeftSize;
}
else if (d < this.Data)
{
if (this.Left == null)
{
return -1;
}
else
{
return this.Left.GetRank(d);
}
}
else
{
int rightRank = this.Right == null ? -1 : this.Right.GetRank(d);
if (rightRank == -1)
{
return -1;
}
else
{
return this.LeftSize + 1 + rightRank;
}
}
}

public void Insert(int d)
{
if (d <= this.Data)
{
if (this.Left == null)
{
this.Left = new RankNode(d);
}
else
{
this.Left.Insert(d);
}

this.LeftSize++;
}
else
{
if (this.Right == null)
{
this.Right = new RankNode(d);
}
else
{
this.Right.Insert(d);
}
}
}
}