基本上,我想知道在实现以下代码以执行插入排序时是否可能发生任何逻辑错误。我注意到一些示例使用带有逻辑AND运算符的while
循环,但是我认为我可以通过使用标志来监视排序列表中的任何值是否小于当前索引来实现相同的输出并通过存储该较小值的位置。
#include<stdio.h>
void insertion(int size, int[*]);
int main()
{
int size;
printf("Size of Array: ");
scanf("%d",&size);
int ary[size];
for(int i=0; i<size; i++)
scanf("%d",&ary[i]);
insertion(size, ary);
return 0;
}
void insertion(int size, int A[size])
{
int value;
int hole;
int flag;
for(int i=1; i<size; i++)
{
value = A[i];//the value of the current index of the unsorted list
//gets stored in variable named value
flag = 0;
for(int j=i-1; j>=0; j--)
{
if(A[j]>value)
{
flag = 1;
hole = j; //index position where value will be
//inserted into
A[j+1] = A[j];
}
}
if(flag) //ensures that insertion occurs only when one of the
//sorted elements is less than value
A[hole] = value;
}
for(int i=0; i<size; i++)
printf("%d ",A[i]);
}
`
以下方法是使用while
循环而不是标志的替代变体:
void unshuffle( int size, int* A )
{
int value;
int position;
for( int i=1; i<size; i++ )
{
value = A[i];
position = i;
while( A[position-1]>value && position>0 )
{
A[position] = A[position-1];
position--;
}
A[position] = value;
}
}
就效率而言,这是编写插入排序的首选方法吗?
答案 0 :(得分:3)
您的方法效率越来越低;考虑以下算法变体:
for(int j=i-1; j>=0; j--)
{
if(A[j] > value)
{
A[j+1] = A[j];
}
else
{
A[j+1] = value; // worst that could happen: self asignment;
// still less costly than another `if`!
break; // you're in the sorted part of the array, so all other
// values are smaller or equal as well -> can exit!
}
}
现在您不再需要标记/孔,但更重要的是,您不再需要遍历已经排序的较小部分。
从...开始的while循环中,使用双重条件将获得相同的结果。
实际上,存在错误,如果当前元素小于所有已排序元素,则不会输入else
子句,因此不会在第一个位置插入元素。修复很容易,但是:
int j;
for(j = i-1; j >= 0; j--)
{
if(A[j] > value)
{
A[j+1] = A[j];
}
else
{
break;
}
}
A[j+1] = value; // (still self-assignment possible)
// if j got -1: insert at 0, so fine
现在我们更加接近原始的while循环...
尽管您仍在尝试优化一种以效率低下(O(n²)
的average(!)运行时)而闻名的算法,但我不认为值得这么多,更好地切换到从一开始就quick-sort(平均运行时间O(n log(n))
,heap-sort(运行时间最多O(n log(n))
,但常数比quicksort差)或intro-sort(前两个混合) ,在大多数实现中都是C ++ std::sort
的标准排序算法)。