算法之七种排序

插入排序

public static void insertSort(int[] t){
		for(int i=1; i<t.length; i++){
			//将第i个数提取出来
			int temp = t[i];
			int j;
			for(j=i-1; j>=0 && temp<t[j]; j--){
				//如果提取出来的那个数小于t[j],数据里面的数就往后移。
				t[j+1] = t[j];
			}
			//提取出来的数大于或等于t[j],就插入到t[j]的后一个位置上(即t[j+1])
			t[j+1] = temp;
			
		}
	}

    时间复杂度:最好情况为O(n);   最坏情况为:O(n^2),是稳定的。

希尔排序

public static void shellSort(int[] t){
		//不断缩小比较数据之间的位置,直到变成插入排序
		for(int delta=t.length/2; delta>0; delta/=2){
			//原理和插入排序一样,
			//只是将1换成delta而已
			for(int i=delta; i<t.length; i++){
				int temp=t[i];
				int j;
				for(j=i-delta; j>=0 && temp<t[j]; j-=delta){
					t[j+delta] = t[j];
				}
				t[j+delta] = temp;
			}
		}
	}

    基本思想是分组的直接插入排序。时间复杂度为:O(n(㏒2n)²),那个2是指下标的2(下同),是不稳定的。


冒泡排序

public static void bubbleSort(int[] t){
		//是否交换的标记
		boolean exchange = true;
		//每循环一次,就会得到一个最大值
		for(int i=1; i<t.length && exchange; i++){
			exchange = false;			
			for(int j=0; j<t.length-i; j++){
				if(t[j]>t[j+1]){
					int temp = t[j+1];
					t[j+1] = t[j];
					t[j] = temp;
					exchange = true;
				}
				
			}
			
		}
	}

    基本思想是:比较相邻两个元素的关键字值,如果反序,则交换。如果按升序排序,每一趟将被扫描的数据序列中的最大元素交换到最后位置,就像气泡从水里冒出一样。
    时间复杂度:最好情况:O(n);   最坏情况:O(n²),是稳定的


快速排序

	public static void quickSort(int[] t){
		quickSort(t,0,t.length-1);
	}

	private static void quickSort(int[] t, int begin, int end) {
		//判断序列是否有效
		if(begin<end){			
			int i=begin, j=end;
			//提取基准值
			int vot = t[i];
			while(i!=j){
				//从后面寻找较小值
				while(i<j && vot <= t[j]){
					j--;
				}
				if(i<j){
					//较小值往前移动
					t[i++] = t[j];
				}
				//从前面寻找较大值
				while(i<j && t[i]<=vot){
					i++;
				}
				if(i<j){
					//较大值往后移动
					t[j--] = t[i];
				}
			}
			//确定基准值的位置
			t[i]=vot;
			//前端子序列在排序,递归调用
			quickSort(t,begin,j-1);
			//后端子序列在排序,递归调用
			quickSort(t,i+1,end);
			
		}
		
	}

    基本思想是:在数据序列中选择一个值作为比较的基准值,每趟从数据序列的两端开始交替进行,将小于基准值的元素交换到序列前端,将大于基准值的元素交换到序列后端,介于两者之间的位置则成为基准值的最终位置。同时,序列被划分成两个子序列,再用同样的方法分别对两个子序列进行排序,直到子序列的长度为1,则完成排序。
    时间复杂度:最好的情况:O(n*㏒2n);   最坏的情况:O(n²);是不稳定的。



直接选择排序

	public static void selectSort(int[] t){
		for(int i=0; i<t.length-1; i++){
			//标记最小值的位标
			int min=i;
			//遍历寻找最小值
			for(int j=i+1; j<t.length; j++){
				if(t[j]<t[min]){
					min=j;
				}
			}
			//将最小值交换到前面
			if(min!=i){
				int temp = t[i];
				t[i] = t[min];
				t[min] = temp;
			}
		}
	}

    基本思想:第一趟从n个元素的数据序列中选出关键字最小(或最大)的元素并放到最前(或最后)位置,下一趟再从n-1个元素中选出最小(大)的元素并放到次前(后)位置。以此类推,经过n-1趟完成排序。
    时间复杂度:最好情况:O(n²);    最坏情况:O(n²);    是不稳定的。


堆排序

	//将以begin为根的子树调整成最小堆
	private static void sift(int[] t,int begin, int end){
		//j为i结点的左孩子
		int i=begin, j=2*i+1;
		//子树根节点的值
		int temp=t[i];
		while(j<=end){
			//比较左右孩子,将j定位到最小那个
			if(j<end && t[j]>t[j+1]){
				j++;
			}
			if(temp>t[j]){
				//若子树根节点的值较大,
				//较小的孩子结点上移
				t[i]=t[j];	
				//使i,j向下一层
				i=j;
				j=2*i+1;
			}else{
				break;
			}
		}
		//当前子树的原根值调整后的位置
		t[i]=temp;
	}
	
	public static void heapSort(int[] t){
		int n=t.length;
		//创建最小堆
		for(int j=n/2-1; j>=0; j--){
			sift(t,j,n-1);
		}
		//每趟将最小值交换到后面,再调整成堆
		for(int j=n-1; j>0; j--){
			int temp = t[0];
			t[0] = t[j];
			t[j] = temp;
			sift(t,0,j-1);
		}
	}

    基本思想:首先和直接选择排序对比一下,在直接选择排序中,每趟从数据序列中选出一个最小值交换到前面,其余n-1个元素原地不动,下一趟需要再次比较这些元素,因此直接选择排序算法的重复比较很多。如果每趟能够利用前一趟的比较结果,则会减少一些重复比较,从而提高算法效率。堆排序就是利用完全二叉树的特性,每趟只需遍历树中的一条路径就行了,而不是全部元素。
    时间复杂度:最好最坏情况都是:O(n*㏒2n);    是不稳定的。


归并排序

	//对子序列元素的操作,
	//m和r分别是相邻的两个已排序子序列的起始下标,
	//n为子序列的长度
	private static void merge(int[] X, int[] Y, int m, int r, int n){
		int i=m, j=r, k=m;
		//将X中两个相邻子序列归并到Y中
		while(i<r && j<r+n && j<X.length){
			if(X[i] < X[j]){
				//将较小值复制到Y中
				Y[k++] = X[i++];
			}else{
				Y[k++] = X[j++];
			}
		}
		//将前一个子序列剩余元素复制到Y中
		while(i<r){
			Y[k++] = X[i++];
		}
		//将后一个子序列剩余元素复制到Y中
		while(j<r+n && j<X.length){
			Y[k++] = X[j++];
		}
	}
	
	
	//对子序列的操作
	private static void mergepass(int[] X, int[] Y, int n){
		int i = 0;
		
		while(i < X.length-n*2+1){
			merge(X, Y, i, i+n, n);
			i += 2*n;
		}
		//对于剩余不够2n的子序列的操作
		if(i+n < X.length){
			//尽管后一个子序列长度不够n,
			//但还是可以再来一次merge
			merge(X, Y, i, i+n, n);
			
		}else{
			for(int j=i; j<X.length; j++){
				Y[j]=X[j];
			}
			
		}
		
	}
	
	//对数组的操作
	public static void mergeSort(int[] X){
		int[] Y = new int[X.length];
		int n = 1;
		//一次while循环完成两趟并归,
		//数据序列从X到Y,再从Y到X,
		//使排序后的数据序列仍在数组X中
		while(n<X.length){
			mergepass(X,Y,n);
			n*=2;

			mergepass(Y,X,n);
			n*=2;
		}
	}

    基本思想:n个元素的数据序列可看成是由n个长度为1的排序子序列组成,反复讲相邻的两个子序列归并成一个排序的子序列,直到合并成一个序列,则排序完成。
    时间复杂度:最好最坏的情况都是:O(n*㏒2n);    是稳定的。



测试方法

public static void main(String[] args) {
		//创建一个数组
		int[] y = new int[10];
		//向数组赋值
		for(int i=0; i<y.length; i++){
			int a = new Random().nextInt(100);
			y[i] = a;
		}
		//执行排序方法
		selectSort(y);
		//打印排序后的数组
		for(int i=0; i<y.length; i++){
			System.out.println(y[i]);
		}
	}


    如果读者有什么更好的建议或疑问,欢迎在下面评论,一起交流进步。 微笑






猜你喜欢

转载自blog.csdn.net/u012367513/article/details/38459219