题目:
当输入数据已经“几乎有序时”,插入排序很快,在实际应用中,我们可以利用这一特点来提高快速排序的速度。当对一个长度小于k的子数组调用快速排序时,让它不做任何排序就返回。当上一层的快速排序调用返回后,对整个数组运行插入排序完成排序过程。证明:这一排序算法的期望时间复杂度为O(nk+nlg(n/k)).
解决方案:
quicksort在递归到只有几个元素大小的数组时开始用插入排序的方法。改进的快速排序方法在
期望时间=原始快排的期望时间+插入排序方法的期望时间。
这里还是要用到7.4(算法导论第7章)的分析方法。对于快排还要计算期望比较次数。
因为被划分在同一个小数组k中的元素,是不会在快排里比较的。所以Xij只要计算那些i和j相差k-1个以上的元素比较就可以了。
定义一个元素集合Zij={zi,zi+1,,,,,,,,zj}
定义一个指示器随机变量Xij=I{zi与zj进行了比较}
E[Xij]=Pr[Xij]=Pr{zi与zj进行了比较}=Pr{zi是Zij的主元}+Pr{zj是Zij的主元}=2/(j-i+1)//因为在快排中,二者能够比较,则其中一个必是主元
快速排序的期望比较次数E[Xij]为
class
SortOp
{ //插入排序
private static void InsertSort(int[] list,int low,int high)
{
for (int i = low; i < high; i++)
{
int t = list[i];
int j = i;
while ((j > 0) && (list[j - 1] > t))
{
list[j] = list[j - 1];
--j;
}
list[j] = t;
}
}
private static void Swap(ref int i, ref int j)
//只有两个元素时直接交换
{
int t;
t = i;
i = j;
j = t;
}
//快速排序优化
public static void QuickSort(int[] list, int low, int high,int k)
{
//只剩下一个无需交换
if (high <= low)
{
return;
}
else if (high == low + 1)
{
//只剩下两个直接交换
if (list[low] > list[high])
{
Swap(ref list[low], ref list[high]);
return;
}
}
//大于三个元素开始优化的快速排序
myQuickSort(list, low, high,k);
}
public static void myQuickSort(int[] list, int low, int high,int k)
{
if (low < high)
{
if(high-low<k) //子序列小于k个使用插入排序
{
InsertSort(list,low,high);
}
else{
int pivot = Partition(list, low, high);
myQuickSort(list, low, pivot - 1,k);
myQuickSort(list, pivot + 1, high,k);
}
}
}
private static int Partition(int[] list, int low, int high)
{
int pivot;
pivot = list[low];
while (low < high)
{
while (low < high && list[high] >= pivot)
{
high--;
}
if (low != high)
{
Swap(ref list[low], ref list[high]);
low++;
}
while (low < high && list[low] <= pivot)
{
low++;
}
if (low != high)
{
Swap(ref list[low], ref list[high]);
high--;
}
}
return low;
}
}
2696

被折叠的 条评论
为什么被折叠?



