zoukankan      html  css  js  c++  java
  • 排序算法学习

    一、排序算法的效率

      对于计算的复杂度,一般依据排序数据量n来度量,主要表征了算法执行速度。这是衡量一个算法的重要指标。对于常见的几种算法,其相应的计算复杂度如下:

    • 冒泡排序算法:平均速度O(n2),最坏情况下的速度为O(n2)
    • 快速排序算法:平均速度O(nlogn),最坏情况下的速度为O(n2)
    • 堆排序算法:平均速度O(nlogn),最坏情况下的速度为O(n2)
    • 插入排序算法:平均速度O(n2),最坏情况下的速度为O(n2)
    • Shell排序算法:平均速度O(n3/2),最坏情况下的速度为O(n2)
    • 归并排序算法:平均速度O(nlogn),最坏情况下的速度为O(nlogn)

      不得不说,冒泡排序、插入排序、合并排序是稳定的。在实际应用中,当数据量n较小时选择简单的冒泡排序能节省一定的内存空间;当n较大时,选择速度为O(nlogn)的算法为首选;

      我使用的参考书籍时宋娟@编著的Java常用算法手册,有些算法的可读性并不高,因此我根据别的dalao的结构照猫画虎的练习了这些算法。

    •   快速排序算法的思想可以参照https://www.cnblogs.com/CBDoctor/p/4077574.html给出的图解,浅显易懂。在QuickSort的实现过程中遇到了一些很弱智的问题。这可能和自己的知识浅薄有很大的关系。首先,我在一次遍历完成后没有调整基准,这是核心思想的错误!再次,意识到错误后在交换基准的时候也犯了低级的错误:
         a[i]=a[i]+temp;
            temp=a[i]-temp;
            a[i]=a[i]-temp;    
            a[low]=temp;//!!!
            /*
             * Here ,I make a mistake that confuses me the whole afternoon!!
             *         a[i]=a[i]+temp;
                    temp=a[i]-temp;
                    a[i]=a[i]-temp;        
                    You need to exchange the array not the temp
                    temp is only a place restoring the a[low]!!!
             */

      能够发现一开始我是将“相遇点”与保存基准数值的temp交换,因此在完成排序后基准并没有发生变化,输出的结果反而是出现大量的基准数值。

      在这里不得不提的是如果将基准设置为第一个数值,首先移动的必须是从后向前的指针j。

    这里举一个数组:                                                             108 36 128 46 44 51 128 14 125 33

    将基准设置为left,之后i指针从左向右寻找到比基准大的值才停下,j指针从右向左寻找到比基准小的值才停下;

      第一次,i->128,j->33。进行交换                               108 36 33 46 44 51 128 14 125 128

      第二次,i->128,j->14。进行交换                               108 36 33 46 44 51  14 128 125 128

      第三次,i->128 i=j停止前进并交换基准                     128 36 33 46 44 51  14 108 125 128

      这就会出现完成排序后的情况不能满足108左侧的值全部小于108,右侧的值全部大于108。大家可以自己尝试先移动j再移动i就不会出现这种问题。

    •   堆排序虽然不稳定,但也是个很棒的算法。思想就是数据结构所学的图形结构,不过无论是构造堆还是输出数据,不去多练习的话还是会出现很多令人费解的错误。

    相关代码:

    static void Heap(int[] a) {
    		int n=a.length;//定义数组的长度
    		for(int i=n/2-1;i>=0;i--) {
    			while(2*i+1<n) {//判断第i个结点是不是非根结点
    				/*Question:
    				 * 上面这个while是不是一定成立???
    				 * Solution:
    				 * At first, I forget to take the destroyed tree  in consideration.
    				 * the code is in the exchanging datas(i=j)
    				 */
    				int j=2*i+1;
    				if((j+1)<n) {
    					if(a[j]<a[j+1])
    						j++;//如果右左子树小于右右子树则将j指向右右子树
    				}
    				
    				if(a[i]<a[j]) {//交换数据
    					a[i]=a[i]+a[j];
    					a[j]=a[i]-a[j];
    					a[i]=a[i]-a[j];
    					i=j;//!!!!堆被破坏,需要重新调整
    				}else
    					break;
    				
    			}
    		}//EndFor
    		//输出构成的堆
    		System.out.print("原数据构成的堆:  ");
    		for(int temp:a)
    			System.out.print(temp+"  ");
    		System.out.println();
    		
    		for(int i=n-1;i>0;i--) {
    			a[0]=a[i]+a[0];
    			a[i]=a[0]-a[i];
    			a[0]=a[0]-a[i];//结点与第i个交换数据
    			
    			int k=0;
    			while(2*k+1<i) {//!!!一开始写成2*k+1<n出现错误
    				/*
    				 * Question:
    				 * Why there is i not n?
    				 * Solution:
    				 * We put the biggest num in the last and do not touch it any more
    				 * so we set i=n-1 in order to deal with the remainders.
    				 */
    				int h=2*k+1;
    				if(h+1<i) {//存在右右子树//!!!!!
    					if(a[h]<a[h+1])//右右子树比右左子树数值大
    						h++;//指向右右子树
    				}
    				
    				if(a[k]<a[h]) {//交换数据
    					a[k]=a[k]+a[h];
    					a[h]=a[k]-a[h];
    					a[k]=a[k]-a[h];
    					k=h;
    				}else
    					break;
    					
    			}
    			System.out.print("第"+(n-i)+"次排序结果:  ");
    			for(int temp:a)
    				System.out.print(temp+"  ");
    			System.out.println();
    		}
    		
    		
    	}//EndHeap
    

      

    潜下心,沉住气。
  • 相关阅读:
    内存溢出
    3.设计模式----TemplateMethod模式
    tomcat 编码问题
    ibatis实现Iterate的使用 (转)
    2.设计模式---Adapter模式
    1.设计模式-------Iterator
    PHP 下载远程图片
    mysql调优 参数说明
    mySQL内存及虚拟内存优化设置
    Firebug入门指南
  • 原文地址:https://www.cnblogs.com/LiYimingRoom/p/11454087.html
Copyright © 2011-2022 走看看