该算法的时间复杂度是多少?

时间:2019-05-09 05:16:27

标签: java algorithm performance data-structures big-o

美好的一天,我正在尝试使用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)

谢谢!

1 个答案:

答案 0 :(得分:1)

  1. 发现树的高度为O(n)。

如果getHeight大于或小于以下值,则将为O(n),其中n是树中的节点数:

static int getHeight(Tree tree) {
    if (tree == null) {
        return 0;
    }

    return 1 + max(getHeight(tree.left, tree.right));
}
  1. 现在将哈希映射中所有元素的坐标存储为O(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);
    }
}
  1. 在屏幕上打印坐标为O(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)


如果包含TreeCoordinategetHeight的定义,以及tree的内容(如果适用),将很有帮助。您还可以使用ideone.com之类的在线游乐场来提供可运行的示例。