美好的一天,我正在尝试使用Big-O来提高自己的能力,我编写了Java算法将一棵树打印到控制台上。
public static void printTree(Tree tree){
int height = getHeight(tree);
int maxWidth = (int)Math.pow(2, height) - 1;
HashMap<Coordinate, Integer> coordinates = getTreeCoordinates(tree, maxWidth/(int)Math.pow(2, 1) + 1, 1, maxWidth);
printCoordinatesToConsole(coordinates, maxWidth, height);
}
static void printCoordinatesToConsole(HashMap<Coordinate, Integer> coordinates, int width, int height){
for (int j = 1; j <= height; j++){
for (int i = 1; i <= width; i++){
if (coordinates.containsKey(new Coordinate(i, j)))
System.out.print(coordinates.get(new Coordinate(i, j)));
else
System.out.print(' ');
}
System.out.print("n\n");
}
}
static HashMap<Coordinate, Integer> getTreeCoordinates(Tree tree, int x, int y, int maxWidth){
HashMap<Coordinate, Integer> result = new HashMap<>();
result.put(new Coordinate(x, y), tree.data);
if (tree.left == null && tree.right == null){
return result;
}
else if (tree.left == null){
result.putAll(getTreeCoordinates(tree.right, x+maxWidth/(int)Math.pow(2, y+1) + 1, y+1, maxWidth));
return result;
}
else if (tree.right == null){
result.putAll(getTreeCoordinates(tree.left, x-maxWidth/(int)Math.pow(2, y+1) - 1, y+1, maxWidth));
return result;
}
else{
result.putAll(getTreeCoordinates(tree.right, x+maxWidth/(int)Math.pow(2, y+1) + 1, y+1, maxWidth));
result.putAll(getTreeCoordinates(tree.left, x-maxWidth/(int)Math.pow(2, y+1) - 1, y+1, maxWidth));
return result;
}
}
据我所知,复杂度基于:
1。查找树高O(n)
2。将哈希表中所有元素的坐标存储为O(n)
3。将坐标打印到屏幕O(宽*高)
现在,由于宽度为2 ^ h,在最坏的情况下为n,这是否意味着时间复杂度为O(n * 2 ^ n)?另外,如果我忽略打印(或者如果我直接在控制台上打印到坐标,而不是遍历所有宽度/高度),那么复杂度将为O(n)
谢谢!
答案 0 :(得分:1)
如果getHeight大于或小于以下值,则将为O(n),其中n是树中的节点数:
static int getHeight(Tree tree) {
if (tree == null) {
return 0;
}
return 1 + max(getHeight(tree.left, tree.right));
}
getTreeCoordinates
= O(height
* n),但可以将其改进为O(n)。 O(HashMap.putAll
)从技术上取决于实现,但是几乎可以肯定,元素数量是线性的!除了使用HashMap.putAll
,您还可以将HashMap
传递给递归调用,例如:
static HashMap<Coordinate, Integer> getTreeCoordinates(Tree tree, int x, int y, int maxWidth){
HashMap<Coordinate, Integer> result = new HashMap<>();
return getTreeCoordinatesImpl(tree, x, y, maxWidth, result);
}
static void getTreeCoordinatesImpl(Tree tree, int x, int y, int maxWidth, HashMap<Coordinate, Integer> result){
result.put(new Coordinate(x, y), tree.data);
if (tree.right != null){
getTreeCoordinatesImpl(tree.right, x+maxWidth/(int)Math.pow(2, y+1) + 1, y+1, maxWidth, result);
}
if (tree.left != null){
getTreeCoordinatesImpl(tree.left, x-maxWidth/(int)Math.pow(2, y+1) - 1, y+1, maxWidth, result);
}
}
height
* width
)。如果您在HashMap而不是所有(x,y)坐标上进行迭代,则将为O(n),其中n是节点数,即树。 O({HashMap.containsKey
)和O(HashMap.get
)均为1(恒定时间)。确切地说,它们是按时间摊销的,平均而言,它们花费的时间是恒定的,但是在极少数情况下,一次运行就可以使哈希映射的元素数量呈线性关系。
在大O表示法中,所有常量都等效(O(1)等于O(2))。所以:
O(printCoordinatesToConsole
)=
O({height
)* O(width
)*(O(HashMap.containsKey
)+ O(HashMap.get
))=
O({height
)* O(width
)* O(1)=
O(height
* width
)
现在,由于宽度为2 ^ h,在最坏的情况下为n,这是否意味着时间复杂度为O(n * 2 ^ n)?
让我们进行数学运算(n是树中的节点数,我假设getTreeCoordinates
的编辑如上所述):
O(printTree
)=
O({getHeight
)+ O(getTreeCoordinates
)+ O(printCoordinatesToConsole
)=
O(n)+ O(n)+ O(height
* width
)
由于height
* width
> = n:
O({printTree
)= O(height
* width
)
此外,如果我忽略打印(或者如果我直接打印到控制台上的坐标而不是遍历所有宽度/高度),那么复杂度将为O(n)
是的,那么上面的等式变为(不打印):
O({printTree
)= O(getHeight
)+ O(getTreeCoordinates
)= O(n)+ O(n)= O(n)
或(在节点的哈希图上迭代打印):
O({printTree
)= O(getHeight
)+ O(getTreeCoordinates
)+ O(n)= O(n)
如果包含Tree
,Coordinate
和getHeight
的定义,以及tree
的内容(如果适用),将很有帮助。您还可以使用ideone.com之类的在线游乐场来提供可运行的示例。