直接插入排序

直接插入排序(Straight Insertion Sort) 

基本思想:

先把要排序的数组分成两部分,第一部分只包含第一个元素,天然有序,而第二部分则包含了数组中除开第一个元素剩余的所有元素。然后依次将第二部分中的每一个元素插入到已经有序的第一部分中,并且仍保持第一部分有序。每次插入一个元素,有序部分将增加一个元素。

重复此过程,直到最后有序部分包含所有元素。


当然,有序部分也可以是最后一个元素。


好了,话不多说,上图。

初始数组如下:


第一步:进行划分。第一个元素 4 为初始有序部分,其余元素为无序部分。即红线左边为有序部分,右边为无序部分。


第二步:从无序部分的元素中依次找出一个元素插入到左边,并且保持插入后仍然有序。这里先将元素 2 插入到左边的有序部分。

<第一次插入>        2 < 4,因此将 2 插入到 4 的左边

此时,有序部分变成了 2、4, 接着,


第三步:将元素 3 插入到左边,并且保持插入后仍然有序。

<第二次插入>        3 < 4,3 > 2,因此将 3 插入到 2 和 4 的中间

此时,有序部分变成了 2、3、4, 继续,


第四步:将元素 5 插入到左边,并且保持插入后仍然有序。

<第三次插入>        5 > 4,将 5 直接插入到 4 的右边

此时,左边的有序部分变成了 2、3、4、5, 接着


第五步:将元素 1 插入到左边,并且保持插入后仍然有序。

<第四次插入>        1 < 5, 1 < 3, 1 < 2, 因此将 1 插入到 2 的左边

此时,所有元素都已经插入到了左边的有序部分,数组已经有序,排序结束。


其实,我们也看到了,插入排序的核心在于将无序部分元素插入到有序部分中,并且还得保持仍然有序。

就上边的情况来说,设定的是第一个元素为初始有序部分,余下元素为无序部分。其实,前面提到过,最后一个元素为初始有序部分也是可以的。完整的测试代码中包含了这种情况。


算法实现:    

/**
	 * 插入排序,最前一位作为有序部分
	 * @param arr 待排序数组
	 */
	public void insertionSort(int[] arr) {
		int length = arr.length;
		int j = 0;
		int temp = 0;
		
		for (int i = 1; i < length; i++) {
			temp = arr[i]; // 存储待插入元素的值
			for (j = i; j > 0; j--) { // 找到一个合适的插入位置
				if (arr[j - 1] > temp) 
					arr[j] = arr[j - 1]; // 依次向右移动已经排好序的元素,为待插入元素留出位置
				else // 若后面的不小于前面的,则不用移动,因为前面的已经排好序了
					break;
			}
			arr[j] = temp; // 将待插入元素插入到指定位置
		}
	}

算法测试:

package algorithms;

import java.util.Arrays;
import java.util.Random;

/**
 * 插入排序
 * @author Wll
 *
 */
public class InsertionSortTest {
	public static void main(String[] args) {
		int[] arr = getRandomArray(9, 1000);
		int[] arr2 = Arrays.copyOf(arr, arr.length);
		System.out.println("插入排序");
		System.out.print("初始数组:");
		printArray(arr);
		
		System.out.println("第一位 " + arr[0] + " 为初始有序部分:");
		insertionSort(arr);
		
		System.out.println();
		
		System.out.println("最后一位 " + arr2[arr2.length - 1] + " 为初始有序部分:");
		insertionSort2(arr2);
	}
	
	/**
	 * 插入排序,最前一位作为有序部分
	 * @param arr 待排序数组
	 */
	private static void insertionSort(int[] arr) {
		int length = arr.length;
		int j = 0;
		int temp = 0;
		
		for (int i = 1; i < length; i++) {
			temp = arr[i]; // 存储待插入元素的值
			for (j = i; j > 0; j--) { // 找到一个合适的插入位置
				if (arr[j - 1] > temp) 
					arr[j] = arr[j - 1]; // 依次向右移动已经排好序的元素,为待插入元素留出位置
				else // 若后面的不小于前面的,则不用移动,因为前面的已经排好序了
					break;
			}
			arr[j] = temp; // 将待排序元素插入到指定位置
			
			// 打印每一趟排序的结果
			System.out.print("第" + i + "趟插入" + temp + ": ");
			for (int k = 0; k < length; k++) {
				if (k == (i + 1))
					System.out.print("|"); // 使用|分隔有序和无序部分
				
				if (k == j)
					System.out.print("▲"); // 为插入元素做标记
				
				System.out.print(arr[k] + "  ");
			}
			System.out.println("\n");
		}
	}
	
	/**
	 * 插入排序,最后一位作为有序部分
	 * @param arr 待排序数组
	 */
	private static void insertionSort2(int[] arr) { 
		int length = arr.length;
		int j = 0;
		int temp = 0;
		
		for (int i = length - 2; i >= 0; i--) {
			temp = arr[i];
			for (j = i; j < length - 1; j++) {
				if (arr[j + 1] < temp)
					arr[j] = arr[j + 1];
				else
					break;
			}
			arr[j] = temp;

			// 打印每一趟排序的结果
			System.out.print("第" + (length - i - 1) + "趟插入" + temp + ": ");
			for (int k = 0; k < length; k++) {
				if (k == j)
					System.out.print("▲"); // 为插入元素做标记
				
				System.out.print(arr[k] + "  ");
				
				if (k == i-1)
					System.out.print("|"); // 使用|分隔有序和无序部分
			}
			System.out.println("\n");
		}
	}
	
	
	/**
	 * 打印数组
	 * @param arr 待打印数组
	 */
	private static void printArray(int[] arr) {
		int length = arr.length;
		for (int i = 0; i < length; i++)
			System.out.print(arr[i] + " ");
		System.out.println();
		System.out.println();
	}
	
	/**
	 * 获得一个随机整型数组
	 * @param size 数组大小
	 * @param limit 数组元素大小的上限
	 * @return 一个随机数组
	 */
	private static int[] getRandomArray(int size, int limit) {
		int[] arr = new int[size];
		Random random = new Random();
		for (int i = 0; i < size; i++)
			arr[i] = random.nextInt(limit);
		
		return arr;
	}
}

运行情况:


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值