排序算法学习

一、排序算法的效率

  对于计算的复杂度,一般依据排序数据量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

  

潜下心,沉住气。
原文地址:https://www.cnblogs.com/LiYimingRoom/p/11454087.html