排序算法java实现--插入法

        排序是接触算法导论的时候最先接触的算法,也是学生时代打交道最多的算法。这几天把几种不同的算法好好回忆一下,包括自己最不熟悉的外排序。

         插入排序算法,包括直接插入排序,二分插入排序和希尔排序。

        直接上代码

         main函数:

public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[] is = new int[MAX];
		int[] shell = new int[MAX / 2];
		for (int i = 0; i < shell.length; i++) {
			if (i == 0) {
				shell[i] = MAX / 2;
			} else {
				shell[i] = shell[i - 1] / 2;
			}
		}
		shell[shell.length - 1] = 1;
		for (int i = 0; i < MAX; i++) {
//			is[i] = new Random().nextInt(MAX);
//			is[i] = i;
			is[i] = MAX - i;
		}
		long start = System.currentTimeMillis();
		
		shellSort(is, shell);
//		directSort(is);
//		binarySort(is);
		long end = System.currentTimeMillis();
		System.out.println("程序执行了" + (end - start) + "毫秒");
	}

          直接插入排序:

/**
	 * @Title: directSort
	 * @Description: TODO(直接排序)
	 * @param 设定文件
	 * @return void 返回类型
	 */
	public static void directSort(int[] is) {
		/**
		 * 第0个是已经排好序的,所以从第一个开始插入
		 */
		for (int i = 1; i < is.length; i++) {
			/**
			 * 每一个元素与前边已经排好的元素做比较
			 */
			int k;
			int temp = is[i];
			for (k = i - 1; k >= 0 && is[k] > temp; k--) {
				is[k + 1] = is[k];
			}
			is[k + 1] = temp;
		}
	}

 直接插入排序的思想最容易理解,就是设想第i个元素前边是已经排序好的数列,像插扑克牌一样,从后往前对比,把第i个元素插到合适的位置。

对100万个随机数进行排序,直插法耗时1分56秒

程序执行了116072毫秒

 对100万个已经排序的数组进行排序,直插法耗时5毫秒。。。

对100万个逆序的数组进行排序,直插法耗时6分钟。。。

程序执行了249916毫秒

     二分插入排序:

    

/**
	 * @Title: binarySort
	 * @Description: TODO(二分插入排序)
	 * @param @param is 设定文件
	 * @return void 返回类型
	 */
	private static void binarySort(int[] is) {
		/**
		 * 第0个是已经排好序的,所以从第一个开始插入
		 */
		for (int i = 1; i < is.length; i++) {
			/**
			 * 每一个元素与前边已经排好的元素做比较
			 */
			int temp = is[i];
			int left = 0;
			int right = i - 1;
			int mid = (left + right) / 2;
			while (left <= right) {
				if (temp > is[mid]) {
					left = mid + 1;
				} else {
					right = mid - 1;
				}
				mid = (left + right) / 2;
			}
			reverse(is, i, left);
		}
	}

           这种方法也是设想第i个元素前边是已经排序好的数列,不过在插入的时候不是用插纸牌的方法,而是用二分查找的手段,从中间查第i个纸牌应该插入的位置,然后插进去。这种方法比直接插入优越的地方在于如果是乱序的,那么查找的时候时间复杂度只有O(logn)。

           二分插入法排序1000000万个随机数耗时1分48秒:

程序执行了108423毫秒

            二分插入法排序1000000万个已排序的数组耗时42秒:

             二分插入法排序1000000万个倒序的数组耗时3分42秒:

程序执行了224106毫秒

 

           希尔排序:

/**
	 * @Title: shellSort
	 * @Description: TODO(希尔排序)
	 * @param @param is
	 * @return void 返回类型
	 */
	private static void shellSort(int[] is, int[] shell) {
		for (int i = 0; i < shell.length; i++) {
			int d = shell[i];
			for (int j = 0; j < d; j++) {
				for (int k = j + d; k < is.length; k = k + d) {
					int temp = is[k];
					int m;
					for (m = k - d; m >= 0 && is[m] > temp; m = m - d) {
						is[m + d] = is[m];
					}
					is[m + d] = temp;
				}
			}
		}
	}

            希尔排序类似于直接插入排序。他的思想主要是利用了如果在顺序的情况下,直接排序是几乎不耗时的。首先将原数组分成几个不同的数组分别排序,然后合并再次重新细分,直到最后对整个数组进行直接插入排序。但这时候数组基本有序了,所以时间消耗会小很多。

        比如数组{1,2,3,4},首先,希尔排序将数组分成两个子数组,{1,3}和{2,4},对两个子数组分别进行直接插入排序后合并然后再次直接插入排序。希尔排序的思想很像分治算法: 把一个大问题分成若干个小问题,利用小问题的结果来对大问题进行计算,从而使大问题得到优化。

       希尔排序1000000万个随机数耗时不到1秒。。。。:

程序执行了209毫秒

            希尔排序1000000万个已排序的数组耗时66毫秒:

             希尔排序1000000万个倒序的数组耗时82毫秒。

          由以上对比可以发现,对于插入排序来说,在数组几乎排好序的情况下,直接插入排序最好,但现实中这种情况不多,现实中大多是乱序情况,这种情况下希尔排序秒杀其他两种插入排序方法。

猜你喜欢

转载自709002341.iteye.com/blog/2254527