zoukankan      html  css  js  c++  java
  • 算法导论: 第7章

    7.4-5 快速排序+插入排序

    粗略证明如下:

    从书中证明可知,只要划分是常数比,那么最后期望都是一样的。故假设每次划分都是均匀的。假设划分深度为h时,每个块的规模都不超过k,则有k*2^h = n,h = lg(n/k)。又因为在最底层,规模不超过k的子序列有n/k个,所以每个子序列内部插入排序时间为O(k^2),总的插入排序时间为O(nk)。(注意:这一步证明不严格,每个都是O(K^2),加起来可能比O(nk)要大。)

    每一次划分为O(n),总共有lg(n/k)层,所以划分的复杂度为O(nlg(n/k)),所以,总的时间为O(nk + nlg(n/k))。

    7-4 快速排序的堆栈深度

    优化的尾递归:
    QUICKSORT (A, p, r )
        while p < r
            do Partition and sort the small subarray Þrst
            q ← PARTITION(A, p, r )
            if q − p < r − q
                then QUICKSORT (A, p, q − 1)
                        p ← q + 1
            else QUICKSORT (A, q + 1, r )
                        r ← q − 1

    7-6 模糊排序

    快速排序可以看成区间大小为1的模糊排序。模糊排序的关键在于如何充分利用重叠区间,解决思路是在调用Partion()划分时,区间如果重叠的部分,就把它们看做是相等的,并提取公共部分继续划分。

    转载代码来源http://blog.csdn.net/mishifangxiangdefeng/article/details/7681109

    #include <iostream>
    using namespace std;
    
    struct node
    {
    	int start;
    	int end;
    	bool operator<(const node & b)const
    	{
    		return end < b.start;
    	}
    	bool operator==(const node & b)const
    	{
    		return (end >= b .start) && (start <= b.end);
    	}
    	bool operator>(const node & b)const
    	{
    		return start > b.end;
    	}
    };
    
    //划分结果:0 -> a小于主元,a+1 -> b-1等于主元,b -> length_A大于主元
    struct divid
    {
    	int a;
    	int b;
    };
    
    node A[11];
    int length_A = 10;
    
    //按划分结果分三行显示
    void Print(divid d)
    {
    	int i = 1;
    	if(d.a > 0)
    	{
    		for(i = 1; i <= d.a; i++)
    			cout<<'('<<A[i].start<<','<<A[i].end<<") ";
    		cout<<endl;
    		i = d.a + 1;
    	}
    	if(d.b > 0)
    	{
    		for(; i < d.b; i++)
    			cout<<'('<<A[i].start<<','<<A[i].end<<") ";
    		cout<<endl;
    		i = d.b;
    	}
    	if(i <= length_A)
    	{
    		for(; i <= length_A; i++)
    			cout<<'('<<A[i].start<<','<<A[i].end<<") ";
    		cout<<endl;
    	}
    	cout<<endl;
    }
    //交换
    void Exchange(node &a, node &b)
    {
    	node temp;
    	temp = a;
    	a = b;
    	b = temp;
    }
    //划分是重点
    divid Partition(node *A, int p, int r)
    {
    	//先取任意一个元素为主元
    	node x = A[r];
    	int i = p-1, j = r+1, k = p;
    	while(k <=r && k < j)
    	{
    		//如果小于主元,交换到前面
    		if(A[k] < x)
    		{
    			i++;
    			Exchange(A[i], A[k]);
    			k++;
    		}
    		//如果大于,交换到后面
    		else if(A[k] > x)
    		{
    			j--;
    			Exchange(A[j], A[k]);
    			//这里不能k++,因为交换过来的元素也可能大于主元
    		}
    		else
    		{
    			//如果相等,不交换,但是要提取公因子
    			x.end = min(x.end, A[k].end);
    			x.start = max(x.start, A[k].start);
    			k++;
    		}
    	}
    	//返回划分结果
    	divid ret = {i, j};
    	if(ret.a < p)ret.a = -1;
    	if(ret.b > r)ret.b = -1;
    	Print(ret);
    	return ret;
    }
    
    void QuickSort(node *A, int p, int r)
    {
    	if(p >= r)
    		return;
    	//把数组划分为三段
    	divid q = Partition(A, p, r);
    	//如果存在第一段,对第一段排序
    	if(q.a > 0)
    		QuickSort(A, p, q.a);
    	//如果存在第三段,对第三段排序
    	if(q.b > 0)
    		QuickSort(A, q.b, r);
    }
    
    int main()
    {
    	int i, n;
    	cin>>n;
    	length_A = n;
    	//init data by random
    	for(i = 1; i <= length_A; i++)
    	{
    		A[i].start = rand() % 100;
    		A[i].end = rand() % 100;
    		if(A[i].start > A[i].end)
    			swap(A[i].start, A[i].end);
    	}
    	divid d = {-1, -1};
    	Print(d);
    	//sort
    	QuickSort(A, 1, length_A);
    	return 0;
    }
    

      

  • 相关阅读:
    Prometheus入门教程(二):Prometheus + Grafana实现可视化、告警
    Prometheus 入门教程(一):Prometheus 快速入门
    Prometheus 系列开篇:为什么要学 Prometheus ?
    你总是遗憾,是因为你还没想好,你的一生想怎么过!
    搞 Java 的年薪 40W 是什么水平?
    闪送,为何能从顺丰中杀出一条血路?
    安全攻击溯源思路及案例
    Windows下登录凭证窃取技巧
    Linux下登录凭证窃取技巧
    如何探测内网存活主机
  • 原文地址:https://www.cnblogs.com/rolling-stone/p/3653045.html
Copyright © 2011-2022 走看看