常见的排序算法Java源码示例

排序算法源码示例


代码将常见的排序算法源码放在一个类中。本文算法已经经过验证,可以直接拿来进行使用。源码中主要包含插入排序(直接插入排序,二分插入排序,希尔排序),交换排序(冒泡排序,快速排序(由quick,partition两个方法完成)),选择排序(简单选择排序,堆排序(由heap,buildMaxHeap,adjustDown三个方法完成)),归并排序(举例了二路归并排序的例子,由mergefrom2和merge两个方法完成)

public class Sort{
	//插入排序
	class InsertSort{
		/**
	     * 插入排序
	     * 将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。
	     * 从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)
	     * 时间复杂度 O(n^2) 稳定  有相同元素则往后插入,不会改变相对位置
	     *
	     * @param src
	     */
		public void direct(int[] src){
			for (int i = 1; i < src.length; i++) {
	            //i 表示处理第几个元素 内层循环j用来前半段的有序插入 先找到插入的位置,然后将元素全部后移
	            int insertIndex = i;
	            for (int j = 0; j < i; j++) {
	                if (src[i] < src[j]) {
	                    insertIndex = j;
	                    //找到下标后立即退出内层循环
	                    break;
	                }
	            }
	            //后移所有元素之前,先暂存当前需要插入的位置的元素,等插入结束后再补齐改元素
	            int temp = src[i];
	            for (int k = i; k > insertIndex; k--) {
	                src[k] = src[k - 1];
	            }
	            src[insertIndex] = temp;
	        }
		}
		//二分插入排序
		public void half(int[] src){
			int length = src.length;
			for(int i=1; i<length; i++){
				int temp = src[i];
				int left = 0;
				int right = i-1;
				while(left<=right){
					int mid = (left+right)/2;
					if(temp < src[mid])
						right = mid - 1;
					else
						left = mid + 1;
				}
				for(int j=i; j>left; j--)
					src[j] = src[j-1];
				src[left] = temp;
			}
		}
		/**
	     * 希尔排序
	     * 是先将数组分为 src/d个组,对每个组进行直接插入排序
	     * 第二轮 d = d/2 在进行直接插入排序 ,一直这样进行下去
	     * 最后一轮的 d=1 即全组的直接插入排序
	     *
	     * @param src
	     */
		public void shell(int[] src){
			int groupNum = src.length >> 2;
	        while (groupNum > 0) {
	            for (int i = groupNum; i < src.length; i++) {
	                int insertIndex = i;
	                for (int j = 0; j < i; j++) {
	                    if (src[i] < src[j]) {
	                        insertIndex = j;
	                        break;
	                    }
	                }
	                int temp = src[i];
	                for (int k = i; k > insertIndex; k--) {
	                    src[k] = src[k - 1];
	                }
	                src[insertIndex] = temp;
	            }
	            groupNum >>= 2;
	        }
		}
	}
	//交换排序
	class SwapSort{
		/**
	     * 冒泡排序
	     * 两两比较相邻的元素,将最大的放在后面
	     * 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
	     * O(n^2) 稳定的 因为 src[j] < src[j - 1] 没加等号,所以想等的元素相对位置不会发生改变
	     * @param src
	     */
		public void bubble(int[] src){
			int length = src.length-1;
			for(int i=0; i<length; i++){
				boolean flag = false;
				for(int j=length; j>i; j--)
					if(src[j] < src[j-1]){
						int temp = src[j];
						src[j] = src[j-1];
						src[j-1] = temp;
						flag = true;
					}
				if(!flag)
					return ;
			}
		}
		/**
	     * 快速排序
	     * 基本思想是基于分治的,在待排序的序列中选取一个元素作为基准,通过一趟排序将待排序表划分为独立的两部分,
	     * 部分都小于该元素,一部分都大于该元素。而后分别递归两个子序列,直到每个部分都只有一个元素或为空为止。
	     * O(n*log(n)) 不稳定
	     *
	     * @param src
	     */
		public void quick(int[] src, int left, int right){
			if(left < right){
				int pivot = partition(src, left, right);
				quick(src, left, pivot-1);
				quick(src, pivot+1, right);
			}
		}
		/**
	     * 返回基准值的最终下标,并且把基准值放在最终位置
	     *
	     * @param src
	     * @param low
	     * @param high
	     * @return
	     */
		public int partition(int[] src, int left, int right){
			int pivot = src[left];
			while(left < right){
				while(left < right && src[right] >= pivot)
					--right;
				src[left] = src[right];
				while(left < right && src[left] <= pivot)
					++left;
				src[right] = src[left];
			}
			src[left] = pivot;
			return left;
		}
	}
	//选择排序
	class SelectSort{
		/**
	     * 选择排序
	     * 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置
	     * 再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
	     * 重复第二步,直到所有元素均排序完毕。
	     * 时间复杂度 O(n^2) 不稳定. 举个例子,序列5 8 5 2 9, 我们知道第一遍选择第1个元素5会和2交换,那么原序列中2个5的相对前后顺序就被破坏了,所以选择排序不是一个稳定的排序算法。
	     *
	     * @param src
	     */
	    public static void sort(int[] src) {
	
	        for (int i = 0; i < src.length - 1; i++) {
	            int minIndex = i;
	            for (int j = i + 1; j < src.length; j++) {
	                minIndex = src[j] < src[minIndex] ? j : minIndex;
	            }
	            int temp = src[i];
	            src[i] = src[minIndex];
	            src[minIndex] = temp;
	        }
	    }
		/**
	     * 堆排序
	     * 看成是完全二叉树序列,利用完全二叉树和孩子节点的内在关系,在当前的无序区中选择关键字最小的,
	     * 输出,然后将最后一个元素和堆顶元素进行交换,破坏了堆结构,再进行调整,直至最后一个(完成排序)
	     * 步骤 1.构造初始堆   2.调整堆结构  3.输出根节点  4.将最后一个叶子节点和堆根元素互换位置  5.调整堆结构
	     * 构建大根堆(升序). 小根堆(降序)
	     * 时间复杂度 O(n*log(n)) 不稳定
	     *
	     * @param src
	     */
		public void heap(int[] src){
			//构建的是大根堆
	        buildMaxHeap(src);
	        // 通过这个数组调整,最大的元素放到最后了
	        for (int i = src.length - 1; i > 0; i--) {
	            int temp = src[i];
	            src[i] = src[0];
	            src[0] = temp;
	            adjustDown(src, 0, i - 1);
	        }
		}
		/**
	     * 建立初始的大根堆
	     *
	     * @param src
	     */
		public void buildMaxHeap(int[] src){
			for(int i=(src.length-1)/2; i>=0; i--)
				adjustDown(src, i, src.length-1);
		}
		    /**
		     * 调整堆元素 调整 以i为根节点,到j结束的堆为 大根堆
		     *
		     * @param src
		     * @param i
		     * @param j
		     */
		    private static void adjustDown(int[] src, int i, int j) {
		        int temp = src[i];
		        for (int k = 2 * i + 1; k <= j; k = k*2 +1) {
		            //将k的值变为左右儿子中较大的那个的下标 k为左儿子 k+1 为右儿子
		            if (k < j && src[k] < src[k + 1]) {
		                k++;
		            }
		            //如果父亲比儿子中较大的那个还大,则不需要交换了
		            if (temp > src[k]) {
		                break;
		            } else {
		                src[i] = src[k];
		                i = k;
		            }
		        }
		        src[i] = temp;
		    }
	}
	//归并排序
	class MergeSort{
		/**
	     * 归并排序
	     * 二路并归排序
	     * 将两个有序的表组合成一个新的有序表。假定待排序表含有n个记录,则可看成是n个有序表,每个表的长度为1,
	     * 然后两两归并,直到合并成一个长度为n的有序表为止.
	     * 时间复杂度 O(n*log(n)) 稳定
	     *
	     * @param src
	     */
		public void mergefrom2(int[] src, int left, int right){
			if(left < right){
				int mid = (left+right) / 2;
				mergefrom2(src, left, mid);
				mergefrom2(src, mid+1, right);
				merge(src, left, mid, right);
			}
		}
		public void merge(int[] src, int left, int mid, int right){
			int[] src0 = new int[src.length];
			System.arraycopy(src, 0, src0, 0, src.length);
			int i,j,k;
			for(i=left, j=mid+1, k=i; i<=mid && j<=right; k++)
				src[k] = src0[i] <= src0[j] ? src0[i++] : src0[j++];
			while(i<=mid) src[k++] = src0[i++];
			while(j<=right) src[k++] = src0[j++];
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值