您的位置:首页 > 编程语言 > Java开发

基础排序算法 java 实现(冒泡、选择、插入、快排、归并、堆排)

2018-01-23 17:00 681 查看
package demo;

import java.util.Arrays;

public class SortUtil {
private static void printArr(int[] arr) {
System.out.println(Arrays.toString(arr));
}

private static void checkSort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
if (arr[i] > arr[i + 1]) {
throw new RuntimeException("Sort Error!");
}
}
}

private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}

// 本机测试
public static void main(String[] args) {
//        int[] arr = {4, 3, 5};

int[] arr = new int[50000 * 100];
java.util.Random random = new java.util.Random();
for (int i = 0; i < arr.length; i++) {
arr[i] = random.nextInt(arr.length);
}

//        System.out.println("排序前:");
//        printArr(arr);

long s = System.currentTimeMillis();

//        bubbleSort(arr);// 50000 数据 5000+ ms
//        selectSort(arr);// 50000 数据 1700+ ms
//        insertSort(arr);// 50000 数据 360+ ms

quickSort(arr, 0, arr.length - 1);// 50000 * 100 数据 770 ms

//        mergeSort(arr);// 50000 * 100 数据 1300 ms
//        mergeSort(arr, 0, arr.length - 1);// 50000 * 100 数据 1300 ms

//        heapSort(arr);// 50000 * 100 数据 1650 ms

long e = System.currentTimeMillis();
System.out.println("耗时:" + (e - s));

checkSort(arr);
System.out.println("排序正确!");

//        System.out.println("排序后:");
//        printArr(arr);
}

private static void bubbleSort(int[] arr) {
int len = arr.length;
for (int i = 0; i < len - 1; i++) { //要放置正确元素的目标位置,最后一个不用放
for (int j = len - 1; j > i; j--) { // 从后往前,把最小(大)的挪动到目标位置
if (arr[j] < arr[j - 1]) { // 后面的大于前面
swap(arr, j, j - 1);//如果没有发送交互则表示排序已经完成,但会多n次判断
}
}
}
}

private static void selectSort(int[] arr) {
int len = arr.length;
for (int i = 0; i < len - 1; i++) { //要放置正确元素的目标位置,最后一个不用放
int min = i;

for (int j = i + 1; j < len; j++) {
if (arr[j] < arr[min]) { // 后面的大于前面
min = j;
}
}

swap(arr, i, min);
}
}

private static void insertSort(int[] arr) {
for (int i = 1; i < arr.length; i++) {// 第一个不需要插入排序
int temp = arr[i];
int j = i - 1;
while (j >= 0 && temp < arr[j]) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = temp;
}
}

/*** quick ***/
private static void quickSort(int[] arr, int left, int right) {
if (left >= right) return;
int pivotIndex = partition(arr, left, right);
quickSort(arr, left, pivotIndex - 1);//排序 target 前面的
quickSort(arr, pivotIndex + 1, right);//排序 target 后面的
}

private static int partition(int[] arr, int left, int right) {
int pivot = arr[right];//堆排序是原地排序,这个额外空间可以省去的,这里为了语义明确在此声明
int target = left;
for (int i = left; i < right; i++) {
if (arr[i] < pivot) {
swap(arr, target++, i);
}
}
swap(arr, target, right);// target 已经处在正确的位置
return target;
}

/*** merge:递归实现 从外向里 ***/

private static void mergeSort(int[] arr, int left, int right) {
if (left == right) return;//待排序列长度为1
int middle = (left + right) / 2;
mergeSort(arr, left, middle);
mergeSort(arr, middle + 1, right);
merge(arr, left, middle, right);
}

/*** merge:迭代实现 从里向外 ***/
private static void mergeSort(int[] arr) {
int len = arr.length;
int left;//需要归并的左坐标
int middle;//需要归并的中坐标(定义为左侧的结束端坐标),也就是步长的最后一个
int right;//需要归并的右坐标
for (int mergeLen = 1; mergeLen < len; mergeLen *= 2) {
left = 0;
while (left + mergeLen < len) { // 有后面的数组需要归并
middle = left + mergeLen - 1;
right = middle + mergeLen < len ? middle + mergeLen : len - 1;
merge(arr, left, middle, right);
left = right + 1;
}
}
}

private static void merge(int[] arr, int left, int leftEnd, int right) {
int len = right - left + 1;
int[] temp = new int[len];//辅助空间
int tempIndex = 0;//辅助空间指针
int i = left;//左侧指针
int j = leftEnd + 1;//右侧指针
while (i <= leftEnd && j <= right) {
if (arr[i] <= arr[j]) {// 带等号保证归并排序的稳定性
temp[tempIndex++] = arr[i++];
} else {
temp[tempIndex++] = arr[j++];
}
}
while (i <= leftEnd) {
temp[tempIndex++] = arr[i++];//左侧数组未
}
while (j <= right) {
temp[tempIndex++] = arr[j++];
}
for (int k = 0; k < len; k++) {
arr[left + k] = temp[k];//将辅助空间内容替换至真实数组的 left-right 空间
}
}

/*** heap ***/
private static void heapSort(int[] arr) {
buildHeap(arr);//初始化大顶堆
int maxHeapIndex = arr.length - 1;
while (maxHeapIndex > 0) {// 堆(无序区)元素个数大于1,未完成排序
swap(arr, 0, maxHeapIndex--);// 此处交换操作很有可能把后面元素的稳定性打乱,所以堆排序是不稳定的排序算法
adjustHeap(arr, 0, maxHeapIndex);// 从新的堆顶元素开始向下进行堆调整,时间复杂度O(logn)
}
}

private static void buildHeap(int[] arr) { // 建堆,时间复杂度O(n)
int len = arr.length;
for (int i = len / 2 - 1; i >= 0; i--) {//从最后一个非叶子节点开始,向上调堆,当i==0时,所有堆成为最大堆
adjustHeap(arr, i, len - 1);
}
}

private static void adjustHeap(int[] arr, int i, int maxIndex) {
int leftChild = i * 2 + 1;
int rightChild = i * 2 + 2;
int max = i;
if (leftChild <= maxIndex && (arr[leftChild] > arr[max])) {
max = leftChild;
}
if (rightChild <= maxIndex && (arr[rightChild] > arr[max])) {
max = rightChild;
}
if (max != i) {
swap(arr, i, max);//把最大的换到当前堆顶,然后继续调剂被破坏的子堆
adjustHeap(arr, max, maxIndex);// 保证被破坏的子堆继续维持大顶堆性质
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐