算法导论7.4-5

部署运行你感兴趣的模型镜像

题目:

当输入数据已经“几乎有序时”,插入排序很快,在实际应用中,我们可以利用这一特点来提高快速排序的速度。当对一个长度小于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]为


那么快排的期望时间是O(nlg(n/k)),假设优化后的快排产生的小数组大小O(k),在每个大小O(k)的小数组里使用插入排序,时间复杂度为O(k^2),总共有O(n/k)个小数组,则插入排序时间为O(nk),。那么把这些时间加起来就是O(nk+nlog(n/k))。

之后对k的取值进行了实验:
实验目的:
       快速排序可以按照以下的算法思想优化,并加快快速排序的速度:即当快速排序所划分的子序列的长度小于某个定值k时,该子序列基本有序,可以采用插入排序的办法对子序列进行排序,从而使整体算法的时间复杂度的期望下降为O(nk+nlg(n/k))。本实验的目的是实现该快速排序的优化算法,并且探讨合理的k的取值范围
问题定义
实验总共要解决两个问题
1、 优化的快速排序的算法确实能够加速快速排序的速度。
2、 讨论k的合理的取值范围。
对于给定规模为n的int[]无序随机数组进行排序,通过实验证明经过优化的快速排序比传统的快排效率要高,并讨论k的值的范围。
实验思想
1、 优化快速排序的方法:
a)          在快速的排序的方法中加入判断语句,当high-low<k的时候则调用插入排序的算法,否则继续使用快速排序。
b)         当k<=2时,实质上不调用插入排序,这样就可以得出相同规模的情况下直接使用快速排序所需要的时间。从而便于比较
2、 通过考察时间消耗来确定性能的高低
a)          每次计算数据都取一定规模的int 32型无序随机数进行排序,为了避免误差,规模n一定时,不同的k值,都计算5次运算时间,取平均值记录。
b)         使用.net framework 2.0提供的Stopwatch计时器对象,该对象可以将时间间隔精确到0.0001ms。
c)          从理论上得到合理的k值的取值范围是k<=logn.因此在验证取值范围的时候要取到log n 两侧的值。
d)         通过比较时间复杂度来计算性能提升的多少,从而得到加快了快速排序的结论,以及合理的k的取值范围。
测试数据及结果
本测试的硬件以及软件环境如下
       CPU:PM 1.5G; 内存:768M;操作系统:windows xp sp2;软件平台:.net 2.0;
1、 数组规模为50的时候得到如下数据。
其中第一行为k的取值、第二行为程序运行所需要的时间,单位为ms。
 
2、 数组规模为500的时候得到如下数据。
其中第一行为k的取值、第二行为程序运行所需要的时间,单位为ms。
整体图
局部图
3、 数组规模为5000的时候得到如下数据。
其中第一行为k的取值、第二行为程序运行所需要的时间,单位为ms
 
4、 数组规模为50000的时候得到如下数据。
其中第一行为k的取值、第二行为程序运行所需要的时间,单位为ms
5、 数组规模为1,000,000的时候得到如下数据。
其中第一行为k的取值、第二行为程序运行所需要的时间,单位为ms
 
结果分析:
1、 由所有的图可以看出,经过优化以后的快速排序比传统快速排序的速度要快,通过数据计算可以排序速度提高了10%-20%左右。
2、 通过图示也可以知道当k=logn的时候,其效率提升并不是最大的,在规模不大(例如5个数量级以下)的排序中其最佳的k的取值往往比log n大,一般以8—12之间为最小。
当规模较大时,一般取logn为宜,即使最佳取值超过logn其性能提升也不明显。
3、 此后随着k的取值的增大,尤其是超过50之后,时间复杂度明显提升,甚至比快速排序的算法要差。
4、 在规模较大的排序过程中快速排序的效率明显好于插入排序。
有可能影响结论的因素:
1、 快速取随机数的算法:
a)          在本实验中,所使用的随机数是在10n的整数内取n个无重复的随机数,该算法有可能会影响对实验结果的分析有轻微影响。
2、 小规模的数组的分析
a)          对于小规模的数组有可能在快速排序之后得到的子序列的长度小于8,因此直接取8值得商榷。
 
实验结论
1、 经过优化以后的快速排序比传统快速排序的速度要快,通过数据计算可以排序速度提高了10%-20%左右。
2、 在规模不大(例如5个数量级以下)的排序中其最佳的k的取值往往比log n大,一般以8—12之间效率最佳。
当规模较大时,k的取值一般取logn为宜,即使最佳取值超过logn其性能提升也不明显。
 
源代码
优化排序的算法源代码(C#描述)
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;
            }

 
        }
 
 

您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

快速排序是一种经典的分治算法,在《算法导论》第三版中对其进行了深入探讨。以下是关于7.4节中的题目解析: ### 7.4 快速排序分析 #### 题目描述 在这一章节中,重点讨论了快速排序的间复杂度及其期望运行间的推导过程。 --- #### **7.4-1** 此题的核心在于理解快速排序划分操作的行为以及其对数组的影响。假设输入数组长度为 \( n \),则每次划分会将数组分为两部分,分别对应小于等于和大于选定的枢纽元的部分[^1]。 对于最坏情况下的间复杂度分析,当每次划分都极不平衡(即一边为空),递归树的高度将达到 \( O(n) \),因此总间为 \( T(n) = T(n-1) + O(n) \),最终得出最坏情况下间复杂度为 \( O(n^2) \)[^1]。 而对于平均情况,则需考虑所有可能的划分方式并计算加权平均值。通过归纳法可以证明,随机化版本的快速排序具有线性对数级别的期望间复杂度 \( O(n\log{n}) \)[^4]。 ```python def randomized_partition(arr, low, high): import random i = random.randint(low, high) arr[i], arr[high] = arr[high], arr[i] pivot = arr[high] i = low - 1 for j in range(low, high): if arr[j] <= pivot: i += 1 arr[i], arr[j] = arr[j], arr[i] arr[i+1], arr[high] = arr[high], arr[i+1] return i + 1 def randomized_quick_sort(arr, low, high): if low < high: q = randomized_partition(arr, low, high) randomized_quick_sort(arr, low, q - 1) randomized_quick_sort(arr, q + 1, high) example_array = [3, 8, 2, 5, 1, 4, 7, 6] randomized_quick_sort(example_array, 0, len(example_array)-1) print(example_array) ``` 上述代码实现了基于随机化的快速排序方法,其中 `randomized_partition` 函数用于选取一个随机位置作为枢轴,并完成一次分割操作。 --- #### **7.4-4** 本题要求严格证明 RANDOMIZED-QUICKSORT 的期望运行间下界为 \( \Omega(n\lg{n}) \)。这可以通过构建概率模型来实现:设 \( X_{ij} \) 表示元素 \( z_i \) 和 \( z_j \) 被比较的概率,则总的比较次数可表示为 \( C = \sum_{i<j}X_{ij} \)。利用独立同分布性质及条件期望公式展开后即可得证。 --- ### 总结 通过对以上问题的具体解答可以看出,《算法导论》不仅提供了理论上的严谨论证,还辅以实际应用案例帮助读者更好地掌握知识点。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值