Java 在算法分析中,什么算比较?
主要问题:当记录比较时,什么才算是比较?我应该只计算数组项之间的比较,因为这就是算法的目的,还是更广泛地接受计算每个比较 目前,我正试图了解这样一个事实,即有人告诉我,最坏情况下冒泡排序算法的理论比较数如下: 比较数量: (N-1)+(N-2)+(N-3)+……+2+1=(N*(N-1))/2=(N^2-N)/2Java 在算法分析中,什么算比较?,java,algorithm,analysis,Java,Algorithm,Analysis,主要问题:当记录比较时,什么才算是比较?我应该只计算数组项之间的比较,因为这就是算法的目的,还是更广泛地接受计算每个比较 目前,我正试图了解这样一个事实,即有人告诉我,最坏情况下冒泡排序算法的理论比较数如下: 比较数量: (N-1)+(N-2)+(N-3)+……+2+1=(N*(N-1))/2=(N^2-N)/2
for i:=1 to N-1 do
{
for j:=0 to N-i do
{
if A[j] > A[j+1] // This is the comparison that's counted.
{
temp := A[j]
A[j] := A[j+1]
A[j+1] := temp
}
}
}
现在在Java中,我的代码如下所示:
public int[] bubble(int[] array)
{
int comparisons = 0;
int exchanges = 0;
int temp;
int numberOfItems = array.length;
boolean cont = true;
comparisons++; // When pass == numberOfItems, a comparison will be made by the for loop that wouldn't otherwise be counted.
for (int pass=1; pass != numberOfItems; pass++)
{
comparisons = comparisons + 2; // Counts both the outer for loop comparison and the if statement comparison.
if (cont) // If any exchanges have taken place, cont will be true.
{
cont = false;
comparisons++; // Counts the inner for loop comparison
for (int index = 0; index != (numberOfItems - pass); index++)
{
comparisons++; // Counts the if statement comparison.
if (array[index] > array[index+1])
{
temp = array[index];
array[index] = array[index+1];
array[index+1] = temp;
cont = true;
exchanges++;
} // end inner if
} // end inner for
}
else
{
break; // end outer if
}
}
System.out.println("Comparisons = " + comparisons + "\tExchanges = " + exchanges);
return array;
}
在我的代码上执行了最坏情况的场景(使用一个包含10个元素的数组,顺序相反),我总共得到了73个比较。这似乎是一个疯狂的高超调的理论结果,这是45个比较。不过,我觉得这是对的,因为我已经考虑了所有for循环和if语句
非常感谢您的帮助
编辑:我注意到内部循环的总比较计数有错误。以前我计算过两次内部循环,但现在它被修复了。我现在得到的不是118次比较,而是73次。但是,问题仍然存在。只有在代码执行过程中达到if语句后,比较变量才应该递增。if语句仅在满足外部for循环和内部for循环中规定的条件时才到达,因此代码应如下所示。
另外,不要忘记更改for循环中的条件,以避免使用!=在评估排序算法时,通常会将数组元素之间的所有比较计算为具有等效成本,而忽略数组索引之类的比较。基本概念是,为了使排序操作与基数分区保持明显不同,被排序项的大小需要随着它们的数量增加而增加。例如,假设有一个数组包含100000000个
char
值,并希望对它们进行排序。虽然可以使用快速排序、冒泡排序或其他方法,但更快的方法是使用int[65536]
并计算每个值的数量。即使需要对具有char
键的项目进行排序,最好的方法是确定在何处放置键为0的最后一个项目(键为0的项目数减去1),在何处放置键为1的最后一个项目(键为0或1的项目数减去1),等。所有此类操作所需的时间与项目数量加上可能的键值数量成比例,无任何lg(N)系数
请注意,如果忽略“簿记”成本,像Quicksort这样的算法就不是很理想。设计用于最大化从每次比较中获得的信息量的排序算法可能会进行较少的比较。然而,除非比较非常昂贵,否则这种排序算法可能会浪费更多的时间“聪明”,而不是“愚蠢”
有一个问题我没怎么讨论过,尽管我认为它在许多现实世界的案例中会提供显著的好处,那就是优化已知范围很窄的项目之间的比较顺序。如果在对一系列1000个字符的路径名执行快速排序时,一个正在处理其条目在共享前950个字符的两个名称之间都是已知的分区,则无需检查该分区中任何名称的前950个字符。除非键长度是一个参数,否则这种优化在big-O术语中不太可能有意义,但在现实世界中,我希望它有时会产生数量级的影响。在测量排序中的比较次数时,只计算数组项之间的比较。在比较它们时,可以计算它们是否实际在数组中 其思想是,数组可能包含需要很长时间进行比较的内容,而不是简单的整数。例如,字符串数组可以使用N(N-1)/2个字符串比较进行冒泡排序,即使单个字符串比较可能需要许多其他操作,包括单个字符的许多比较
根据比较的数量衡量排序算法的性能,使得衡量独立于被排序的事物的类型。如果通常计算数组元素之间的比较并忽略数组索引之间的比较,这是否意味着我们也忽略检查标志的If语句?@NickSabia:Yup。基本上,假设元素的比较速度足够慢,并且会随着元素数量的增加而变慢,从而使其他任何可能正在做的事情相形见绌。人们可以设计这样的案例,例如记账成本会随着元素的数量呈指数增长,但一般来说,出于算法分析的目的,记账成本被视为可以忽略不计。@NickSabia:我想我没有读过关于这个主题的正式论述,但非正式地说,如果人们假设比较元素的成本将与被排序元素数量的对数成正比,以便真正的排序仍然是必要的,簿记成本操作将不会影响算法的复杂性,除非它们增长得更快。
public int[] bubble(int[] array)
{
int comparisons = 0;
int exchanges = 0;
int temp;
int numberOfItems = array.length;
boolean cont = true;
for (int pass=1; pass <= numberOfItems; pass++)
{
if (cont) // If any exchanges have taken place, cont will be true.
{
cont = false;
for (int index = 0; index <= (numberOfItems - pass); index++)
{
if (array[index] > array[index+1])
{ comparison++;
temp = array[index];
array[index] = array[index+1];
array[index+1] = temp;
cont = true;
exchanges++;
} // end inner if
} // end inner for
}
}
comparison++; // here you increment by one because you must also count the comparison that failed
System.out.println("Comparisons = " + comparisons + "\tExchanges = " + exchanges);
return array;
}