查找和排序算法

1、基本查找

public class test {
    public static void main(String[] args) {
        //定义一个数组
        int[] array = {1,5,8,9,5,21,53,90,10,2};
        //根据元素找出该元素在数组中第一次出现的索引
        int index = getIndexByEle(array,5);
        System.out.println("该元素的索引为:"+index);
    }

    private static int getIndexByEle(int[] array,int ele) {

        for (int i = 0; i < array.length; i++) {
            if (ele == array[i])
                return i;
        }
        return -1;//没有找到该元素
    }
}

2、二分查找

前提:该数组的元素必须有序

思想:每一次都查找中间的元素,比较大小就能够减少查找一半的元素

代码实现:

private static int getIndexByEle(int[] arr, int ele) {
    //定义最小索引,中间索引,最大索引
    int minIndex = 0;
    int maxIndex = arr.length-1;
    int midIndex = (minIndex+maxIndex)/2;
    while (minIndex <= maxIndex){
        //查找元素正好等于中间索引元素
        if (ele == arr[midIndex])
            return midIndex;
        //查找元素小于中间索引元素
        else if (ele < arr[midIndex])
            maxIndex = midIndex-1;
        //查找元素大于中间索引元素
        else
            minIndex = midIndex+1;
        midIndex = (minIndex+maxIndex)/2;
    }
    return -1;//没有找到
}

3、冒泡排序

原理:数组元素两两比较,交换位置,大元素往后放,那么经过一轮的比较后,最大的元素,就会出现在最大索引处。

代码实现:

//冒泡排序
    private static int[] sortArray(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
            int flag = 0;
				//将最大元素后调至该次循环的最大索引处
            for (int j = 0; j < arr.length - i - 1; j++) {
                if (arr[j] > arr[j+1]){
                    int temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                    flag = 1;
                }
            }
            if (flag == 0)//如果当前已经有序,则跳出循环
                break;
        }
        return arr;
  	}

4、选择排序

原理:从0索引处开始,依次和后面的元素进行比较,小的元素往前放,经过一轮比较后,最小的元素就出现在了最小索引处

代码实现:

//选择排序
    private static int[] sortArray(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = i+1; j < arr.length; j++) {
                if (arr[i] > arr[j]){
                    int temp = arr[i];
                    arr[i] = arr[j];
                    arr[j] = temp;
                }
            }
        }
        return arr;
    }

5、直接插入排序

原理:其基本操作是将一个记录插入到一个长度为m的有序表中,使之有序。从1索引处开始,将后面的元素,插入到之前的有序列表中使之仍保持有序

代码实现:

//直接插入排序
    private static int[] sortArray(int[] arr) {
        for (int i = 1; i < arr.length; i++) {
            int j = i;
            while (j > 0 && arr[j] < arr[j-1]){
                int temp = arr[j];
                arr[j] = arr[j-1];
                arr[j-1] = temp;
                j--;
            }
        }
        return arr;
   	 }
//两层for循环
    private static int[] sortArray1(int[] arr) {
        for (int i = 1; i < arr.length; i++) {
            for (int j = i; j > 0; j--) {
                if (arr[j] < arr[j - 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j - 1];
                    arr[j - 1] = temp;
                }
            }
        }
        return arr;
    }

6、希尔排序(又称缩小增量排序)

思想:先将原表按增量ht分组,每个子文件按照直接插入排序法排序。同样,用下一个增量ht/2将文件再分为子文件,再直接插入法排序。直到ht=1时整个文件排好序。

关键:选择合适的增量,增量的最普通选择就是使用数组长度的一半

排序算法:可以通过三重for循环来实现

代码实现:

//希尔排序
    private static int[] sortArray(int[] arr) {
        for (int h = arr.length/2; h > 0; h /= 2) {
            for (int i = h; i < arr.length; i++) {
                int j = i;
                while (j-h >= 0 && arr[j] < arr[j - h]) {
                    int temp = arr[j];
                    arr[j] = arr[j - h];
                    arr[j - h] = temp;
                    j -= h;
                }
            }
        }
        return arr;
}

增量的选取选择克努特序列:h=1; h=3*h+1;

//根据克努特序列,选择增量
    private static int[] sortArray1(int[] arr) {
        int ht = 1;
        while (ht <= arr.length/3)
            ht = ht*3+1;
        for (int h = ht; h > 0; h =(h-1)/3) {
            for (int i = h; i < arr.length; i++) {
                int j = i;
                while (j-h >= 0 && arr[j] < arr[j - h]) {
                    int temp = arr[j];
                    arr[j] = arr[j - h];
                    arr[j - h] = temp;
                    j -= h;
                }
            }
        }
        return arr;
    }

7、快速排序

思想:分治法,比大小,再分区

首先,从数组中取出一个数,作为基准数

然后,分区:将比这个数大或是等于的数全部放到它的右边,小于它的数全部放到它的左边

最后,再对左右区间重复第二步,直到各个区间只有一个数

代码实现:

public class ArrayTest6 {
    public static void main(String[] args) {
        int[] arr = {24, 69, 80, 52, 13};
        quickSort(arr,0, arr.length-1);
        for (int i : arr) {
            System.out.println(i);
        }
    }
    //快速排序,传入数组,开始位置,结束位置
    private static void quickSort(int[] arr,int low,int high) {
        // 找寻基准数据的正确索引
        if (low < high){
            int index = getIndex(arr,low,high);
            quickSort(arr,low,index-1);
            quickSort(arr,index+1,high);
        }
    }
    private static int getIndex(int[] arr, int low, int high) {
        int tmp = arr[low];
        while (low < high){
            while (low < high && arr[high] >= tmp)
                high--;
            arr[low] = arr[high];
            while (low < high && arr[low] < tmp)
                low++;
            arr[high] = arr[low];
        }
        // 跳出循环时low和high相等,此时的low或high就是tmp的正确索引位置
        arr[low] = tmp;
        return low;//返回tmp的正确位置
    }
}

8、归并排序

思想:利用归并的思想实现排序的方法

二路归并排序:假设初始序列有N个记录,则可以看作是N个有序的子序列,每个子序列的长度为1,然后两两归并,得到N/2个长度为2或1的子序列,再两两归并…如此重复,直至得到一个长度为N的有序序列为止。

代码实现:

public class ArrayTest7 {
    public static void main(String[] args) {
        int[] arr = {24, 69, 80, 52, 13};
        mergeSort(arr,0, arr.length-1);
        for (int i : arr) {
            System.out.println(i);
        }
    }

    //归并排序
    private static void mergeSort(int[] arr,int low,int high) {
        // 找寻基准数据的正确索引
        if (low < high){
            int mid = (low+high)/2;
            mergeSort(arr,low,mid);//将左边进行归并排序
            mergeSort(arr,mid+1,high);//将右边进行归并排序
            merge(arr,low,mid,high);//将两个有序数组进行归并
        }
    }
		//将两个有序数组进行归并
    private static void merge(int[] arr, int low, int mid, int high) {
        int i = low;
        int j = mid+1;
        int[] tempArr = new int[high-low+1];//定义临时数组
        int index = 0;//临时数组的起始索引
        while (i <= mid && j <= high){
            if (arr[i] <= arr[j])
                tempArr[index++] = arr[i++];
            else
                tempArr[index++] = arr[j++];
        }
        //将左边剩余元素填充进temp中
        while (i <= mid)
            tempArr[index++] = arr[i++];
        //将右边剩余元素填充进temp中
        while (j <= high)
            tempArr[index++] = arr[j++];
        //将临时数组中的元素放到原数组中去
        for (int k = 0; k < tempArr.length; k++) {
            arr[low+k] = tempArr[k];
        }
    }

}

9、基数排序(桶排序)

思想:它不需要直接对元素进行相互比较,也不需要将元素相互交换,需要做的就是对元素进行“分类”。基数排序的实现不需要进行对关键字的比较,只需对关键字进行“分配“与”收集“两种操作即可完成。

按个位十位百位的数字分别进行分配与收集的操作。

代码实现:

//基数排序
    private static void sortArray(int[] arr) {
        //首先得到最大数的长度
        int max = arr[0];
        for (int i = 1; i < arr.length; i++) {
            if (arr[i] > max)
                max = arr[i];
        }
        int len = String.valueOf(max).length();
        //定义二维数组,放十个桶
        int[][] tempArr = new int[10][arr.length];
        //用于存储桶内的元素位置
        int[] counts = new int[10];
        //循环轮次
        for (int i = 0, n = 1; i < len; i++, n *= 10) {
            for (int j = 0; j < arr.length; j++) {
                //获取每个位上的数字,计算余数
                int ys = (arr[j] / n) % 10;
                // 把数据放在指定数组中,有两个信息,放在第几个桶+数据应该放在第几位
                tempArr[ys][counts[ys]++] = arr[j];
            }

            //记录取的数字应该放到的位置
            int index = 0;
            for (int j = 0; j < counts.length; j++) {
                for (int k = 0; k < counts[j]; k++) {
                    arr[index++] = tempArr[j][k];
                }
                //清除上一次统计的个数
                counts[j] = 0;
            }
        }  
   }

10、堆排序

堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序。

思想:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点;将其与末尾元素进行交换,此时末尾元素就是最大值;然后将剩余n-1个元素重新构造呈一个堆,这样会得到n个元素的次小值;如此反复执行,便能得到一个有序序列了;

排序步骤:首先建造成一颗完全二叉树,然后从最后一个非叶子结点开始转成大顶堆;把根节点的元素和最后一个元素进行调换;

代码实现:

//堆排序
    private static void sortArray(int[] arr) {
        //1.构建大顶堆
        for (int i = arr.length/2-1; i >= 0 ; i--) {
            //从第一个非叶子结点从下至上,从左至右调整结构
            adjustHeap(arr,i, arr.length);
        }
        //2.调整堆结构+交换堆顶元素与末尾元素
        for (int i = arr.length-1; i > 0; i--) {
            //将堆顶元素与末尾元素进行交换
            int temp=arr[0];
            arr[0] = arr[i];
            arr[i] = temp;
            //重新对堆进行调整
            adjustHeap(arr,0,i);
        }
    }

    private static void adjustHeap(int[] arr, int i, int length) {
        int temp = arr[i];
        //从i结点的左子节点开始,也就是2i+1处开始
        for (int j = 2*i+1; j < length; j = j*2+1) {
            //如果左子结点小于右子结点,j指向右子结点
            if (j+1 < length && arr[j] < arr[j+1])
                j++;
            //如果子结点大于父结点,将子结点的值赋给父结点(不用进行交换)
            if(arr[j] > temp){
                arr[i] = arr[j];
                i = j;
            }else{
                break;
            }
        }
        arr[i] = temp;//将temp的值放到最终位置
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值