java中常见的排序——选择排序
选择排序的基本思想概述
- 选择排序:数组中的第一个数据与后面的数据依次比较,第一轮比较结束后最小的数据出现在第一位,与冒泡排序不同的是:第一轮比较结束之后,最大的数据出现在最大的索引位置,而且两个比较的数据都不是固定的,选择排序中有一个数据一定是固定的。
- 堆排序: 是一种树形选择排序,是对直接选择排序的有效改进。
堆:具有n个元素的序列(h1,h2…hn-1,hn),当且仅当满足hi>=h2i,hi>=2i+1,或者满足 hi<=2i,hi<=2i+1时(i=1,2…n/2),我们称之为 堆。堆顶的元素(第一个元素)必为最大项(大根堆),如果最小那就是小根堆。一个完全二叉树就可以很直观的表示堆的结构,堆顶为根,其他为左右子树。
那么这个堆排序的思想就是将一个将要排序的数组看做是一个顺序存储的二叉树,调整他们的存储顺序,使之成为一个堆,此时根节点的数据最大,让根节点的最大的数据与最后一个节点交换,然后对前面n-1个数据重新调整使之再成为堆,依次类推。总结就是三步走:A、建立堆(大根堆或小根堆);B、根节点与相对应位置的数据交换;C、重复AB,直到数组有序。
直接上代码
选择排序
public class SelectionSortDemo {
public static void main(String[] args) {
int[] arr = new int[] { 63, 4, 24, 1, 3, 4, 15 };
System.out.println("排序前:");
printArray(arr);
System.out.println("选择排序后:");
slectionSort(arr);
printArray(arr);
}
private static void slectionSort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
for (int j = i + 1; j < arr.length; j++) {
if (arr[i] > arr[j]) {
swap(arr, j, i);
}
}
printArray(arr);
}
}
private static void swap(int[] arr, int x, int y) {
int temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}
private static void printArray(int[] arr) {
for (int i : arr) {
System.out.print(i + " ");
}
System.out.println();
}
}
堆排序
public class HeapSortDemo {
public static void main(String[] args) {
int[] arr = new int[] { 63, 4, 24, 1, 3, 4, 15 };
System.out.println("排序前:");
printArray(arr);
System.out.println("堆排序后:");
heapSort(arr);
printArray(arr);
}
// 这里采用的是 建立大堆根
private static void heapSort(int[] arr) {
int arrayLength = arr.length;
// 循环建堆
for (int i = 0; i < arrayLength - 1; i++) {
// 建完一次堆之后,根节点位置的数据与相应位置的数据交换,再次建堆时位置固定的数据将不再参与建堆
buildMaxHeap(arr, arrayLength - 1 - i);
// 根节点位置的数据与相应位置的数据交换
swap(arr, 0, arrayLength - 1 - i);
printArray(arr);
}
}
// 对data数组从0到lastIndex建大顶堆
public static void buildMaxHeap(int[] data, int lastIndex) {
// 从lastIndex处节点(最后一个节点)的父节点开始
for (int i = (lastIndex - 1) / 2; i >= 0; i--) {
// k保存正在判断的节点
int k = i;
// 如果当前k节点的子节点存在
while (k * 2 + 1 <= lastIndex) {
// k节点的左子节点的索引
int biggerIndex = 2 * k + 1;
// 如果biggerIndex小于lastIndex,即biggerIndex+1代表的k节点的右子节点存在
if (biggerIndex < lastIndex) {
// 若果右子节点的值较大
if (data[biggerIndex] < data[biggerIndex + 1]) {
// biggerIndex总是记录较大子节点的索引
biggerIndex++;
}
}
// 如果k节点的值小于其较大的子节点的值
if (data[k] < data[biggerIndex]) {
// 交换他们
swap(data, k, biggerIndex);
// 将biggerIndex赋予k,开始while循环的下一次循环,重新保证k节点的值大于其左右子节点的值
k = biggerIndex;
} else {
break;
}
}
}
}
/**
* 交换arr数组中下标x 和 y的元素位置
*
* @param arr
* @param x
* @param y
*/
private static void swap(int[] arr, int x, int y) {
int temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}
/**
* 输出数组arr中的元素
*
* @param arr
*/
private static void printArray(int[] arr) {
for (int i : arr) {
System.out.print(i + " ");
}
System.out.println();
}
}