算法基础(一) 排序

文章目录

排序工具

1 生成随机数

/**
* 生成一个随机数数
*
* @param n      数组中的元素数量
* @param rangeL 左区间
* @param rangeR 右区间
* @return
*/
public static Integer[] generateRandomArray(int n, int rangeL, int rangeR) {
   if (rangeL >= rangeR) {
       return null;
   }

   Integer arr[] = new Integer[n];
   for (int i = 0; i < n; i++) {
       int random = (int) (Math.random() * (rangeR - rangeL + 1) + rangeL);
       arr[i] = random;
   }

   return arr;
}

2 计算耗时

public static void testSortSpendTime(ISort iSort, Comparable[] arr) {
   long startTime = System.currentTimeMillis();

   if (iSort != null) {
       iSort.sort();
   }

   long endTime = System.currentTimeMillis();

   long spendTime = endTime - startTime;

   System.out.println("算法消耗的时间为: " + spendTime + "ms");
}

public interface ISort {
    void sort();
}

3 近乎有序随机数

public static Integer[] generateNearlyOrderArray(int n, int swapTimes) {
    Integer[] arr = new Integer[n];
    for (int i = 0; i < n; i++) {
        arr[i] = new Integer(i);
    }

    for (int i = 0; i < swapTimes; i++) {
        int indexA = (int) (Math.random() * n);
        int indexB = (int) (Math.random() * n);

        int t = arr[indexA];
        arr[indexA] = arr[indexB];
        arr[indexB] = t;
    }

    return arr;
}

4 检测数组是否有序


/**
 * 检查数组是否是正序
 *
 * @param arr
 * @return
 */
public static boolean isSorted(Comparable[] arr) {
    for (int i = 0; i < arr.length - 1; i++) {
        if (arr[i].compareTo(arr[i + 1]) < 0) {
            return false;
        }
    }

    return true;
}

1 选择排序

private static void selectSort(Comparable[] arr) {
    int n = arr.length;

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

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

    arr[i] = arr[j];
    arr[j] = t;
}

2 插入排序

private static void insertSort(Comparable[] arr) {
    int n = arr.length;

    for (int i = 0; i < n; i++) {

        Comparable e = arr[i];
        int j = i;
        for (; j > 0; j--) {
            if (arr[j - 1].compareTo(e) > 0) {
                arr[j] = arr[j - 1];
            } else {
                break;
            }
        }

        arr[j] = e;

    }
}

3 希尔排序

public static void shellSort(Comparable[] arr) {
    int n = arr.length;
    int h = 1;

    //1 计算增量的值
    while (h < n / 3) {
        h = 3 * h + 1;
    }

    //2 增量h递减
    while (h >= 1) {

        //3 对增量为h的数组进行插入排序
        for (int i = h; i < n; i++) {
            Comparable element = arr[i];

            int j = i;
            for (; j >= h; j -= h) {
                if (element.compareTo(arr[j - h]) < 0) {
                    arr[j] = arr[j - h];
                } else {
                    break;
                }
            }

            arr[j] = element;
        }

        h /= 3;
    }

}

4 归并排序

public static void merge(Comparable[] arr, int left, int right) {
    int middle = (left + right) / 2;
    Comparable[] cpArray = Arrays.copyOfRange(arr, left, right + 1);

    int leftIndex = left;
    int rightIndex = middle + 1;

    for (int k = left; k <= right; k++) {
        //1 左边的已经排好序
        if (leftIndex > middle) {
            arr[k] = cpArray[rightIndex - left];
            rightIndex++;
            //2 右边的已经排好序
        } else if (rightIndex > right) {
            arr[k] = cpArray[leftIndex - left];
            leftIndex++;
            //3 左边小于右边
        } else if (cpArray[leftIndex - left].compareTo(cpArray[rightIndex - left]) < 0) {
            arr[k] = cpArray[leftIndex - left];
            leftIndex++;
            //4 右边小于左边
        } else {
            arr[k] = cpArray[rightIndex - left];
            rightIndex++;
        }
    }

}


private static void mergeSort(Comparable[] arr, int left, int right) {
    if (left >= right) {
        return;
    }
    int middle = (left + right) / 2;
    mergeSort(arr, left, middle);
    mergeSort(arr, middle + 1, right);
    merge(arr, left, right);
}

5 快速排序

private static int partition(Comparable[] arr, int left, int right) {
        Comparable v = arr[left];
        int j = left;

        for (int i = left + 1; i <= right; i++) {
            if (v.compareTo(arr[i]) > 0) {
                j++;
                SortTestUtils.swap(arr, j, i);
            }
        }

        SortTestUtils.swap(arr, j, left);

        return j;
    }

    private static void sort(Comparable[] arr, int left, int right) {
        if (left >= right) {
            return;
        }

        int p = partition(arr, left, right);
        sort(arr, left, p - 1);
        sort(arr, p + 1, right);
    }

6 双路快排

避免重复键值导致效率低问题

private static int partition_2(Comparable[] arr, int left, int right) {
        int randomIndex = (int) (Math.random() * (right - left + 1) + left);
        SortTestUtils.swap(arr, left, randomIndex);

        Comparable v = arr[left];

        int i = left + 1, j = right;

        while (true) {

            //1 找到第一个比v大的index
            while (i <= right && arr[i].compareTo(v) < 0) {
                i++;
            }

            //2 找到后面往前第一个比v小的index
            while (j >= left + 1 && arr[j].compareTo(v) > 0) {
                j--;
            }

            //3 表示left到right之前的index已经遍历结束
            if (i > j) {
                break;
            }

            //4 交换i和j的值,此时i的值时比v大,j的值比v小
            SortTestUtils.swap(arr, i, j);

            //5 index分别向后和向前挪一位
            i++;
            j--;
        }

        SortTestUtils.swap(arr, left, j);
        return j;
    }

7 三路快排

private static void quickSort_3(Comparable[] arr, int left, int right) {
        if(left >= right){
            return;
        }

        int randomIndex = (int) (Math.random() * (right - left + 1) + left);
        SortTestUtils.swap(arr, left, randomIndex);

        Comparable v = arr[left];

        int leftIndex = left;
        int rightIndex = right + 1;

        int i = left + 1;
        while (i < rightIndex) {
            if (arr[i].compareTo(v) < 0) {
                SortTestUtils.swap(arr, i, leftIndex + 1);
                i++;
                leftIndex++;
            } else if (arr[i].compareTo(v) > 0) {
                SortTestUtils.swap(arr, i, rightIndex - 1);
                rightIndex--;
            } else {
                i++;
            }
        }

        SortTestUtils.swap(arr, left, leftIndex);

        quickSort_3(arr, left, leftIndex - 1);
        quickSort_3(arr, rightIndex, right);
    }

8 堆排序

public static void sort(Comparable[] arr) {
 	int n = arr.length;
    for (int i = (n - 1 - 1) / 2; i >= 0; i--) {
        shiftDown(arr, n, i);
    }
    
    for (int i = n - 1; i > 0; i--) {
        swap(arr, 0, i);
        shiftDown(arr, i, 0);
    }
}

private static void shiftDown(Comparable[] arr, int n, int k) {
   Comparable e = arr[k];
   while (2 * k + 1 < n) {
       int j = 2 * k + 1;

       if (j + 1 < n && arr[j + 1].compareTo(arr[j]) > 0) {
           j += 1;
       }

       if (e.compareTo(arr[j]) >= 0) {
           break;
       }

       swap(arr, k, j);
       k = j;
   }
}

	
上一篇:Java容器类面试题总结


下一篇:数据结构与算法之堆排序