常见排序查找算法

简介: 常见排序查找算法

1 数组打乱顺序

数据里有{1,2,3,4,5,6,7,8,9},请随机打乱顺序,生成一个新的数组(请以代码实现)

    import java.util.Arrays;
    //打乱数组 
    public class Demo1 { //随机打乱 
        public static int[] srand(int[] a) {
            int[] b = new int[a.length];
            for (int i = 0; i < a.length; i++) {
                //随机获取下标 
                int tmp = (int) (Math.random() * (a.length - i)); //随机数: [ 0 , a.length - i ) 
                b[i] = a[tmp];
                //将此时a[tmp]的下标移动到靠后的位置 
                int change = a[a.length - i - 1];
                a[a.length - i - 1] = a[tmp];
                a[tmp] = change;
            }
            return b;
        }
        public static void main(String[] args) {
            int[] a = {1, 2, 3, 4, 5, 6, 7, 8, 9};
            System.out.println(Arrays.toString(srand(a)));
        }
    }

2 判断整数是不是2的阶次方

写出代码判断一个整数是不是2的阶次方(请代码实现,谢绝调用API方法)

import java.util.Scanner;
    //判断整数是不是2的阶次方 
    public class Demo2 {
        public static boolean check(int sum) {
            boolean flag = true;
            //判断标志 
            while (sum > 1) {
                if (sum % 2 == 0) {
                    sum = sum / 2;
                } else {
                    flag = false;
                    break;
                }
            }
            return flag;
        }
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in);
            System.out.println("请输入一个整数:");
            int sum = scanner.nextInt();
            System.out.println(sum + " 是不是2的阶次方:" + check(sum));
        }
    }

3、判断日期

假设今日是2015年3月1日,星期日,请算出13个月零6天后是星期几,距离现在多少天(请用代码实现,谢绝调用 API方法)

    mport java.util.Scanner;
    //算出星期几
    public class Demo4 {
        public static String[] week = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
        public static int i = 0;
        public static int[] monthday1 = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
        public static int[] monthday2 = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
        //查看距离当前天数的差值
        public static String distance(int year, int month, int day, int newMonth, int newDay) {
            int sum = 0; //设定初始距离天数
            if (month + newMonth >= 12) {
                if (((year + 1) % 4 == 0 && (year + 1) % 100 != 0) || (year + 1) % 400 == 0) {
                    sum += 366 + newDay;
                    for (int i = 0; i < newMonth - 12; i++) {
                        sum += monthday1[month + i];
                    }
                } else {
                    sum += 365 + newDay;
                    for (int i = 0; i < newMonth - 12; i++) {
                        sum += monthday1[month + i];
                    }
                }
            } else {
                for (int i = 0; i < newMonth; i++) {
                    sum += monthday1[month + i];
                }
                sum += newDay;
            }
            return week[sum % 7];
        }
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in);
            System.out.println("请输入当前年份");
            int year = scanner.nextInt();
            System.out.println("请输入当前月份");
            int month = scanner.nextInt();
            System.out.println("请输入当前天数");
            int day = scanner.nextInt();
            System.out.println("请输入当前是星期几:以数字表示,如:星期天 为 0");
            int index = scanner.nextInt();
            System.out.println("今天是:" + year + "-" + month + "-" + day + " " +
                    week[index]);
            System.err.println("请输入相隔月份");
            int newMonth = scanner.nextInt();
            System.out.println("请输入剩余天数");
            int newDay = scanner.nextInt();
            System.out.println("经过" + newMonth + "月" + newDay + "天后,是" +
                    distance(year, month, day, newMonth, newDay));
        }
    }

4、面向对象思想实现篮子物品交换

有两个篮子,分别为A 和 B,篮子A里装有鸡蛋,篮子B里装有苹果,请用面向对象的思想实现两个篮子里的物品交换(请用代码实现)

答:

    //面向对象思想实现篮子物品交换
    public class Demo5 {
        public static void main(String[] args) {
//创建篮子
            Basket A = new Basket("A");
            Basket B = new Basket("B");
//装载物品
            A.load("鸡蛋");
            B.load("苹果");
//交换物品
            A.change(B);
            A.show();
            B.show();
        }
    }
    class Basket {
        public String name; //篮子名称
        private Goods goods; //篮子中所装物品
        public Basket(String name) {
// TODO Auto-generated constructor stub
            this.name = name;
            System.out.println(name + "篮子被创建");
        }
        //装物品函数
        public void load(String name) {
            goods = new Goods(name);
            System.out.println(this.name + "装载了" + name + "物品");
        }
        public void change(Basket B) {
            System.out.println(this.name + " 和 " + B.name + "中的物品发生了交换");
            String tmp = this.goods.getName();
            this.goods.setName(B.goods.getName());
            B.goods.setName(tmp);
        }
        public void show() {
            System.out.println(this.name + "中有" + goods.getName() + "物品");
        }
    }
    class Goods {
        private String name; //物品名称
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public Goods(String name) {
// TODO Auto-generated constructor stub
            this.name = name;
        }
    }

5 二分查找

又叫折半查找,要求待查找的序列有序。每次取中间位置的值与待查关键字比较,如果中间位置的值比待查关键字大,则在前半部分循环这个查找的过程,如果中间位置的值比待查关键字小,则在后半部分循环这个查找的过程。直到查找到了为止,否则序列中没有待查的关键字。

public static int biSearch(int []array,int a){
  int lo=0;
  int hi=array.length-1;
  int mid;
  while(lo<=hi){
    mid=(lo+hi)/2;
    //中间位置 if(array[mid]==a){ return mid+1; }else if(array[mid]<a){ //向右查找 lo=mid+1; }else{ //向左查找 hi=mid-1; } }return -1; }

6 冒泡排序算法

1)比较前后相邻的二个数据,如果前面数据大于后面的数据,就将这二个数据交换。


2)这样对数组的第 0 个数据到 N-1 个数据进行一次遍历后,最大的一个数据就“沉” 到数组第N-1 个位置。


3) N=N-1,如果 N 不为 0 就重复前面二步,否则排序完成。

    public static void bubbleSort1(int [] a, int n){
        int i, j;
        for(i=0; i<n; i++){//表示 n 次排序过程。
            for(j=1; j<n-i; j++){
                if(a[j-1] > a[j]){//前面的数字大于后面的数字就交换
//交换 a[j-1]和 a[j]
                    int temp;
                    temp = a[j-1];
                    a[j-1] = a[j];
                    a[j]=temp;
                }
            }
        }
    }

7 插入排序算法

通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应的位置并插入。插入排序非常类似于整扑克牌。在开始摸牌时,左手是空的,牌面朝下放在桌上。接着, 一次从桌上摸起一张牌,并将它插入到左手一把牌中的正确位置上。 为了找到这张牌的正确位置,要将它与手中已有的牌从右到左地进行比较。无论什么时候,左手中的牌都是排好序的。如果输入数组已经是排好序的话,插入排序出现最佳情况,其运行时间是输入规模的一个线性函数。如果输入数组是逆序排列的,将出现最坏情况。平均情况与最坏情况一样,其时间代价是(n2)。

    public void sort(int arr[]){
        for(int i =1; i<arr.length;i++)
        {
//插入的数
            int insertVal = arr[i];
//被插入的位置(准备和前一个数比较)
            int index = i-1;
//如果插入的数比被插入的数小
            while(index>=0&&insertVal<arr[index])
            {
//将把 arr[index] 向后移动
                arr[index+1]=arr[index];
//让 index 向前移动
                index--;
            }
//把插入的数放入合适位置
            arr[index+1]=insertVal;
        }
    }

8 快速排序算法

快速排序的原理:选择一个关键值作为基准值。比基准值小的都在左边序列(一般是无序的),比基准值大的都在右边(一般是无序的)。 一般选择序列的第一个元素。


一次循环: 从后往前比较,用基准值和最后一个值比较,如果比基准值小的交换位置,如果没有继续比较下一个,直到找到第一个比基准值小的值才交换。 找到这个值之后,又从前往后开始比较,如果有比基准值大的,交换位置,如果没有继续比较下一个,直到找到第一个比基准值大的值才交换。直到从前往后的比较索引>从后往前比较的索引,结束第一次循环,此时,对于基准值来说,左右两边就是有序的了。

    public void sort(int[] a, int low, int high) {
        int start = low;
        int end = high;
        int key = a[low];
        while (end > start) {
//从后往前比较
            while (end > start && a[end] >= key)
//如果没有比关键值小的,比较下一个,直到有比关键值小的交换位置,然后又从前往后比较
                end--;
            if (a[end] <= key) {
                int temp = a[end];
                a[end] = a[start];
                a[start] = temp;
            }
//从前往后比较
            while (end > start && a[start] <= key) {
//如果没有比关键值大的,比较下一个,直到有比关键值大的交换位置
                start++;
                if (a[start] >= key) {
                    int temp = a[start];
                    a[start] = a[end];
                    a[end] = temp;
                }
//此时第一次循环比较结束,关键值的位置已经确定了。左边的值都比关键值小,右边的值都比关键值大,但是两边的顺序还有可能是不一样的,进行下面的递归调用
            }
//递归
            if (start > low) sort(a, low, start - 1);//左边序列。第一个索引位置到关键值索引-1
            if (end < high) sort(a, end + 1, high);//右边序列。从关键值索引+1 到最后一个
        }
    }

9 希尔排序算法

基本思想:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序” 时,再对全体记录进行依次直接插入排序。

操作方法:选择一个增量序列t1, t2, …, tk,其中 ti>tj, tk=1; 2. 按增量序列个数k,对序列进行k趟排序;

每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m的子序列,分别对各子表进行直接插入排序。仅增量因子为1时,整个序列作为一个表来处理,表长度即为整个序列的长度。

2021051114342619.png

    private void shellSort(int[] a) {
        int dk = a.length / 2;
        while (dk >= 1) {
            ShellInsertSort(a, dk);
            dk = dk / 2;
        }
    }
    private void ShellInsertSort(int[] a, int dk) {
//类似插入排序,只是插入排序增量是 1,这里增量是 dk,把 1 换成 dk 就可以了
        for (int i = dk; i < a.length; i++) {
            if (a[i] < a[i - dk]) {
                int j;
                int x = a[i];//x 为待插入元素
                a[i] = a[i - dk];
                for (j = i - dk; j >= 0 && x < a[j]; j = j - dk) {
//通过循环,逐个后移一位找到要插入的位置。
                    a[j + dk] = a[j];
                }
                a[j + dk] = x;//插入
            }
        }
    }

10 归并排序算法

归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。

    public class MergeSortTest {
        public static void main(String[] args) {
            int[] data = new int[]{5, 3, 6, 2, 1, 9, 4, 8, 7};
            print(data);
            mergeSort(data);
            System.out.println("排序后的数组: ");
            print(data);
        }
        public static void mergeSort(int[] data) {
            sort(data, 0, data.length - 1);
        }
        public static void sort(int[] data, int left, int right) {
            if (left >= right)
                return;
// 找出中间索引
            int center = (left + right) / 2;
// 对左边数组进行递归
            sort(data, left, center);
// 对右边数组进行递归
            sort(data, center + 1, right);
// 合并
            merge(data, left, center, right);
            print(data);
        }
        /**
         * 将两个数组进行归并,归并前面 2 个数组已有序,归并后依然有序
         *
         * @param data   数组对象
         * @param left   左数组的第一个元素的索引
         * @param center 左数组的最后一个元素的索引, center+1 是右数组第一个元素的索引
         * @param right  右数组最后一个元素的索引
         */
        public static void merge(int[] data, int left, int center, int right) {
                // 临时数组
            int[] tmpArr = new int[data.length];
                // 右数组第一个元素索引
            int mid = center + 1;
           // third 记录临时数组的索引
             int third = left;
             // 缓存左数组第一个元素的索引
            int tmp = left;
            while (left <= center && mid <= right) {
                // 从两个数组中取出最小的放入临时数组
                if (data[left] <= data[mid]) {
                    tmpArr[third++] = data[left++];
                } else {
                    tmpArr[third++] = data[mid++];
                }
            }
         // 剩余部分依次放入临时数组(实际上两个 while 只会执行其中一个)
            while (mid <= right) {
                tmpArr[third++] = data[mid++];
            }
            while (left <= center) {
                tmpArr[third++] = data[left++];
            }
   // 将临时数组中的内容拷贝回原数组中
   // (原 left-right 范围的内容被复制回原数组)
            while (tmp <= right) {
                data[tmp] = tmpArr[tmp++];
            }
        }
        public static void print(int[] data) {
            for (int i = 0; i < data.length; i++) {
                System.out.print(data[i] + "\t");
            }
            System.out.println();
        }
    }

11 桶排序算法

桶排序的基本思想是: 把数组 arr 划分为 n 个大小相同子区间(桶),每个子区间各自排序,最后合并 。计数排序是桶排序的一种特殊情况,可以把计数排序当成每个桶里只有一个元素的情况。


1.找出待排序数组中的最大值 max、最小值 min


2.我们使用 动态数组 ArrayList 作为桶,桶里放的元素也用 ArrayList 存储。桶的数量为(maxmin)/arr.length+1


3.遍历数组 arr,计算每个元素 arr[i] 放的桶


4.每个桶各自排序

    public static void bucketSort(int[] arr) {
        int max = Integer.MIN_VALUE;
        int min = Integer.MAX_VALUE;
        for (int i = 0; i < arr.length; i++) {
            max = Math.max(max, arr[i]);
            min = Math.min(min, arr[i]);
        }
        //创建桶
        int bucketNum = (max - min) / arr.length + 1;
        ArrayList<ArrayList<Integer>> bucketArr = new ArrayList<>(bucketNum);
        for (int i = 0; i < bucketNum; i++) {
            bucketArr.add(new ArrayList<Integer>());
        }
                //将每个元素放入桶
        for (int i = 0; i < arr.length; i++) {
            int num = (arr[i] - min) / (arr.length);
            bucketArr.get(num).add(arr[i]);
        }
        //对每个桶进行排序
        for (int i = 0; i < bucketArr.size(); i++) {
            Collections.sort(bucketArr.get(i));
        }
    }

12 基数排序算法

将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。

    public class radixSort {
        int a[] = {49, 38, 65, 97, 76, 13, 27, 49, 78, 34, 12, 64, 5, 4, 62, 99, 98, 54, 101, 56, 17, 18, 23, 34, 15, 35, 2 5, 53, 51};
        public radixSort() {
            sort(a);
            for (inti = 0; i < a.length; i++) {
                System.out.println(a[i]);
            }
        }
        public void sort(int[] array) {
               //首先确定排序的趟数;
            int max = array[0];
            for (inti = 1; i < array.length; i++) {
                if (array[i] > max) {
                    max = array[i];
                }
            }
            int time = 0;
            //判断位数;
            while (max > 0) {
                max /= 10;
                time++;
            }
                   //建立 10 个队列;
            List<ArrayList> queue = newArrayList < ArrayList > ();
            for (int i = 0; i < 10; i++) {
                ArrayList<Integer> queue1 = new ArrayList<Integer>();
                queue.add(queue1);
            }
                 //进行 time 次分配和收集;
            for (int i = 0; i < time; i++) {
             //分配数组元素;
                for (intj = 0; j < array.length; j++) {
                  //得到数字的第 time+1 位数;
                    int x = array[j] % (int) Math.pow(10, i + 1) / (int) Math.pow(10, i);
                    ArrayList<Integer> queue2 = queue.get(x);
                    queue2.add(array[j]);
                    queue.set(x, queue2);
                }
                int count = 0;//元素计数器;
              //收集队列元素;
                for (int k = 0; k < 10; k++) {
                    while (queue.get(k).size() > 0) {
                        ArrayList<Integer> queue3 = queue.get(k);
                        array[count] = queue3.get(0);
                        queue3.remove(0);
                        count++;
                    }
                }
            }
        }
    }

13 剪枝算法

在搜索算法中优化中,剪枝,就是通过某种判断,避免一些不必要的遍历过程,形象的说,就是剪去了搜索树中的某些“枝条”,故称剪枝。应用剪枝优化的核心问题是设计剪枝判断方法,即确定哪些枝条应当舍弃,哪些枝条应当保留的方法。

14 回溯算法

回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。

15 最短路径算法

从某顶点出发,沿图的边到达另一顶点所经过的路径中,各边上权值之和最小的一条路径叫做最短路径。解决最短路的问题有以下算法,Dijkstra算法,Bellman-Ford算法,Floyd算法和SPFA算法等

16 最小生成树算法

现在假设有一个很实际的问题:我们要在n个城市中建立一个通信网络,则连通这n个城市需要布置n-1一条通信线路,这个时候我们需要考虑如何在成本最低的情况下建立这个通信网?


于是我们就可以引入连通图来解决我们遇到的问题,n个城市就是图上的n个顶点,然后,边表示两个城市的通信线路,每条边上的权重就是我们搭建这条线路所需要的成本,所以现在我们有n个顶点的连通网可以建立不同的生成树,每一颗生成树都可以作为一个通信网,当我们构造这个连通网所花的成本最小时,搭建该连通网的生成树,就称为最小生成树。


构造最小生成树有很多算法,但是他们都是利用了最小生成树的同一种性质:MST性质(假设N=(V,{E})是一个连通网, U 是顶点集V的一个非空子集,如果(u,v)是一条具有最小权值的边,其中u属于U, v属于V-U,则必定存在一颗包含边(u, v)的最小生成树),下面就介绍两种使用MST性质生成最小生成树的算法:普里姆算法和克鲁斯卡尔算法。

28ebf1bd8ba244a08a4f9438cf8f639b.png

17 常见加密算法

常见登录密码加密方式

目录
相关文章
|
5月前
|
算法 C++
【洛谷 P1223】排队接水(贪心算法+结构体排序)
该问题要求安排$n$个人的排队顺序以最小化平均等待时间。每个人接水需时$T_i$,解决方案是让接水时间短的人优先。给定$n\leq1000$和$t_i\leq10^6$,代码示例使用C++实现,通过排序使时间从小到大排列,然后计算平均等待时间。样例输入为10个人的时间数组,输出为优化后的排队顺序及平均等待时间(291.90)。
53 0
|
3月前
|
算法
【算法】二分查找——在排序数组中查找元素的第一个和最后一个位置
【算法】二分查找——在排序数组中查找元素的第一个和最后一个位置
|
9天前
|
搜索推荐 算法 C语言
【排序算法】八大排序(上)(c语言实现)(附源码)
本文介绍了四种常见的排序算法:冒泡排序、选择排序、插入排序和希尔排序。通过具体的代码实现和测试数据,详细解释了每种算法的工作原理和性能特点。冒泡排序通过不断交换相邻元素来排序,选择排序通过选择最小元素进行交换,插入排序通过逐步插入元素到已排序部分,而希尔排序则是插入排序的改进版,通过预排序使数据更接近有序,从而提高效率。文章最后总结了这四种算法的空间和时间复杂度,以及它们的稳定性。
50 8
|
9天前
|
搜索推荐 算法 C语言
【排序算法】八大排序(下)(c语言实现)(附源码)
本文继续学习并实现了八大排序算法中的后四种:堆排序、快速排序、归并排序和计数排序。详细介绍了每种排序算法的原理、步骤和代码实现,并通过测试数据展示了它们的性能表现。堆排序利用堆的特性进行排序,快速排序通过递归和多种划分方法实现高效排序,归并排序通过分治法将问题分解后再合并,计数排序则通过统计每个元素的出现次数实现非比较排序。最后,文章还对比了这些排序算法在处理一百万个整形数据时的运行时间,帮助读者了解不同算法的优劣。
36 7
|
1月前
|
搜索推荐 Shell
解析排序算法:十大排序方法的工作原理与性能比较
解析排序算法:十大排序方法的工作原理与性能比较
49 9
|
1月前
|
算法 搜索推荐 Java
数据结构与算法学习十三:基数排序,以空间换时间的稳定式排序,速度很快。
基数排序是一种稳定的排序算法,通过将数字按位数切割并分配到不同的桶中,以空间换时间的方式实现快速排序,但占用内存较大,不适合含有负数的数组。
23 0
数据结构与算法学习十三:基数排序,以空间换时间的稳定式排序,速度很快。
|
1月前
|
算法
❤️算法笔记❤️-(每日一刷-83、删除排序链表中的重复项)
❤️算法笔记❤️-(每日一刷-83、删除排序链表中的重复项)
30 0
|
1月前
|
存储 算法 搜索推荐
算法进阶之路:Python 归并排序深度剖析,让数据排序变得艺术起来!
算法进阶之路:Python 归并排序深度剖析,让数据排序变得艺术起来!
70 0
|
3月前
|
搜索推荐 算法 Java
现有一个接口DataOperation定义了排序方法sort(int[])和查找方法search(int[],int),已知类QuickSort的quickSort(int[])方法实现了快速排序算法
该博客文章通过UML类图和Java源码示例,展示了如何使用适配器模式将QuickSort类和BinarySearch类的排序和查找功能适配到DataOperation接口中,实现算法的解耦和复用。
39 1
现有一个接口DataOperation定义了排序方法sort(int[])和查找方法search(int[],int),已知类QuickSort的quickSort(int[])方法实现了快速排序算法
|
3月前
|
算法 搜索推荐 Java
算法实战:手写归并排序,让复杂排序变简单!
归并排序是一种基于“分治法”的经典算法,通过递归分割和合并数组,实现O(n log n)的高效排序。本文将通过Java手写代码,详细讲解归并排序的原理及实现,帮助你快速掌握这一实用算法。
41 0