[置顶] 插入排序、冒泡排序、选择排序与希尔排序、快速排序、归并排序

从算法时间代价考虑,分为两类

第一类:插入排序、冒泡排序、选择排序

它们比较相邻的元素,平均算法时间代价都为O(n2);

插入排序:

public class insertion_sort {
	
	public static void insertsort(int[] unsorted){
		for(int i=1;i<unsorted.length;i++){
			if(unsorted[i-1]>unsorted[i]){
				int temp=unsorted[i];
				int j = i;
				while(j>0&&unsorted[j-1]>temp){
					unsorted[j]=unsorted[j-1];
					j--;
				}
				unsorted[j]=temp;
			}
		}
		for(int i=0;i<unsorted.length;i++){
			System.out.println(unsorted[i]);
		}
	}
	
	public static void main(String[] args) {
		int[] x={6,2,4,1,5,9};
		insertsort(x);
 	}
}
冒泡排序:

原理是临近的数字两两进行比较,按照从小到大或者从大到小的顺序进行交换,

这样一趟过去后,最大或最小的数字被交换到了最后一位,

然后再从头开始进行两两比较交换,直到倒数第二位时结束,其余类似看例子

例子为从小到大排序,

原始待排序数组| 6 | 2 | 4 | 1 | 5 | 9 |


第一趟排序(外循环)

第一次两两比较6 > 2交换(内循环)

交换前状态| 6 | 2 | 4 | 1 | 5 | 9 |

交换后状态| 2 | 6 | 4 | 1 | 5 | 9 |

 

第二次两两比较,6 > 4交换

交换前状态| 2 | 6 | 4 | 1 | 5 | 9 |

交换后状态| 2 | 4 | 6 | 1 | 5 | 9 |

 

第三次两两比较,6 > 1交换

交换前状态| 2 | 4 | 6 | 1 | 5 | 9 |

交换后状态| 2 | 4 | 1 | 6 | 5 | 9 |

 

第四次两两比较,6 > 5交换

交换前状态| 2 | 4 | 1 | 6 | 5 | 9 |

交换后状态| 2 | 4 | 1 | 5 | 6 | 9 |

 

第五次两两比较,6 < 9不交换

交换前状态| 2 | 4 | 1 | 5 | 6 | 9 |

交换后状态| 2 | 4 | 1 | 5 | 6 | 9 |

 

第二趟排序(外循环)

第一次两两比较2 < 4不交换

交换前状态| 2 | 4 | 1 | 5 | 6 | 9 |

交换后状态| 2 | 4 | 1 | 5 | 6 | 9 |

 

第二次两两比较,4 > 1交换

交换前状态| 2 | 4 | 1 | 5 | 6 | 9 | 

交换后状态| 2 | 1 | 4 | 5 | 6 | 9 |

 

第三次两两比较,4 < 5不交换

交换前状态| 2 | 1 | 4 | 5 | 6 | 9 | 

交换后状态| 2 | 1 | 4 | 5 | 6 | 9 |

 

第四次两两比较,5 < 6不交换

交换前状态| 2 | 1 | 4 | 5 | 6 | 9 |

交换后状态| 2 | 1 | 4 | 5 | 6 | 9 |

 

第三趟排序(外循环)

第一次两两比较2 > 1交换

交换后状态| 2 | 1 | 4 | 5 | 6 | 9 |

交换后状态| 1 | 2 | 4 | 5 | 6 | 9 |

 

第二次两两比较,2 < 4不交换

交换后状态| 1 | 2 | 4 | 5 | 6 | 9 | 

交换后状态| 1 | 2 | 4 | 5 | 6 | 9 |

 

第三次两两比较,4 < 5不交换

交换后状态| 1 | 2 | 4 | 5 | 6 | 9 | 

交换后状态| 1 | 2 | 4 | 5 | 6 | 9 |

 

第四趟排序(外循环)无交换

第五趟排序(外循环)无交换


排序完毕,输出最终结果1 2 4 5 6 9


public class bubble_sort {
	public static void bubblesort(int[] unsorted){
		for(int i=0;i<unsorted.length;i++){
			for(int j=i;j<unsorted.length;j++){
				if(unsorted[i]>unsorted[j]){
					int temp=unsorted[i];
					unsorted[i]=unsorted[j];
					unsorted[j]=temp;
				}
			}
		}
		for(int i=0;i<unsorted.length;i++){
			System.out.println(unsorted[i]);
		}
	}
	public static void main(String[] args){
		int[]x={6,2,4,1,5,9};
		bubblesort(x);
	}
}

选择排序:

就是直接从待排序数组里选择一个最小(或最大)的数字,每次都拿一个最小数字出来,

顺序放入新数组,直到全部拿完

再简单点,对着一群数组说,你们谁最小出列,站到最后边

然后继续对剩余的无序数组说,你们谁最小出列,站到最后边

再继续刚才的操作,一直到最后一个,继续站到最后边,现在数组有序了,从小到大

举例

先说看每步的状态变化,后边介绍细节,现有无序数组[6 2 4 1 5 9]

第一趟找到最小数1,放到最前边(与首位数字交换)

交换前:| 6 | 2 | 4 | 1 | 5 | 9 |

交换后:| 1 | 2 | 4 | 6 | 5 | 9 |

第二趟找到余下数字[2 4 6 5 9]里的最小数2,与当前数组的首位数字进行交换,实际没有交换,本来就在首位

交换前:| 1 | 2 | 4 | 6 | 5 | 9 |

交换后:| 1 | 2 | 4 | 6 | 5 | 9 |


第三趟继续找到剩余[4 6 5 9]数字里的最小数4,实际没有交换,4待首位置无须交换

第四趟从剩余的[6 5 9]里找到最小数5,与首位数字6交换位置

交换前:| 1 | 2 | 4 | 6 | 5 | 9 |

交换后:| 1 | 2 | 4 | 5 | 6 | 9 |

第五趟从剩余的[6 9]里找到最小数6,发现它待在正确的位置,没有交换

排序完毕输出正确结果[1 2 4 5 6 9]

第一趟找到最小数1的细节

当前数组是| 6 | 2 | 4 | 1 | 5 | 9 |

先把6取出来,让它扮演最小数

当前最小数6与其它数一一进行比较,发现更小数就交换角色

当前最小数6与2比较,发现更小数,交换角色,此时最小数是2,接下来2与剩余数字比较

当前最小数2与4比较,不动

当前最小数2与1比较,发现更小数,交换角色,此时最小数是1,接下来1与剩余数字比较

当前最小数1与5比较,不动

当前最小数1与9比较,不动,到达末尾

当前最小数1与当前首位数字进行位置交换,如下所示

交换前:| 6 | 2 | 4 | 1 | 5 | 9 |

交换后:| 1 | 2 | 4 | 6 | 5 | 9 |

完成一趟排序,其余步骤类似

public class selection_sort {
	public static void selectionsort(int[]unsorted){
		for(int i=0;i<unsorted.length;i++){
			int min=unsorted[i],min_index=i;
			for(int j=i;j<unsorted.length;j++){
				if(unsorted[j]<min){
					min=unsorted[j];
					min_index=j;
				}
			}
			if(min_index!=i){
				int temp=unsorted[i];
				unsorted[i]=unsorted[min_index];
				unsorted[min_index]=temp;
			}
		}
		for(int i=0;i<unsorted.length;i++){
			System.out.println(unsorted[i]);
		}
	}
	public static void main(String[] args) {
		int[] x={6,2,4,1,5,9};
		selectionsort(x);
 	}
}

希尔排序要快于前三个排序算法,而快速排序和归并排序的整个算法的时间代价为 θ(nlogn)。

希尔排序:

希尔排序Shell Sort是基于插入排序的一种改进,同样分成两部分,

第一部分,希尔排序介绍

第二部分,如何选取关键字,选取关键字是希尔排序的关键

第一块希尔排序介绍

准备待排数组[6 2 4 1 5 9]

首先需要选取关键字,例如关键是3和1(第一步分成三组,第二步分成一组),那么待排数组分成了以下三个虚拟组:

[6 1]一组

[2 5]二组

[4 9]三组

看仔细啊,不是临近的两个数字分组,而是3(分成了三组)的倍数的数字分成了一组,

就是每隔3个数取一个,每隔三个再取一个,这样取出来的数字放到一组,

把它们当成一组,但不实际分组,只是当成一组来看,所以上边的"组"实际上并不存在,只是为了说明分组关系

对以上三组分别进行插入排序变成下边这样

[1 6] [2 5] [4 9]

具体过程:

[6 1]6和1交换变成[1 6]

[2 5]2与5不动还是[2 5]

[4 9]4与9不动还是[4 9]

第一趟排序状态演示:

待排数组:[6 2 4 1 5 9]

排后数组:[1 2 4 6 5 9]

第二趟关键字取的是1,即每隔一个取一个组成新数组,实际上就是只有一组啦,隔一取一就全部取出来了嘛

此时待排数组为:[1 2 4 6 5 9]

直接对它进行插入排序

[1 2 4]都不用动,过程省略,到5的时候,将5取出,在前边的有序数组里找到适合它的位置插入,就是4后边,6前边

后边的也不用改,所以排序完毕

顺序输出结果:[1 2 4 5 6 9]

第二块希尔排序的关键是如何取关键字,因为其它内容与插入排序一样

那么如何选取关键字呢?就是分成三组,一组,这个分组的依据是什么呢?为什么不是二组,六组或者其它组嘞?

好的增量序列的共同特征:

① 最后一个增量必须为1

② 应该尽量避免序列中的值(尤其是相邻的值)互为倍数的情况

参见 http://baike.baidu.com/view/2217047.htm

增量的取值规则为第一次取总长度的一半,第二次取一半的一半,依次累推直到1为止

http://www.cnblogs.com/huangxincheng/archive/2011/11/20/2255695.html

public class shell_sort {
	public static void shellsort(int[] unsorted,int len){
		int group,i,j,temp;
		for(group=len/2;group>0;group/=2){
			for(i=group;i<len;i++){
				for(j=i-group;j>=0;j-=group){
					if(unsorted[j]>unsorted[j+group]){
						temp=unsorted[j];
						unsorted[j]=unsorted[j+group];
						unsorted[j+group]=temp;
					}
				}
			}
		}
		for(i=0;i<unsorted.length;i++){
			System.out.println(unsorted[i]);
		}
	}
	public static void main(String[] args){
		int[]x={6,2,4,1,5,9};
		shellsort(x,x.length);
	}
}

快速排序:

原理,通过一趟扫描将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列

举个例子

如无序数组[6 2 4 1 5 9]

a),先把第一项[6]取出来,

用[6]依次与其余项进行比较,

如果比[6]小就放[6]前边,2 4 1 5都比[6]小,所以全部放到[6]前边

如果比[6]大就放[6]后边,9比[6]大,放到[6]后边,//6出列后大喝一声,比我小的站前边,比我大的站后边,行动吧!霸气十足~

一趟排完后变成下边这样:

排序前 6 2 4 1 5 9

排序后 2 4 1 5 6 9


b),对前半部分[2 4 1 5]继续进行快速排序

重复步骤a)后变成下边这样:

排序前 2 4 1 5

排序后 1 2 4 5

前半部分排序完成,总的排序也完成:

排序前:[6 2 4 1 5 9]

排序后:[1 2 4 5 6 9]

排序结束


public class quick_sort {
	public static int partition(int[] unsorted,int low,int high){
		int pivot = unsorted[low];
		while(low<high){
			while(low<high&&unsorted[high]>pivot)
				high--;
			unsorted[low]=unsorted[high];
			while(low<high&&unsorted[low]<=pivot)
				low++;
			unsorted[high]=unsorted[low];
		}
		unsorted[low]=pivot;
		return low;
	}
	public static void quicksort(int[] unsorted,int low,int high){
		int loc=0;
		if(low<high){
			loc=partition(unsorted,low,high);
			quicksort(unsorted,low,loc-1);
			quicksort(unsorted,loc+1,high);
		}
		
	}
	public static void main(String[] args) {
		int[] x={6,2,4,1,5,9};
		quicksort(x,0,x.length-1);
		for(int i=0;i<x.length;i++){
			System.out.println(x[i]);
		}
 	}
}
归并排序:

原理,把原始数组分成若干子数组,对每一个子数组进行排序,

继续把子数组与子数组合并,合并后仍然有序,直到全部合并完,形成有序的数组

举例

无序数组[6 2 4 1 5 9]

先看一下每个步骤下的状态,完了再看合并细节

第一步 [6 2 4 1 5 9]原始状态

第二步 [2 6] [1 4] [5 9]两两合并排序,排序细节后边介绍

第三步 [1 2 4 6] [5 9]继续两组两组合并

第四步 [1 2 4 5 6 9]合并完毕,排序完毕

输出结果[1 2 4 5 6 9]

合并细节

详细介绍第二步到第三步的过程,其余类似

第二步:[2 6] [1 4] [5 9]

两两合并,其实仅合并[2 6] [1 4],所以[5 9]不管它,

原始状态

第一个数组[2 6]

第二个数组[1 4]

--------------------

第三个数组[...]

 

第1步,顺序从第一,第二个数组里取出一个数字:2和1

比较大小后将小的放入第三个数组,此时变成下边这样

第一个数组[2 6]

第二个数组[4]

--------------------

第三个数组[1]

 

第2步,继续刚才的步骤,顺序从第一,第二个数组里取数据,2和4,

同样的比较大小后将小的放入第三个数组,此时状态如下

第一个数组[6]

第二个数组[4]

--------------------

第三个数组[1 2]

 

第3步,再重复前边的步骤变成,将较小的4放入第三个数组后变成如下状态

第一个数组[6]

第二个数组[...]

--------------------

第三个数组[1 2 4]

 

第4步,最后将6放入,排序完毕

第一个数组[...]

第二个数组[...]

--------------------

第三个数组[1 2 4 6]

 

[ 1 2 4 6 ]与[ 5 9 ]的合并过程与上边一样


public class merge_sort {
	public static void merge(int[] unsorted,int first,int mid,int last,int[] sorted){
		int i=first,j=mid;
		int k=0;
		while(i<mid&&j<last){
			if(unsorted[i]<unsorted[j]){
				sorted[k++]=unsorted[i++];
			}else{
				sorted[k++]=unsorted[j++];
			}
		}
		while(i<mid)
			sorted[k++]=unsorted[i++];
		while(j<last)
			sorted[k++]=unsorted[j++];
		for(int v=0;v<k;v++)
			unsorted[first+v]=sorted[v];
	}
	public static void mergesort(int[] unsorted,int first,int last,int[] sorted){
		if(first+1<last){
			int mid=(first+last)/2;
			System.out.println("{0}-{1}-{2}"+first+mid+last);
			mergesort(unsorted,first,mid,sorted);
			mergesort(unsorted,mid,last,sorted);
			merge(unsorted,first,mid,last,sorted);
			
		}
	}
	public static void main(String[] args) {
		int[] x={6,2,4,1,5,9};
		int[] sorted=new int[x.length];
		mergesort(x,0,x.length,sorted);
		for(int i=0;i<sorted.length;i++){
			if(x[i]>0)
				System.out.println(x[i]);
		}
 	}
}


你可能感兴趣的:(数据结构,排序,冒泡排序,插入排序,快速排序)