首页 > 技术文章 > 常用查找和排序

ya-qiang 2018-08-30 21:27 原文

package com.itwang.sort_search;

/**
 * @ProjectName: JavaPractice
 * @Package: com.itwang.sort_search
 * @ClassName: BinarySearch
 * @Author: JikeWang
 * @Description: 二分查找
 * @Date: 2018-08-28 21:21
 * @Version: 1.0
 */
public class Search {

    /**
     * @Method find
     * @Author JikeWang
     * @Version  1.0
     * @Description 顺序查找
     * @param array 要查找的元素数组
     * @param key 要查找的元素
     * @Return int 返回查找结果 -1:表示没有查找到  0~array.length-1: 表示查找到
     * @Exception
     * @Date 2018-08-30 18:42
     */
    public int find(int[] array, int key){
        int i;
        for (i = 0 ;i < array.length; i++){
            if (array[i] == key){
                break;
            }
        }
        if (i == array.length){
            return -1;//如果没有查找到
        }else{
            return i;//如果查找到
        }
    }
    /**
     * @Method binarySearch
     * @Author JikeWang
     * @Version  1.0
     * @Description 二分查找(折半查找)前提元素必须是有序的
     * @param array 要查找的数组
     * @param key 要查找的关键元素
     * @Return int 返回的查找结果,如果找到则返回元素的位置,如果没有找到则返回元素应该插入的位置
     * @Exception
     * @Date 2018-08-28 21:28
     */
    public int binarySearch(int[] array, int key){
        int low = 0, high = array.length - 1;
        while (low <= high){
            int mid = (high + low) >> 1;
            if (array[mid] < key){
                low = mid + 1;
            }else if (array[mid] > key){
                high = mid - 1;
            }else {
                return mid;
            }
        }
        return low;
    }

    /********************************插入排序********************************/
    /**
     * @Method insertSort
     * @Author JikeWang
     * @Version  1.0
     * @Description 直接插入排序
     * @param array 要排序的数组集合
     * @Return void
     * @Exception
     * @Date 2018-08-30 18:44
     */
    void insertSort(int[] array){
        //直接插入排序,假定前面是有序的,从1后面位置开始插入排序
        System.out.println("---------直接插入排序---------");
        for (int i = 1; i < array.length; i++){
            int tmp = array[i];
            int j = i - 1;
            //遍历找到插入的位置
            while ((j >= 0) && (tmp < array[j])){
                array[j + 1] = array[j];//如果插入的元素小于当前元素,元素后移
                j--;
            }
            //将要插入的元素插入到找到的位置(j+1)是由于上面循环结束后减了一次1
            array[j + 1] = tmp;
        }
    }
    /**
     * @Method binaryInsertSort
     * @Author JikeWang
     * @Version  1.0
     * @Description 折半插入排序(跟直接插入排序一样,只是在查找元素插入位置的时候利用了折半查找
     * @param array 要排序的数组集合
     * @Return void
     * @Exception
     * @Date 2018-08-30 18:45
     */
    void binaryInsertSort(int[] array){
        System.out.println("---------折半插入排序---------");
        for (int i = 1; i < array.length; i++){
            int tmp = array[i];
            int low = binarySearch(array,tmp);
            //元素后移
            for (int j = i - 1; j >= low; j --){
                array[j+1] = array[j];
            }
            array[low] = tmp;
        }
    }
    /**
     * @Method shellSort
     * @Author JikeWang
     * @Version  1.0
     * @Description 希尔排序(先将整个待排序记录序列分割成若干子序列,分别进行直接插入排序,
     *              待整个序列中的记录“基本有序”时,再对全体记录进行一次直接插入排序)
     *              分割序列可以根据某一增量进行分割
     * @param array
     * @Return void
     * @Exception
     * @Date 2018-08-30 18:49
     */
    public void shellSort(int[] array){
        //增量每次都是/2
        for (int step = array.length / 2; step > 0; step /= 2){
            //从增量那组开始进行插入排序,直至完毕
            for (int i = step; i < array.length; i++){
                int j = i;
                int tmp = array[j];

                //j-step就是代表与它同组隔壁的元素
                while (j - step >= 0 && tmp < array[j - step]){
                    array[j] = array[j - step];
                    j = j - step;
                }
                array[j] = tmp;
            }
        }
    }

    /********************************交换排序********************************/
    /**
     * @Method bubbleSort
     * @Author JikeWang
     * @Version  1.0
     * @Description 冒泡排序,每次循环通过比较相邻的元素大小进行交换,最终会是最后一个元素时最大的。
     *              第一轮,需要循环n-1次,最后一个元素最大,
     *              第二轮,需要循环n-2次,最后一个元素最大,
     *              以此类推,需要进行n轮,每轮循环n-i次
     * @param array
     * @Return void
     * @Exception
     * @Date 2018-08-30 18:57
     */
    public void bubbleSort(int[] array){
        System.out.println("---------冒泡排序---------");
        //进行array.length次循环,每轮进行array.length - i次循环
        for (int i = 1; i <= array.length; i++){
            boolean flag = true;
            //设定一个标记,若为true,则表示此次循环
            //没有进行交换,否则有交换
            for (int j = 0; j < array.length - i; j++){
                if (array[j] > array[j + 1]){
                    swap(array, j, j+1);
                    flag = false;
                }
            }
        }
    }
    /**
     * @Method quickSort
     * @Author JikeWang
     * @Version  1.0
     * @Description 快速排序(快速排序是对冒泡排序的一种改进,通过一趟排序将待排序列分割成独立的两部分,
     *              其中一部分记录的关键字均比另一部分记录关键字小,然后分别对这两部分记录进行排序)
     * @param array
     * @param low
     * @param high
     * @Return void
     * @Exception
     * @Date 2018-08-30 19:01
     */
    public void quickSort(int[] array, int low, int high){
        if (low >= high){
            return;
        }
        int index = partition(array, low, high);
        quickSort(array, low, index - 1);
        quickSort(array, index + 1, high);

    }

    public int partition(int[] array, int low, int high) {
        //以第一个元素作为枢轴值
        int key = array[low];
        while (low < high){
            //从后半部分向前扫描
            while (array[high] >= key && low < high) high--;
            //将后半部分小于枢轴值的元素放到前半部分
            array[low] = array[high];
            //从前半部分向后扫描
            while (array[low] <= key && low < high) low++;
            //将前半部分大于枢轴值的元素放到后半部分
            array[high] = array[low];
        }
        array[low] = key;
        return low;
    }

    /********************************选择排序********************************/
    /**
     * @Method selectSort
     * @Author JikeWang
     * @Version  1.0
     * @Description 简单选择排序(每一次首先选择当前索引位置的元素是最小值,通过跟后面元素的比较,确定最小元素位置,
     *              如果最小位置发生变化,则将最小位置的元素赋值到当前选择的位置)
     * @param array
     * @Return void
     * @Exception
     * @Date 2018-08-30 19:01
     */
    public void selectSort(int[] array){
        System.out.println("---------简单选择排序---------");
        for (int i = 0; i < array.length - 1; i++){
            int min = i;
            //每一趟循环比较,找到最小的元素的下标并赋值给min
            for (int j = i + 1;j < array.length; j++){
                if (array[j] < array[min])
                    min = j;
            }
            //如果min发生变化,进行交换
            if (min != i){
                swap(array, min, i);
            }
        }
    }
    //构建大顶堆
    public int[] buildMaxHeap(int[] array){
        for (int i = array.length / 2 - 1;i >= 0;i--){
            //从第一个非叶子节点从下至上,从右至左调整结构
            adjustDownHeap(array, i, array.length);
        }
        return array;
    }
    //向下调整堆
    private void adjustDownHeap(int[] array, int k, int length) {
        //取出当前元素
        int tmp = array[k];
        //i为初始化为节点k的左孩子,沿节点较大的子节点向下调整
        for (int i = 2*k + 1; i < length - 1; i = 2*i + 1 ){
            if (i < length && array[i] < array[i+1])//取节点较大的子节点的下标
                i++;//如果节点的右孩子>左孩子,则取右孩子节点的下标
            if (array[i] <= tmp) break;//根节点 >=左右子女中关键字较大者,调整结束
            else{ //根节点 <左右子女中关键字较大者
                array[k] = array[i];//将左右子结点中较大值array[i]调整到双亲节点上
                k = i; //【关键】修改k值,以便继续向下调整
            }
        }
        array[k] = tmp;//被调整的结点的值放人最终位置
    }
    /**
     * @Method heapSort
     * @Author JikeWang
     * @Version  1.0
     * @Description 堆排序(堆排序首先需要构建堆,这里是构建大顶堆,构建完毕后需要将元素从小到大整理出来,
     *              因为堆顶元素时最大值,通过从后向前操作,每次将堆顶元素赋值到当前位置,但每次赋值后,
     *               堆的结构就发生了变化,需要重新调整)
     * @param array
     * @Return void
     * @Exception
     * @Date 2018-08-30 19:01
     */
    public void heapSort(int[] array){
        array = buildMaxHeap(array);
        //n-1趟的交换和建堆过程
        for (int i = array.length - 1; i > 1;i--){
            swap(array, 0, i);//将堆顶元素和堆低元素交换
            adjustDownHeap(array, 0, i);//整理、将剩余的元素整理成堆
        }
    }
    /**
     * @Method deleteMax
     * @Author JikeWang
     * @Version  1.0
     * @Description 删除堆顶元素操作
     * @param array
     * @Return int[]
     * @Exception
     * @Date 2018-08-30 19:02
     */
    public int[] deleteMax(int[] array){
        //将堆的最后一个元素与堆顶元素交换,堆底元素值设为-999996
        array[0] = array[array.length-1];
        array[array.length-1] = -99999;
        //对此时的根节点进行向下调整
        adjustDownHeap(array, 0, array.length);
        return array;
    }
    /**
     * @Method insertData
     * @Author JikeWang
     * @Version  1.0
     * @Description 插入操作:向大根堆array中插入数据data
     * @param array
     * @param data
     * @Return int[]
     * @Exception
     * @Date 2018-08-30 19:02
     */
    public int[] insertData(int[] array, int data){
        array[array.length-1] = data; //将新节点放在堆的末端
        int k = array.length-1;  //需要调整的节点
        int parent = (k-1)/2;    //双亲节点
        while(parent >=0 && data>array[parent]){
            array[k] = array[parent];  //双亲节点下调
            k = parent;
            if(parent != 0){
                parent = (parent-1)/2;  //继续向上比较
            }else{  //根节点已调整完毕,跳出循环
                break;
            }
        }
        array[k] = data;  //将插入的结点放到正确的位置
        return array;
    }

    //两个位置的元素交换值
    private void swap(int[] array, int j, int i) {
        int tmp = array[j];
        array[j] = array[i];
        array[i] = tmp;
    }
    //打印元素
    void print(int[] array){
        for (int a : array) {
            System.out.print(a + "\t");
        }
        System.out.println();
    }
    public static void main(String[] args) {
        int[] array = {2,5,7,9,24};
        int[] sort_array = {2,5,3,1};
        Search search = new Search();

        //二分查找(折半查找)
        int result = search.binarySearch(array, 10);
        System.out.println(result);

        //直接插入排序
        //search.insertSort(sort_array);

        //折半插入排序
        //search.binaryInsertSort(sort_array);


        //冒泡排序
        //search.binaryInsertSort(sort_array);

        //简单选择排序
        //search.selectSort(sort_array);

        //希尔排序
        //search.shellSort(sort_array);

        //快速排序
        //search.quickSort(sort_array, 0, sort_array.length - 1);

        search.heapSort(sort_array);
        search.print(sort_array);

    }
}

 

推荐阅读