zoukankan      html  css  js  c++  java
  • 【啊哈!算法】之三、交换排序

    作者:jofranks 原创作品,转载请标明出处!版权所有,侵权必究!

    来源:http://blog.csdn.net/jofranks


    交换排序的基本思想是:两两比较待排序的数据,发现两个数据的次序相反则进行交换,直到没有反序的数据为止。

    本文交换排序有:冒泡排序,快速排序~!


    一、冒泡排序

    冒泡排序是一种稳定的排序算法,他的时间复杂度是O(n^2)  当然,当数据基本有序的时候,他可以达到线性复杂度!


    OK,发一个冒泡排序的动画演示: 冒泡排序动画演示

    他的算法基本思想是:

    最多进行n-1趟排序,每趟排序时,从底部向上扫描,一旦发现两个相邻的元素不符合规则,则交换。我们 发现,第一趟排序后,最小值在A[1],第二趟排序后,较小值在A[2],第n-1趟排序完成后,所有 元素完全按 顺序排列。


    下面来看一下排序的过程:

    待排序数据:53  33  19  53  3  63  82  20  19  39

     


    第一趟排序:3  53  33  19  53  19  63  82  20  39

    第二趟排序:3  19 53  33  19  53  20  63  82  39

    第三趟排序:3  19 19  53  33  20  53  39  63  82

    第四趟排序:3  19 19  20  53  33  39  53  63  82

    第五趟排序:没有反序数据,排序结束。


    void bubble_sort(int *a, int N)
    {
    	int temp;
    	for(int i = N; i > 0; i--)
    	{
    		for(int j = 0; j < i - 1; j++) 
    		{
    			if(a[j] > a[j + 1])  //大的放后面
    			{
    				temp = a[j];
    				a[j] = a[j + 1];
    				a[j + 1] = temp;
    			}
    
    		}
    	}
    }


    ok 我们来看一下改进的冒泡排序,用一个标志:

    void bubble_sort1(int *a, int N)
    {
    	int temp;
    	int n;
    	for(int i = N - 1; i > 0;)
    	{
    		n = i;  //记录交换的位置
    		i = 0;  //假设本次没有交换
    		for(int j = 0; j < n; j++)
    		{
    			if(a[j] > a[j + 1])
    			{
    				temp = a[j];
    				a[j] = a[j + 1];
    				a[j + 1]  = temp;
    
    				i = j + 1;
    			}
    		}
    	}
    }



    二、鸡尾酒排序

    他是冒泡排序的一种改进,与冒泡排序不同的地方就是在排序时以双向在序列中进行排序!

    他的时间复杂度是O(n^2)  但是,如果数据基本有序的情况下 复杂度将是线性的!


    ok下面来看一下代码:

    void Cocktal_sort(int *a, int N)
    {
    	int temp;
    	int M = N - 1;
    	for(int i = 0; i < M;)
    	{
    		for(int j = M; j > i; j--)  //将最小的数据排在前面
    		{
    			if(a[j] < a[j - 1])
    			{
    				temp = a[j];
    				a[j] = a[j - 1];
    				a[j - 1] = temp;
    			}
    		}
    		i++;
    		//将最大的数据排在后面
    		for(int j = i; j < M; j++)
    		{
    			if(a[j] > a[j + 1])
    			{
    				temp = a[j];
    				a[j] = a[j + 1];
    				a[j + 1] = temp;
    			}
    		}
    
    		M--;
    	}
    }




    三、快速排序

    快速排序是一种不稳定的算法, 他的时间复杂度是O(nlgn)  空间复杂度是O(nlgn)

    他是采用分治法!

    在A[1..n]中任取一个数据元素作为比较的“基准”(不妨记为X),将数据区划分为左右两个部分:A[1..i-1]和A[i+1..n],且A[1..i-1]≤X≤A[i+1..n](1≤i≤n),当A[1..i-1]和A[i+1..n]非空时,分别对它们进行上述的划分过程,直至所有数据元素均已排序为止。

    上面是一趟排序的过程!

    ok,来看一个完整的例子!

    待排序数据:  67  67  14  52  29   9  90  54  87  71

    X=67         i                                    j

    扫描j          i                           j 

    交换          54  67  14  52  29   9  90  67  87  71

    扫描i                                 i    j 

    交换          54  67  14  52  29   9  67  90  87  71

    j=i,结束                              ij  

    第一趟排序后:54  67  14  52  29  9  [67]  90 87  71

    第二趟排序后: 9  29  14 52  [54]  67 [67] 71  87  [90]

    第三趟排序后:[9]  29  14 52  [54  67  67  71] 87 [90]

    第四趟排序后:[9]  14 [29] 52  [54 67  67  71 87  90]

    第五趟排序后:[9  14  29 52  54  67  67  71 87  90]


    来看一下排序的过程:

    ① 选定基准X(不妨用A[low])

    ② j向前扫描,直到A[j]<X,交换A[i]与A[j],i+1。保证了A[low..i-1]≤X

    ③ i向后扫描,直到A[i]>X,交换A[i]与A[j],j-1。保证了X≤A[j..high]

    ④ 继续执行②、③,直到i=j。这时,X恰好在A[i]位置上。

    ⑤ 对序列A[low..i-1]及A[i+1..high]按照上述规律继续划分,直到序列为空。


    仔细分析算法,我们发现,在排序中,我们总是用基准X与另一数据交换,因此,一趟排序结束后,X就能确切定位其最终位置。


    OK,我们来看一下C递归代码:

    //递归版本
    void quick_sort(int *a, int left, int right)
    {
    	int temp = a[left];//主元
    	if(left >= right)
    		return ;
    
    	int i = left, j = right;
    	for(; i != j;)
    	{
    		//开始移动,分治计算,找出比主元大的和比主元小的!小的放前面,大的放后面
    		while(i < j && a[j] >= temp)
    			j--;
    		if(j >= i)
    			a[i] = a[j];
    
    		while(i < j && a[i] <= temp)
    			i++;
    		if(j >= i)
    			a[j] = a[i]; 
    
    	}
    	a[i] = temp;
    	//递归
    	quick_sort(a, left, i - 1);
    	quick_sort(a, i + 1, right);
    }


    OK,现在我们分开,看一下代码,先来看取第一个元素为主元:

    //我们选首元素为主元
    int pation(int *a, int left, int right)
    {
    	int i = left;
    	int j = right;
    	int temp = a[left];  
    
    	for(;i < j ;)
    	{
    		while(i < j && a[j] >= temp)
    			j--;
    		if(j >= i)
    			a[i] = a[j];
    		while(i < j && a[i] <= temp)
    			i++;
    		if(j >= i)
    			a[j] = a[i];
    	}
    	a[i] = temp;
    	return i;
    }
    
    void quick_sort1(int *a, int left, int right)
    {
    	if(left < right)
    	{
    		int index = pation(a, left, right);
    		quick_sort1(a, left, index - 1);
    		quick_sort1(a, index + 1, right);
    	}
    }

    下面我们再换一种pation函数的写法,下面演示的主要是pation的不同了,所以我只贴这个函数的代码了!

    //以首元素为主元
    int pation2(int *a, int left, int right)
    {
    	int temp = a[left];
    	int n;
    	int i = left;
    	for(int j = i; j <= right; j++)
    	{
    		if(a[j] < temp)
    		{
    			i++;
    			n = a[j];
    			a[j] = a[i];
    			a[i] = n;
    		}
    	}
    
    	n = a[i];
    	a[i] = a[left];
    	a[left] = n;
    
    	return i;
    }

    下面再来一个将最后一个元素作为主元的情况:

    //以最后一个元素为主元
    int pation3(int *a, int left, int right)
    {
    	int temp = a[right];
    	int n ;
    	int i = left - 1;
    	for(int j = left; j < right; j++)
    	{
    		if(a[j] <= temp)
    		{
    			//将小元素和大元素呼唤
    			i++;
    			n = a[i];
    			a[i] = a[j];
    			a[j] = n;
    		}
    	}
    	//将尾元素挪到第一个较大的元素的位置,
    	//也就是说将尾元素和第一个较大的元素交换
    	n = a[i + 1];
    	a[i + 1] = a[right];
    	a[right] = n;
    
    	return i + 1;
    }


    ok先到这里,过几天把非递归实现补充上来!





    ---------2012/8/2

    ---------jofranks 于南昌




  • 相关阅读:
    C语言ll作业01
    C语言寒假大作战04
    C语言寒假大作战03
    C语言寒假大作战02
    C语言寒假大作战01
    C语言I作业12—学期总结
    C语言I博客作业11
    C语言I博客作业10
    第三章预习笔记-运算方法和运算部件
    非数值数据的编码表示
  • 原文地址:https://www.cnblogs.com/java20130723/p/3211441.html
Copyright © 2011-2022 走看看