Shell排序和插入排序

1.Shell排序算法

本人部分理论内容参考自这里,感兴趣者可以直接在此处查看。

Shell sort is a sorting algorithm that requires asymptotically fewer
than O(n²) comparisons and exchanges in the worst case. Although it is
easy to develop an intuitive sense of how this algorithm works, it is
very difficult to analyze its execution time, but estimates range from
O(nlog2 n) to O(n1.5) depending on implementation details.

Shell sort is a generalization of insertion sort, with two
observations in mind:

  1. Insertion sort is efficient if the input is “almost sorted”.
  2. Insertion sort is inefficient, on average, because it moves values just one position at a time.

Shell sort improves insertion sort by comparing elements separated by
a gap of several positions. This lets an element take “bigger steps”
toward its expected position. Multiple passes over the data are taken
with smaller and smaller gap sizes. The last step of Shell sort is a
plain insertion sort, but by then, the array of data is guaranteed to
be almost sorted.

简言之:希尔排序得名于其发明者Donald Shell,是一种运行复杂度在O(nlogn)~O(n^1.5)之间的一种算法,具体复杂度取决于实现细节,即:gap的选择。
作为一种特殊的插入排序算法,其独到之处在于2点:
1. 当待排序数组几乎已经有序时,插入排序效率较高。
2. 插入排序整体效率较低,因为它每次只移动一个值。

1.gap=arr.length/2:
这里写图片描述
2. 第一次粗排序后结果:
这里写图片描述
3. gap = gap/2;
这里写图片描述
4. 第二次粗排序后结果:
这里写图片描述
5. gap=1,最后进行一波插入排序示意图(可以看到,需要进行交换的元素数量较少,效率就从这里体现出来了):

2.插入排序算法&&Shell 排序

实质上,Shell排序就是加了一层gap的插入排序,但是带来了的性能的大幅提升,不可思议。
插入排序

    /**
     * @param arr
     * @author fqyuan
     * @see A little twisted among the 3 simple sort method:
     *      select/insert/bubble.
     */
    public static void insertSort(int[] arr) {
        for (int i = 1; i < arr.length; i++) {
            int key = arr[i];
            int j = i - 1;
            // Find the position to insert at: j.
            for (; j >= 0 && arr[j] > key; j--)
                arr[j + 1] = arr[j];
            arr[j + 1] = key;
        }
    }

Shell排序

/**
     * @param arr
     * @author fqyuan
     * @see Shell sort:
     */
    public static void shellSort(int[] arr) {
        for (int gap = arr.length / 2; gap > 0; gap = gap == 2 ? 1 : (int) (gap / 2.2)) {
            for (int i = gap; i < arr.length; i++) {
                int temp = arr[i];
                int j = i - gap;
                for (; j >= 0 && arr[j] > temp; j -= gap)
                    arr[j + gap] = arr[j];
                arr[j + gap] = temp;
            }
        }
    }

3.性能比较

由运行结果可知:这里选取了10,000,000个随机数排列,运行结果表现出quick sort快速排序表现最好,merge sort和 shell sort性能相近。

package com.fqyuan.sort;

import java.util.Random;

import org.junit.Test;

public class SortUtils {

    /**
     * @param arr
     * @author fqyuan
     * @see 这里的swap操作在第二层循环之外,减少了交换的次数,改善了部分性能。
     */
    public static void selectSort(int[] arr) {

        for (int i = 0; i < arr.length - 1; i++) {
            int minIndex = i;
            for (int j = i + 1; j < arr.length; j++) {
                if (arr[minIndex] > arr[j])
                    minIndex = j;
            }
            swap(arr, minIndex, i);
        }
    }

    /**
     * @param arr
     * @author fqyuan
     * @see 加入了sorted flag之后,如果是已经排序好的数组,可以大幅减少排序swap次数。
     */
    public static void bubbleSort(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
            boolean sorted = true;
            for (int j = 0; j < arr.length - i - 1; j++) {
                if (arr[j] > arr[j + 1]) {
                    swap(arr, j, j + 1);
                    sorted = false;
                }
            }
            if (sorted)
                break;
        }
    }

    /**
     * @param arr
     * @author fqyuan
     * @see A little twisted among the 3 simple sort method:
     *      select/insert/bubble.
     */
    public static void insertSort(int[] arr) {
        for (int i = 1; i < arr.length; i++) {
            int key = arr[i];
            int j = i - 1;
            // Find the position to insert at: j.
            for (; j >= 0 && arr[j] > key; j--)
                arr[j + 1] = arr[j];
            arr[j + 1] = key;
        }
    }

    public static void mergeSort(int[] arr) {
        if (arr.length < 2)
            return;
        int mid = arr.length / 2;
        int[] left = new int[arr.length / 2];
        int[] right = new int[arr.length - mid];
        for (int i = 0; i < mid; i++)
            left[i] = arr[i];
        for (int i = mid; i < arr.length; i++)
            right[i - mid] = arr[i];

        mergeSort(left);
        mergeSort(right);
        merge(left, right, arr);
    }

    private static void merge(int[] left, int[] right, int[] arr) {
        int nL = left.length;
        int nR = right.length;
        int i = 0, j = 0, k = 0;
        while (i < nL && j < nR) {
            if (left[i] <= right[j])
                arr[k++] = left[i++];
            else
                arr[k++] = right[j++];
        }
        if (i < nL) {
            while (i < nL)
                arr[k++] = left[i++];
        } else {
            while (j < nR)
                arr[k++] = right[j++];
        }
    }

    public static void quickSort(int arr[]) {
        quickSort(arr, 0, arr.length - 1);
    }

    private static void quickSort(int[] arr, int startIndex, int endIndex) {
        if (startIndex < endIndex) {
            // int pivot = randomizePartiton(arr, startIndex, endIndex);
            int pivot = partition(arr, startIndex, endIndex);
            quickSort(arr, startIndex, pivot - 1);
            quickSort(arr, pivot + 1, endIndex);
        }
    }

    private static int randomizePartiton(int[] arr, int startIndex, int endIndex) {
        int randomIndex = (int) Math.floor((Math.random() * (endIndex - startIndex + 1) + startIndex));
        swap(arr, randomIndex, endIndex);
        return partition(arr, startIndex, endIndex);
    }

    private static int partition(int arr[], int startIndex, int endIndex) {
        // Randomize the pivot.

        int randomIndex = (int) Math.floor((Math.random() * (endIndex - startIndex + 1) + startIndex));
        swap(arr, randomIndex, endIndex);

        int pivotValue = arr[endIndex];
        int pivotIndex = startIndex;
        for (int i = startIndex; i < endIndex; i++) {
            if (arr[i] < pivotValue) {
                swap(arr, i, pivotIndex);
                pivotIndex++;
            }
        }
        swap(arr, pivotIndex, endIndex);

        return pivotIndex;
    }

    /**
     * @param arr
     * @author fqyuan
     * @see Shell sort:
     */
    public static void shellSort(int[] arr) {
        for (int gap = arr.length / 2; gap > 0; gap = gap == 2 ? 1 : (int) (gap / 2.2)) {
            for (int i = gap; i < arr.length; i++) {
                int temp = arr[i];
                int j = i - gap;
                for (; j >= 0 && arr[j] > temp; j -= gap)
                    arr[j + gap] = arr[j];
                arr[j + gap] = temp;
            }
        }
    }

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

    public void printArr(int arr[]) {
        // for (int val : arr)
        // System.out.print(val + " ");
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
            if ((i + 1) % 10 == 0)
                System.out.println();
        }
        System.out.println();
    }

    @Test
    public void test() {

        // selectSort time test.
        long start = System.currentTimeMillis();
        Random random = new Random();
        int[] arr = new int[100000];
        for (int i = 0; i < arr.length; i++)
            arr[i] = random.nextInt(100000);
        // printArr(arr);
        // selectSort(arr);
        // printArr(arr);
        long end = System.currentTimeMillis();
        System.out.println("Select Sort -- time taken is: " + (end - start) + "ms");

        // insertSort time test
        start = System.currentTimeMillis();
        arr = new int[100000];
        for (int i = 0; i < arr.length; i++)
            arr[i] = random.nextInt(100000);
        // printArr(arr);
        // insertSort(arr);
        // printArr(arr);
        end = System.currentTimeMillis();
        System.out.println("Insert Sort -- time taken is: " + (end - start) + "ms");

        // bubbleSort time test
        start = System.currentTimeMillis();
        arr = new int[100000];
        for (int i = 0; i < arr.length; i++)
            arr[i] = random.nextInt(100000);
        // printArr(arr);
        // bubbleSort(arr);
        // printArr(arr);
        end = System.currentTimeMillis();
        System.out.println("Bubble Sort -- time taken is: " + (end - start) + "ms");

        // mergeSort time test
        start = System.currentTimeMillis();
        arr = new int[10000000];
        for (int i = 0; i < arr.length; i++)
            arr[i] = random.nextInt(10000000);
        // printArr(arr);
        mergeSort(arr);
        // printArr(arr);
        end = System.currentTimeMillis();
        System.out.println("Merge Sort -- time taken is: " + (end - start) + "ms");

        // quickSort time test
        start = System.currentTimeMillis();
        arr = new int[10000000];
        for (int i = 0; i < arr.length; i++)
            arr[i] = random.nextInt(1000000);
        // printArr(arr);
        quickSort(arr);
        // printArr(arr);
        end = System.currentTimeMillis();
        System.out.println("Quick Sort -- time taken is: " + (end - start) + "ms");

        // quickSort time test
        start = System.currentTimeMillis();
        arr = new int[10000000];
        for (int i = 0; i < arr.length; i++)
            arr[i] = random.nextInt(10000000);
        // printArr(arr);
        shellSort(arr);
        // printArr(arr);
        end = System.currentTimeMillis();
        System.out.println("Shell Sort -- time taken is: " + (end - start) + "ms");

    }

    @Test
    public void test1() {
        Random random = new Random();
        int[] arr = new int[100];
        for (int i = 0; i < 100; i++) {
            arr[i] = random.nextInt(100);
        }
        printArr(arr);
        shellSort(arr);
        printArr(arr);
    }
}

//Running result(单元测试test的结果):
Select Sort -- time taken is: 21ms
Insert Sort -- time taken is: 1ms
Bubble Sort -- time taken is: 0ms
Merge Sort -- time taken is: 2030ms
Quick Sort -- time taken is: 1231ms
Shell Sort -- time taken is: 1866ms
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值