排序

一、选择排序

1.堆排序

定义:堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序
可参考https://www.cnblogs.com/chengxiao/p/6129630
https://www.jianshu.com/p/938789fde325

public class HeapSort {
    public static void main(String[] args) {

        /**
         * 堆排序,利用二叉树左右节点的模式来比较
         */
        int[] a = {19, 8, 27, 6, 35, 14, 3, 12, 1, 0, 9, 10, 7};

        HeapSort heapSort = new HeapSort();
        heapSort.heapSort(a);
        for (int i = 0; i < a.length; i++) {
            System.out.println(a[i]);
        }

    }

    public void heapSort(int[] a) {
        if (a == null || a.length <= 1) {
            return;
        }

        buildMaxHeap(a);
        for (int i = a.length - 1; i > 0; i--) {
            //最大的在0位置,那么开始沉降,这样每交换一次最大的值就丢到最后了
            exchangeElement(a, 0, i);
            //继续获取0位置最大值
            maxHeap(a, i, 0);

        }

    }

    /**
     * 创建最大堆
     *
     * @param a
     */
    private void buildMaxHeap(int[] a) {
        if (a == null || a.length <= 1) {
            return;
        }
        int half = (a.length ) / 2-1;
        for (int i = half; i >= 0; i--) {
            maxHeap(a, a.length, i);
        }

    }

    /**
     * 利用二叉树跟、左、右节点的值进行比较,不断的更换最大值对应的小标largest,
     * 当当前传过来的下标与最大值的小标不想等时,两者交换相应的位置,然后再用递归的方式进行查找最大,
     * 但是此时是以前面所找的最大值的小标为标准
     * @param a
     * @param length
     * @param index
     */
    private void maxHeap(int[] a, int length, int index) {
        int left = index * 2 + 1;
        int right = index * 2 + 2;
        int largest = index;
        if (left < length  && a[left] > a[index]) {
            largest = left;
        }
        if (right < length  && a[right] > a[largest]) {
            largest = right;
        }
        if (index != largest) {
            exchangeElement(a, index, largest);

            maxHeap(a, length, largest);
        }
    }

    private void exchangeElement(int[] a, int index, int largest) {
        int temp = a[index];
        a[index] = a[largest];
        a[largest] = temp;
    }

}

2,

定义:首先,找到数组中最小的那个元素,其次,将它和数组的第一个元素交换位置(如果第一个元素就是最小元素那么它就和自己交换)。再次,在剩下的元素中找到最小的元素,将它与数组的第二个元素交换位置。如此往复,直到将整个数组排序。这种方法叫做选择排序,因为它在不断地选择剩余元素之中的最小者。

 public static void main(String[] args) {

       int[] a = {3, 7, 1, 5, 6, 2, 4};
        for (int i = 0; i < a.length; i++) {
            for (int j = i + 1; j < a.length; j++) {
                int temp;
                if (a[i] > a[j]) {
                    temp = a[i];
                    a[i] = a[j];
                    a[j] = temp;
                }
            }
            System.out.println(a[i]);
        }



    }

二、插入排序(适合小规模数组)

1.直接插入排序

定义:每次将一个待排序的元素与已排序的元素进行逐一比较,直到找到合适的位置按大小插入。
自己的理解:
在一个无序的数组中,首先将前两个元素进行对比排序,然后第三个元素和第二个元素进行对比,如果第三个元素大于第二个元素,则进行下一步,将第四个元素和第三个元素对比排序;否则如果第三个元素小于第二个元素,将两者位置互换后,再将重新排序后的第二个元素和第一个元素进行对比排序.....以此类推即可实现插入排序

public class InsertSort {
    public static void main(String[] args) {

        /**
         * 直接插入排序
         */
        int[] a = {9, 3, 8, 23, 86, 33, 54, 0, 1, 65, 10, -1};
        //从数组中下标为1的元素开始
        for (int i = 1; i < a.length; i++) {
            //用temp记录当前遍历的元素值
            int temp = a[i];
            //外部定义j,为了在break的情况下记录j的值
            int j;
            for (j = i - 1; j >= 0; j--) {
                //如果a[j]大于当前的值,则最后一个元素需要往后移动一位,所以将a[j]的值赋值给a[j+1],
                //否则,就结束循环,记录j的值
                if (a[j] > temp) {
                    a[j + 1] = a[j];
                } else {
                    break;
                }
            }
            //break下的小标为j,值比temp小,所以temp的值需要赋值给a[j+1]
            a[j + 1] = temp;
        }

        for (int i = 0; i < a.length; i++) {
            System.out.println(a[i]);
        }

    }
}

2.二分法插入排序

先要知道数组中的左边、右边以及中间的下标,然后当坐标下标小于等于右边下标时,将要插入的数字与中间下标对应的数字进行比较,做变换左、中、右下标的循环,最后以左下标为标准,将左及左后边全部后移,当左下标的值不等于i时,左位置插入该数据。

public class BinaryInsertSort {
    public static void main(String[] args) {
        int[] a = {3, 0, 1, 90, 56, 34, 23, 76, 46, -1, 77};
        BinaryInsertSort b = new BinaryInsertSort();
        b.sort(a);
        for (int i = 0; i < a.length; i++) {
            System.out.println(a[i]);
        }

    }

    /**
     * 二分法插入排序
     *
     * @param a
     */
    public void sort(int[] a) {
        for (int i = 1; i < a.length; i++) {
            //记录当前遍历到的数值
            int temp = a[i];
            //定义左边的下标
            int left = 0;
            //定义右边的下标
            int right = i - 1;
            //初始化中间的下标
            int mid = 0;
            //循环:当左边下标小于等于右边下标时
            while (left <= right) {
                //计算中间下标
                mid = (left + right) / 2;
                //当当前遍历的值�大于中间小标对应的值时,变动左边下标
                if (temp > a[mid]) {
                    left = mid + 1;
                } else {
                    //当当前遍历的值小于中间小标对应的值时,变动右边下标
                    right = mid - 1;
                }
            }

            //遍历数组,以左下标为标准,让大于等于左边下标对应的所有的值都往后移动一位
            for (int j = i - 1; j >= left; j--) {
                if (temp < a[j]) {
                    a[j + 1] = a[j];
                }

            }

            //当左边下标不等于遍历的小标时(即要插入的那个数在当前排序数字中不是最大时),给左边下标对应的数赋值
            //要插入的那个数在当前排序数字中是最大时,直接插入,不做任何操作
            if (left != i) {
                a[left] = temp;
            }
        }


    }
}

3.希尔排序

定义:希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止


排序_第1张图片
希尔排序过程
public class HeerSort {
    public static void main(String[] args) {
        /**
         * 希尔排序
         */
        int[] a = {49, 38, 65, 97, 76, 13, 27, 49, 78, 34, 12, 64, 1, 33, 85, 29};
        int d = a.length / 2;   //默认增量,总长度除以2
        while (true) {
            for (int i = 0; i < d; i++) {//注意i的值是小于增量的
                for (int j = i; j + d < a.length; j += d) {//以增加作为间距
                    int temp;
                    if (a[j] > a[j + d]) {
                        temp = a[j];
                        a[j] = a[j + d];
                        a[j + d] = temp;
                    }
                }
            }
            //增量为1时结束
            if (d == 1) {
                break;
            }
            d--;
        }

        for (int i = 0; i < a.length; i++) {
            System.out.println(a[i]);
        }

    }
}

三、快速排序

定义:是对冒泡排序的一种改进。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列

public class QuickSort {
    public static void main(String[] args) {
        QuickSort quickSort = new QuickSort();
        int[] a = {19, 2, 6, 90, 67, 33, -7, 24, 3, 56, 34, 5};
        quickSort.quick(a);
        for (int i = 0; i < a.length; i++) {
            System.out.println(a[i]);
        }

    }

    public void quick(int[] a) {
        if (a.length < 0) {
            return;
        }
        quickSort(a, 0, a.length - 1);

    }

    /**
     * 快速排序
     *
     * @param a
     * @param low
     * @param high
     */
    private void quickSort(int[] a, int low, int high) {
        //获取下标后,以该下标为基准,用迭代的方法左右两边都做相同的操作
         if (low < high) {
            int middle = getMiddle(a, low, high);
            quickSort(a, 0, middle - 1);
            quickSort(a, middle + 1, high);
        }
    }

    /**
     * 以数组中的一个数为基准元素,然后获取该元素在此数组中的排序的下标
     * @param a
     * @param low
     * @param high
     * @return
     */
    private int getMiddle(int[] a, int low, int high) {
        int temp = a[low];//以下标为low的值作为基准元素
        while (low < high) {
            //从右边开始,一个个与基准元素进行比较,大于基准元素的,high--,小于基准元素的,结束循环
            while (low < high && temp < a[high]) {
                high--;
            }
            //结束循环之后,将a[high]的值放到a[low]中,
            a[low] = a[high];

            //在从左边开始,一个个与基准元素进行比较,小于基准元素的,low++;大于基准元素的,结束循环
            while (low < high && temp > a[low]) {
                low++;
            }
            //结束循环之后,将a[low]的值放到a[high]中,
            a[high] = a[low];
        }
        a[low] = temp;
        return low;
    }
}

四、归并排序

定义:是一类与插入排序、交换排序、选择排序不同的另一种排序方法。归并的含义是将两个或两个以上的有序表合并成一个新的有序表;
基本思想:分而治之(divide - conquer);每个递归过程涉及三个步骤
第一, 分解: 把待排序的 n 个元素的序列分解成两个子序列, 每个子序列包括 n/2 个元素.
第二, 治理: 对每个子序列分别调用归并排序MergeSort, 进行递归操作
第三, 合并: 合并两个排好序的子序列,生成排序结果.

排序_第2张图片
image
public class MergeSort {
    public static void main(String[] args) {
        int[] a = new int[]{90, 3, 2, 67, 44, -9, 87, 65, 11, 9, 2, 8};
        MergeSort m = new MergeSort();
        m.mergeSort(a, 0, a.length - 1);
        for (int i = 0; i < a.length; i++) {
            System.out.println(a[i]);
        }

    }

    /**
     * 归并排序
     * @param a
     * @param left
     * @param right
     */
    public void mergeSort(int[] a, int left, int right) {
        if (left < right) {
            int middle = (left + right) / 2;
            //将数组拆分成单个元素的多个数组
            mergeSort(a, left, middle);
            mergeSort(a, middle + 1, right);
            //逐一合并
            merge(a, left, middle, right);
        }

    }

    /**
     * 合并排好序的数组,定义一个新的数组,然后两个数组从第一个开始进行比较,
     * 谁小就放入新的数组,同时对应的下标加或者减1,
     * @param a
     * @param left
     * @param middle
     * @param right
     */
    private void merge(int[] a, int left, int middle, int right) {
        int[] tempArray = new int[a.length];
        int rightStart = middle + 1;
        int temp = left;
        int third = left;
        //当左边小于等于中间;右边开始下标小于等于右边
        while (left <= middle && rightStart <= right) {
            //从第一个元素开始逐个比较,如果左边的值小于右边的值,将左边的值放在新的数组中,否则,将右边的值放在新的数组中
            if (a[left] <= a[rightStart]) {
                tempArray[third++] = a[left++];
//                tempArray[third]=a[left];
//                third++;
//                left++;
            } else {
                tempArray[third++] = a[rightStart++];
            }
        }

        //当右边的数组全部比较完了,但是左边的依然还有,则将左边剩余的元素依次放入新的数组中
        while (left <= middle) {
            tempArray[third++] = a[left++];
        }
        //当左边的数组全部比较完了,但是右边的依然还有,则将右边剩余的元素依次放入新的数组中
        while (rightStart <= right) {
            tempArray[third++] = a[rightStart++];
        }

        while (temp <= right) {
            a[temp] = tempArray[temp];
            temp++;
        }


    }
}

五、基数排序

基本思路:

  • 第一:获取数组中的最大值以及最大值的位数;
  • 第二:创建一个多维数组,里面有十个数组,分别存放位数对应的1-10的数字;
  • 第三:遍历原始数组,分别获取个位、十位、百位等位对应的值,通过这个值获取在多维数组中对应的数组,
  • 把原始数组中的这个元素添加到多维数组中对应的数组中,
  • 第四:开始收集;遍历多维数组中的每个数组,把每个数组中的元素一个个赋值给原始数组元素,赋值一个,移除一个,同时count次数++
public class BasicSort {
    public static void main(String[] args) {
        int[] a = {136, 2, 6, 8, 9, 2, 8, 11, 23, 56, 34, 90, 89, 29, 145, 209, 320, 78, 3};
        BasicSort basicSort = new BasicSort();
        basicSort.sort(a);
        for (int i = 0; i < a.length; i++) {
            System.out.println(a[i]);
        }

    }

    /**
     * 基数排序:
     * 基本思路:
     * 第一:获取数组中的最大值以及最大值的位数;
     * 第二:创建一个多维数组,里面有十个数组,分别存放位数对应的1-10的数字;
     * 第三:遍历原始数组,分别获取个位、十位、百位等位对应的值,通过这个值获取在多维数组中对应的数组,
     * 把原始数组中的这个元素添加到多维数组中对应的数组中,
     * 第四:开始收集;遍历多维数组中的每个数组,把每个数组中的元素一个个赋值给原始数组元素,赋值一个,移除一个,
     * 同时count次数++
     *
     * @param a
     */
    public void sort(int[] a) {
        //获取数组中的最大值
        int max = 0;
        for (int i = 0; i < a.length; i++) {
            if (max < a[i]) {
                max = a[i];
            }
        }

        //获取最大值的位数
        int times = 0;
        while (max > 0) {
            max = max / 10;
            times++;
        }

        //创建一个多维数组
        List queue = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            ArrayList q = new ArrayList();
            queue.add(q);
        }

        for (int i = 0; i < times; i++) {
            for (int j = 0; j < a.length; j++) {
                //获取对应的位的值(i为0是各位,1是10位,2是百位)
                int x = a[j] % (int) Math.pow(10, i + 1) / (int) Math.pow(10, i);
                //通过得到的位的值获取多维数组中对应的数组,然后将该数据添加到对应的数组中
                ArrayList q = queue.get(x);
                q.add(a[j]);
            }

            //开始收集
            int count = 0;
            //遍历多维数组中的每个数组
            for (int j = 0; j < 10; j++) {
                while (queue.get(j).size() > 0) {
                    ArrayList q = queue.get(j);//获取多维数组中的单个数组
                    //将第一个值赋值给原有的数组,然后移除第一个
                    a[count] = q.get(0);
                    q.remove(0);
                    count++;

                }
            }
        }

    }
}

六、二分查找

public class BinarySearch {
    public static void main(String[] args) {
        int[] array = {10, 23, 4, 3, 2, 5, 1, 2, 623, 92, 23, 23, 234, 2, 34, 234, 234, 2, 10};
        BinarySearch binarySearch = new BinarySearch();
        BasicSort basicSort = new BasicSort();
        basicSort.sort(array);
        for (int i = 0; i < array.length; i++) {
            System.out.print(array[i] + "---");
        }
//        binarySearch.binarySearch(5, array, 0, array.length - 1);
        binarySearch.directBinarySearch(array,5);


    }

    /**
     * 递归查找(二分查找)
     *
     * @param elem
     * @param array
     * @param low
     * @param high
     * @return
     */
    public int binarySearch(int elem, int[] array, int low, int high) {
        if (low > high) {
            return -1;
        }
        int middle = (low + high) / 2;
        if (elem < array[middle]) {
            //找左边
            return binarySearch(elem, array, low, middle - 1);
        } else if (elem > array[middle]) {
            //找右边
            return binarySearch(elem, array, middle + 1, high);
        } else if (elem == array[middle]) {
            System.out.print("-------" + middle);
            return middle;
        } else {
            return -1;
        }

    }

    /**
     * 非递归查找
     * @param array
     * @param elem
     * @return
     */
    public int directBinarySearch(int[] array, int elem) {
        int low = 0;
        int high = array.length - 1;
        while (low <= high) {
            int middle = (low + high) / 2;
            if (elem < array[middle]) {
                high = middle - 1;
            } else if (elem > array[middle]) {
                low = middle + 1;
            } else if (elem == array[middle]) {
                System.out.print("-------" + middle);
                return middle;
            }
        }
        return -1;
    }
}

你可能感兴趣的:(排序)