JAVA代码实现冒泡、选择、插入、希尔排序

冒泡、选择、插入、希尔排序

今天学习了八大算法中的冒泡、选择、插入、希尔排序算法。以数据从小到大排序为例,谈一谈自己的理解。有错误之处,还望指出,我会及时改正。

1. 冒泡排序
冒泡排序每次将相邻元素进行比较,较大的数放在后面,每轮下来,最大的数都会被交换到最后,并且下一轮不需要进行排序了。通过双重for循环实现,平均和最差时间复杂度为O(n^2)。

package com.sort.bubbleSort;

import java.util.Arrays;

/*
 * 冒泡排序
 */
public class BubbleSortDemo2 {

	public static void main(String[] args) {
		int[] array = { 5, 9, 8, 3, 2, 0, 1 };
		System.out.println("排序前:" + Arrays.toString(array));
		bubbleSort(array);
		System.out.println("排序后:" + Arrays.toString(array));

	}

	// 冒泡排序
	public static void bubbleSort(int[] array) {
		int temp = 0;
		boolean flag = false;
		// 共执行array.length-1
		for (int i = 0; i < array.length - 1; i++) {
			// 每轮都会将最大的数放到最后,所以每轮只需要执行array.length-1-i次
			for (int j = 0; j < array.length - 1 - i; j++) {
				if (array[j] > array[j + 1]) {
					flag = true;
					temp = array[j + 1];
					array[j + 1] = array[j];
					array[j] = temp;
				}
			}

			// 每轮排序完,检查一下该轮是否有数调整位置了
			if (!flag) {// 如果没有数调整位置,说明已经有序了
				break;
			} else {
				flag = false;
			}
		}
	}

}

2. 选择排序
每轮将最小的数放在前面,直至放完。平均和最差时间复杂度为O(n^2)。

package com.sort.selectionSort;

import java.util.Arrays;

/*
 * 选择排序
 */
public class SelectSortDemo2 {

	public static void main(String[] args) {
		int[] array = { 5, 9, 8, 3, 2, 0, 1 };
		System.out.println("排序前:" + Arrays.toString(array));
		selectSort(array);
		System.out.println("排序后:" + Arrays.toString(array));

	}

	// 选择排序
	public static void selectSort(int[] array) {
		int min = 0;// 记录最小值
		int minIndex = 0;// 记录最小值的下标
		// 一共需要排序array.length-1轮
		for (int i = 0; i < array.length - 1; i++) {
			// 假定每轮的第一个数就是最小值
			min = array[i];
			minIndex = i;
			// 每轮会将最小的值放在最前面,所以每轮从第i+1个数开始
			for (int j = i + 1; j < array.length; j++) {
				if (min > array[j]) {// 说明假定的最小值并不是真正的最小值
					// 将更小的那个值标记为最小值
					min = array[j];
					minIndex = j;
				}
			}
			// 每轮找到最小值后,将最小值和开始假定的最小值交换位置
			if (minIndex != i) {
				array[minIndex] = array[i];
				array[i] = min;
			}
		}
	}

}


3. 插入排序
插入排序的思想是将一堆数分成有序表和无序表两类,每轮从无序表中取一个数按顺序放到有序表中,直至放完。平均和最差时间复杂度为O(n^2)。

package com.sort.insertSort;

import java.util.Arrays;

/*
 * 插入排序
 */
public class InsertSortDemo2 {

	public static void main(String[] args) {
		int[] array = { 5, 9, 8, 3, 2, 0, 1 };
		System.out.println("排序前:" + Arrays.toString(array));
		insertSort(array);
		System.out.println("排序后:" + Arrays.toString(array));

	}

	// 插入排序
	/*
	 *  思路分析:
	 *    1.插入排序的思想是将一堆数分成有序和无序两部分,每次从无序组的中取一个数核有序组进行比较,放入有序组
	 *    2.将array数组的第一个数看作一个有序组,后面的n-1个数看作无序组;
	 *    3.从第2个数开始,每取一个数就按顺序插入到有序组中
	 *    4.记录每次待插入的数,记录每次待插入数前面的那个数的下标
	 *    5.以从小到大排序为例,那么每次待插入数的前一个数,即有序组的最后一个数,这个数肯定是最大的,
	 *      如果待插入的数小于这个最大数,说明位置没找到插入位置,就需要跟最大数前面那个数进行比较,以此类推(下标往前移动)
	 *      直到待插入的数比有序组中某个数大时,插入位置就找到了,就是那个数的位置
	 *    6.交换位置即可
	 *    举例:{101, 34, 119, 1,-1,89}==>34  {101, 101, 119, 1,-1,89}==>{34, 101, 119, 1,-1,89}
	 *        {34, 101, 119, 1,-1,89}==>119 {34, 101, 119, 1,-1,89}==>{34, 101, 119, 1,-1,89}
	 *        {34, 101, 119, 1,-1,89}==>1 {34, 101, 119, 119,-1,89}==>{34, 101, 101, 119,-1,89}==>{34, 34, 101, 119,-1,89}==>{1, 34, 101, 119,-1,89}
	 */
	public static void insertSort(int[] array) {
		// 先将array中的第一个元素设为有序表,后面n-1个元素为无序表,接下来每次从无序表中取一个数据插入到有序表中,所以需要array.length-1轮
		int insertVal = 0;// 待插入的数
		int insertIndex = 0;// 待插入的位置
		for (int i = 1; i < array.length; i++) {
			// 每次从无序表中取第一个数作为待插入数
			insertVal = array[i];
			// 将待插入数的前一个位置记录下来,也就是有序表中最大数的位置
			insertIndex = i - 1;
			// 从有序表中最大数的位置开始找,如果待插入的数小于这个最大数,就找打插入位置了,否则,往前移动(将这个最大的数赋值给后一个数),直到遍历到有序表中的第一个数,也就是最小的那个数为止
			while (insertIndex >= 0 && insertVal < array[insertIndex]) {
				array[insertIndex + 1] = array[insertIndex];
				insertIndex--;
			}
			// 遍历结束,说明找到待插入数的位置了
			if (insertIndex + 1 != i) {// 待插入位置就是自己目前的位置就不用移动(里面就一行代码,对性能几乎没有提升,也可以不做判断)
				array[insertIndex + 1] = insertVal;
			}
			System.out.println("第" + i + "轮排序" + Arrays.toString(array));
		}
	}

}

4. 希尔排序
希尔排序是一种改进的插入排序。当较小的数比较靠后时,如果使用直接插入排序会移动很多数,这样导致性能很低,希尔排序通过设定步长进行分组排序的方式,提高了较小数靠后时排序的性能。其平均时间复杂度为O(nlogn),最坏时间复杂度为O(n^2)。其方式有两种,一是交换法,二是移动法。

package com.sort.shellSort;

import java.util.Arrays;

/*
 * 希尔排序
 */
public class ShellSortDemo2 {

	public static void main(String[] args) {
		int[] array = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
		System.out.println("排序前:" + Arrays.toString(array));
		shellSort2(array);
		System.out.println("排序后:" + Arrays.toString(array));

	}

	// 希尔排序(交换法)---不提倡,交换数据对性能有影响
	public static void shellSort1(int[] array) {
		int temp = 0;
		int count = 0;
		// 计算每轮的步长,,每轮的步长也是每轮的组数
		for (int gap = array.length / 2; gap > 0; gap /= 2) {
			// 每轮有gap组,每组的第一个数作为有序表,不参与排序,所以每轮需要排 array.length-gap次
			for (int i = gap; i < array.length; i++) {
				// 每组的数间隔为gap
				for (int j = i - gap; j >= 0; j -= gap) {
					if (array[j] > array[j + gap]) {
						temp = array[j + gap];
						array[j + gap] = array[j];
						array[j] = temp;
					}
				}
			}
			System.out.println("第" + (++count) + "轮排序:" + Arrays.toString(array));
		}
	}

	// 希尔排序(移动法)---推荐
	public static void shellSort2(int[] array) {
		int count = 0;
		int insertVal = 0;// 待插入的数
		int insertIndex = 0;// 待插入数的前gap个数的下标
		// 计算每轮的步长,,每轮的步长也是每轮的组数
		for (int gap = array.length / 2; gap > 0; gap /= 2) {
			// 每轮有gap组,每组的第一个数作为有序表,不参与排序,所以每轮需要排 array.length-gap次
			for (int i = gap; i < array.length; i++) {
				// 先记录待插入的数
				insertVal = array[i];
				// 记录待插入数的前gap个数的下标
				insertIndex = i - gap;
				// 对比插入排序:如果前gap个数的下标不在数组的最前面,并且待插入的数小于前gap个数,那就将前gap个数的值赋给当前下标往前移动gap个之后,再比较
				while (insertIndex >= 0 && insertVal < array[insertIndex]) {
					array[insertIndex + gap] = array[insertIndex];
					insertIndex -= gap;
				}
				// 循环结束表示找到插入位置了,就将待插入的数插入到插入位置即可
				if (insertIndex + gap != i) {
					array[insertIndex + gap] = insertVal;
				}
			}
			System.out.println("第" + (++count) + "轮排序:" + Arrays.toString(array));
		}
	}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章