排序算法(冒泡、选择、插入、希尔、归并、快排、堆排序)

 

package Sort;

public class sort {
	// https://www.cnblogs.com/onepixel/articles/7674659.html
	public static void main(String[] args) {
		int[] arr = { 2, 6, 3, 5, 7, 3, 6, 8 };
		HeapSort(arr);
		for (int i = 0; i < arr.length; i++) {
			System.out.print(arr[i] + " ");
		}
	}
	// 冒泡
	// 每次比较相邻的元素,如果第一个比第二个大就交换他们两个
	// 这样交换到最后,最后的元素是最大的
	// 针对除了最后一个元素以外的所有元素重复以上步骤
	public static void BubbleSort(int[] arr) {
		int len = arr.length;
		for (int i = 0; i < len - 1; i++) {
			for (int j = 0; j < len - 1 - i; j++) {
				if (arr[j] > arr[j + 1]) {
					int temp = arr[j + 1];
					arr[j + 1] = arr[j];
					arr[j] = temp;
				}
			}
		}
	}

	// 选择排序
	// 在未排序序列中找到最小的元素,放到排序序列的起始位置,
	// 然后再从剩余未排序元素中继续寻找最小的元素,放在已排序的末尾
	public static void SelectionSort(int[] arr) {
		int len = arr.length;
		int min = 0;
		for (int i = 0; i < len - 1; i++) {
			min = i;
			for (int j = i + 1; j < len; j++) {
				if (arr[j] < arr[min]) {
					min = j;
				}
			}
			if (min != i) {
				int temp = arr[i];
				arr[i] = arr[min];
				arr[min] = temp;
			}
		}
	}

	// 插入排序
	// 从第一个元素开始,该元素可以认为已经被排序
	// 取出下一个元素,在已经排序的元素序列中从后向前扫描
	// 找到他在已排序的序列中的位置
	public static void InsertSort(int[] arr) {
		int len = arr.length;
		for (int i = 1; i < len; i++) {
			for (int j = i; j > 0; j--) {
				if (arr[j] < arr[j - 1]) {
					int temp = arr[j];
					arr[j] = arr[j - 1];
					arr[j - 1] = temp;
				}
			}
		}
	}

	// 希尔排序
	// 插入排序的改进版,会优先比较距离较远的元素
	public static void Shell(int[] arr) {
		int n = arr.length;
		int h = 1;
		while (h < n / 3) {
			// 1,4,13……
			h = h * 3 + 1;
		}
		while (h >= 1) {
			for (int i = h; i < n; i++) {
				for (int j = i; j >= h; j--) {
					if (arr[j] < arr[j - h]) {
						int temp = arr[j];
						arr[j] = arr[j - h];
						arr[j - h] = temp;
					}
				}
				h = h / 3;
			}
		}
	}

	// 归并排序
	// 把长度为n的输入序列分成两个长度为n/2的子序列
	// 对这两个子序列分别采用归并排序
	// 将两个排序好的子序列合并成一个最终的排序序列
	public static void MergeSort(int[] arr, int start, int end) {
		if (arr == null || start >= end) {
			return;
		}
		int middle = (start + end) / 2;
		// 递归
		MergeSort(arr, start, middle);
		MergeSort(arr, middle + 1, end);
		// 归并
		Merge(arr, start, middle, end);
	}

	public static void Merge(int[] arr, int start, int mid, int end) {
		int[] array = new int[end + 1]; // 定义一个临时数组,用来存储排序后的结果
		int k = start; // 临时数组的索引
		int i = start;
		int j = mid + 1;
		// 取出最小值放入临时数组中
		while (i <= mid && j <= end) {
			array[k++] = arr[i] > arr[j] ? arr[j++] : arr[i++];
		}

		// 若还有段序列不为空,则将其加入临时数组末尾
		while (i <= mid) {
			array[k++] = arr[i++];
		}
		while (j <= end) {
			array[k++] = arr[j++];
		}

		// 将临时数组中的值copy到原数组中
		for (int m = start; m <= end; m++) {
			arr[m] = array[m];
		}

	}

	// 快速排序
	// 从数列中挑选一个数作为基准
	// 所有元素比基准小的放在基准前面,比基准大的放在基准后面,退出后,基准在中间位置
	// 递归
	public static void QuickSort(int[] a, int start, int end) {
		// 1,找到递归算法的出口
		if (start > end) {
			return;
		}
		// 2, 存
		int i = start;
		int j = end;
		// 3,key
		int key = a[start];
		// 4,完成一趟排序
		while (i < j) {
			// 4.1 ,从右往左找到第一个小于key的数
			while (i < j && a[j] > key) {
				j--;
			}
			// 4.2 从左往右找到第一个大于key的数
			while (i < j && a[i] <= key) {
				i++;
			}
			// 4.3 交换
			if (i < j) {
				int temp = a[i];
				a[i] = a[j];
				a[j] = temp;
			}
		}
		// 4.4,调整key的位置
		int temp = a[i];
		a[i] = a[start];
		a[start] = temp;
		// 5, 对key左边的数快排
		QuickSort(a, start, i - 1);
		// 6, 对key右边的数快排
		QuickSort(a, i + 1, end);
	}

	// 堆排序
	// 父节点的键值大于子节点
	// 构建大根堆:将array看成完全二叉树的顺序存储结构
	private static int[] buildMaxHeap(int[] array) {
		// 从最后一个节点array.length-1的父节点(array.length-1-1)/2开始,直到根节点0,反复调整堆
		for (int i = (array.length - 2) / 2; i >= 0; i--) {
			adjustDownToUp(array, i, array.length);
		}
		return array;
	}

	// 将元素array[k]自下往上逐步调整树形结构
	private static void adjustDownToUp(int[] array, int k, int length) {
		int temp = array[k];
		for (int i = 2 * k + 1; i < length - 1; i = 2 * i + 1) { // i为初始化为节点k的左孩子,沿节点较大的子节点向下调整
			if (i< length && array[i] < array[i + 1]) { // 取节点较大的子节点的下标
				i++; // 如果节点的右孩子>左孩子,则取右孩子节点的下标
			}
			if (temp >= array[i]) { // 根节点 >=左右子女中关键字较大者,调整结束
				break;
			} else { // 根节点 <左右子女中关键字较大者
				array[k] = array[i]; // 将左右子结点中较大值array[i]调整到双亲节点上
				k = i; // 【关键】修改k值,以便继续向下调整
			}
		}
		array[k] = temp; // 被调整的结点的值放人最终位置
	}

	// 堆排序
	public static void HeapSort(int[] array) {
		array = buildMaxHeap(array); // 初始建堆,array[0]为第一趟值最大的元素
		for (int i = array.length - 1; i >=1; i--) {
			int temp = array[0]; // 将堆顶元素和堆低元素交换,即得到当前最大元素正确的排序位置
			array[0] = array[i];
			array[i] = temp;
			adjustDownToUp(array, 0, i); // 整理,将剩余的元素整理成堆
		}
	}


}

猜你喜欢

转载自blog.csdn.net/wenyimutouren/article/details/82251096