排序算法可以描述如下:
1。从数组数据创建二进制搜索树。
(对于多次出现,当前节点的增量发生变量)
2。以顺序方式遍历BST。
(Inorder遍历将返回数组中元素的排序顺序。)
第3。在inorder遍历中的每个节点处,用当前节点值覆盖当前索引(索引从0开始)的数组元素。
这是一个相同的Java实现:
节点类的结构
class Node {
Node left;
int data;
int occurence;
Node right;
}
inorder功能 (返回类型是int,只是为了在每次调用时获得正确的索引,它们不起作用)
public int inorder(Node root,int[] arr,int index) {
if(root == null) return index;
index = inorder(root.left,arr,index);
for(int i = 0; i < root.getOccurence(); i++)
arr[index++] = root.getData();
index = inorder(root.right,arr,index);
return index;
}
主要()
public static void main(String[] args) {
int[] arr = new int[]{100,100,1,1,1,7,98,47,13,56};
BinarySearchTree bst = new BinarySearchTree(new Node(arr[0]));
for(int i = 1; i < arr.length; i++)
bst.insert(bst.getRoot(),arr[i]);
int dummy = bst.inorder(bst.getRoot(),arr,0);
System.out.println(Arrays.toString(arr));
}
我知道,空间复杂性很糟糕,但除非将这种排序用于极其庞大的数据集,否则它不应该是一个大问题。但是,正如我所看到的,时间复杂性O(n)是不是? (来自BST的插入和检索是O(log n),并且每个元素被触摸一次,使其成为O(n))。如果我错了,请纠正我,因为我还没有好好研究Big-O。
答案 0 :(得分:0)
假设插入的摊销(平均)复杂度为O(log n)
,则N
插入(构建树)将给O(log(1) + log(2) + ... + log(N-1) + log(N)
= { {1}} = O(log(N!))
(斯特林定理)。要回读已排序的数组,请执行按顺序深度优先遍历,它会访问每个节点一次,因此O(NlogN)
。将这两者结合起来O(N)
。
但是,这要求树始终平衡!对于最基本的二叉树,一般情况并非如此,因为插入不会检查每个子树的相对深度。有许多自我平衡的变体 - 最着名的两个是红黑树和 AVL树。然而,平衡的实施非常复杂,并且通常会导致实际性能中更高的常数因素。
答案 1 :(得分:0)
目标是实现一个O(n)算法,用n [1,n ^ 2]范围内的每个元素对n个元素的数组进行排序
在这种情况下,Radix排序(计数变化)将是O(n),采用固定数量的通过(logb(n ^ 2)),其中b是用于该字段的“基数”,并且ba函数为n,例如b == n,它需要两次传递,或者b == sqrt(n),它需要四次传递,或者如果n足够小,b == n ^ 2,它将需要两次传递可以使用一次通过和计数排序。 b可以向上舍入到2的下一个幂,以便用二进制移位和二进制和替换除法和模。基数排序需要O(n)额外空间,但二叉树的链接也是如此。