码迷,mamicode.com
首页 > 编程语言 > 详细

数据结构和算法--6排序算法

时间:2020-03-21 16:41:05      阅读:66      评论:0      收藏:0      [点我收藏+]

标签:分治策略   记录   过程   flag   输出   ext   select   稳定性   amp   

1.排序的分类

1) 内部排序:指将需要处理的所有数据都加载到内部存储器中进行排序

2) 外部排序:无法全部加载到内存中,需要借助外部存储进行

3)图示:

技术图片

2.算法的时间复杂度

1)  度量一个程序(算法)执行时间的两种方法

A.事后统计的方法

问题:a.需要实际运行该程序。b.时间也依赖于计算机的硬件,软件等环境因素。所以要在同一台计算机的相同状态下运行,才能比较哪个算法速度更快

B.事前估算的方法

通过分分析某个算法的时间复杂度来判断哪个算法更优

2)  时间频度

A. 基本介绍

一个算法花费的时间与算法中语句的执行次数成正比,哪个算法中语句执行次数多,它花费的时间越长,一个算法中的语句执行次数称为语句频度或时间频度。记为T(n)

B. 忽略常数项,忽略低次项,忽略系数

C .图示:技术图片

3)常见的时间复杂度

 技术图片

A.

 技术图片 

B.

技术图片

C.

技术图片

D.

技术图片

E.

技术图片

4)平均时间复杂度和最坏时间复杂度

A.平均时间复杂度:所有可能的输入实例均以等概率出现的情况下,该算法的运行时间

B.最坏时间复杂度:最坏情况下的时间复杂度,一般讨论的时间算法复杂度均是最坏时间复杂度

C.

 技术图片

3.算法的空间复杂度

1)基本介绍

该算法该耗费的存储空间,也是空间规模n的函数。随着n的增大而增大,当n较大时,将占用较多的存储单元,例如快速排序和归并排序算法

4.排序

1)冒泡排序

A.思想:

通过对待排序序列从前往后(从下标较小的元素开始),依次比较相邻元素的值,若发现逆序则交换,使值较大的元素逐渐从前移向后部。

B.图示:

技术图片

C.代码:

package com.offcn.sort;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

//冒泡排序
public class BubbleSort {
    public static void main(String[] args){
            int[] arr = {3,9,-1,10,-2};
            //冒泡优化
           int[] arr1 = {1,2,3,4,5,6};
            bubbleSort(arr);
        //冒泡排序的速度测试
        int[] arrTime = new int[80000];
        for(int i = 0; i < arrTime.length;i++){
            arrTime[i] = (int)(Math.random()*8000000);
        }
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String format = sdf.format(date);
        System.out.println("排序前的时间为"+format);

        bubbleSort(arrTime);

        Date date1 = new Date();
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String format1 = sdf1.format(date1);
        System.out.println("排序后的时间为"+format1);
    }
    public static void bubbleSort(int[] arr){
        //临时遍历
        int temp = 0;
        //定义一个变量
        boolean flag = false;
        //总共循环arr.length-1次,每次拿到最大的值
        for(int i = 0;i < arr.length-1;i++){
            //里层循环,拿到最大值后,只需再遍历前面未排序的数字即可,循环次数递减
            for(int j = 0;j < arr.length-1-i;j++){
                //如果前一个数字小,就互换位置,大的后移
                if(arr[j] > arr[j+1]){
                    //如果需要换位,则flag = true
                    flag = true;
                    temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
            System.out.println(""+(i+1)+"次排序结果");
            System.out.println(Arrays.toString(arr));
            //冒泡排序优化
            if(!flag){
                //如果本次排序未换位,说明已经排好,退出
                break;
            }else {
                flag = false;
            }
        }
    }
}

D 输出:

技术图片

 优化:

技术图片

 速度:

技术图片

2)选择排序

A.思想:

第一次从arr[0]~arr[n-1]中选取最小值,与arr[0]交换,第二次从arr[1]~arr[n-1]中选取最小值,与arr[1]交换,第三次从arr[2]~arr[n-1]中选取最小值,与arr[2]交换…得到
一个按排序码从小到大排列的有序序列。

B.图示:

技术图片

 C.代码

package com.offcn.sort;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

//选择排序
public class SelectSort {
    public static void main(String[] args){
        int[] arr={101,-1,119,1};
        System.out.println("排序前~"+Arrays.toString(arr));
        selectSort(arr);

        //选择排序的速度测试
        int[] arrTime = new int[80000];
        for(int i = 0; i < arrTime.length;i++){
            arrTime[i] = (int)(Math.random()*8000000);
        }
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String format = sdf.format(date);
        System.out.println("排序前的时间为"+format);

        selectSort(arrTime);

        Date date1 = new Date();
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String format1 = sdf1.format(date1);
        System.out.println("排序后的时间为"+format1);

    }
    public static void selectSort(int[] arr){
        //循环arr.length-1次,每次把最小值往前移动
        for(int i = 0;i < arr.length-1;i++){
            //默认最小值的索引是i
            int minIndex = i;
            //默认最小值是arr[i]
            int min = arr[i];
            //每次最小值都是跟后面的数比较
            for(int j =(i+1);j<arr.length;j++){
                //如果后面的值比默认最小值还小,就互换位置
                if(min > arr[j]){
                    minIndex = j;
                    min = arr[j];
                }
            }
            //优化,如果索引为i,说明循环中没有换位
            if(minIndex != i){
                //把默认最小值换到后面去
                arr[minIndex] = arr[i];
                //把最小值放前
                arr[i] = min;
            }
            System.out.println(""+(i+1)+"次排序"+ Arrays.toString(arr));
        }
    }
}

D.输出:

技术图片

速度:

技术图片

 

 3)插入排序

A.思想:

把n个待排序的元素看成为一个有序表和一个无序表,开始时有序表中只包含一个元素,无序表中包含n-1个元素,排序过程中每次从无序表中取出第一个元素,把它的排序码依次与有序表元素
的排序码进行比较,将它插入到有序表中的适当位置,使之成为新的有序表。

B.图示:

技术图片

 C.代码

package com.offcn.sort;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

//插入排序
public class InsertSort {
    public static void main(String[] args){
        int[] arr={101,-1,119,1};
        System.out.println("排序前~"+Arrays.toString(arr));
        insertSort(arr);

        //插入排序的速度测试
        int[] arrTime = new int[80000];
        for(int i = 0; i < arrTime.length;i++){
            arrTime[i] = (int)(Math.random()*8000000);
        }
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String format = sdf.format(date);
        System.out.println("排序前的时间为"+format);

        insertSort(arrTime);

        Date date1 = new Date();
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String format1 = sdf1.format(date1);
        System.out.println("排序后的时间为"+format1);

    }
    public static void insertSort(int[] arr){
        for(int i = 1;i < arr.length;i++){
            //arr[i]表示无序表的第一个数字,先存起来,找合适的位置插入进去
            int insertVal = arr[i];
            //insertIndex表示有序表的最后一个数字的下标
            int insertIndex = i-1;
            //insertValue依次跟有序表中的数据比较,而且有序表的数要比insertVal大的情况下
            while (insertIndex >=0 && arr[insertIndex] > insertVal){
                //把大的数复制一份放入无序表的第一个数
                arr[insertIndex+1] = arr[insertIndex];
                //有序表索引前移
                insertIndex--;
            }
            //把有序表的第一个值插入进去,因为while循环最后都是--,所以需要insertIndex+1
            //优化,==i时,int insertVal = arr[i];
            if(insertIndex+1 != i){
                arr[insertIndex+1] = insertVal;
            }
            System.out.println(""+(i)+"次排序"+ Arrays.toString(arr));
        }
    }
}

D.输出:

技术图片

速度:

技术图片

 

 4)希尔排序

A.介绍:

希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序。

B.思想:

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

C.图示:

技术图片

D.交换法代码

package com.offcn.sort;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

//希尔排序
public class ShellSort {
    public static void main(String[] args){
        int[] arr = {8,9,1,7,2,3,5,4,6,0};
        shellSort(arr);
        //希尔排序交换法的速度测试
        int[] arrTime = new int[80000];
        for(int i = 0; i < arrTime.length;i++){
            arrTime[i] = (int)(Math.random()*8000000);
        }
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String format = sdf.format(date);
        System.out.println("排序前的时间为"+format);

        shellSort(arrTime);

        Date date1 = new Date();
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String format1 = sdf1.format(date1);
        System.out.println("排序后的时间为"+format1);
    }
    //交换法
    public static void shellSort(int[] arr){
        int count = 0;
        //外层循环arr.length/2/2/2/2/2至=1时
        for(int grap = (arr.length)/2;grap > 0;grap/=2){
            //i表示一组中位置在后的数字
            for(int i = grap;i < arr.length;i++){
                for(int j = i-grap;j >=0;j-=grap){
                    //如果后面的数字小于前面的,则换位
                    if(arr[j+grap] < arr[j]){
                        int temp = arr[j];
                        arr[j] = arr[j+grap];
                        arr[j+grap] = temp;
                    }
                }
            }
            System.out.println(""+(++count)+"次排序:"+Arrays.toString(arr));
        }

    }
}

输出:

技术图片

速度:

技术图片

 

 E.移位法代码

//希尔排序
public class ShellSort {
    public static void main(String[] args){
        int[] arr = {8,9,1,7,2,3,5,4,6,0};
        shellSort2(arr);
        //希尔排序移位法的速度测试
        int[] arrTime = new int[80000];
        for(int i = 0; i < arrTime.length;i++){
            arrTime[i] = (int)(Math.random()*8000000);
        }
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String format = sdf.format(date);
        System.out.println("排序前的时间为"+format);

        shellSort2(arrTime);

        Date date1 = new Date();
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String format1 = sdf1.format(date1);
        System.out.println("排序后的时间为"+format1);
    }
    public static void shellSort2(int[] arr){
        //外层循环arr.length/2/2/2/2/2至=1时
        int count =0;
        for(int grap = arr.length/2;grap > 0;grap/=2){
            for(int i = grap;i<arr.length;i++){
                //arr[j] 表示一组中位置在后的数字,arr[j-grap]表示位置在前
                int j = i;
                int temp = arr[j];
                //如果前面的数字比较打,移位
                if(arr[j] < arr[j-grap]){
                    while (j-grap>=0 && temp<arr[j-grap]){
                        arr[j] = arr[j-grap];
                        j-=grap;
                    }
                    //当退出while循环,则找到位置
                    arr[j] = temp;
                }
            }
            System.out.println(""+(++count)+"次排序:"+Arrays.toString(arr));
        }

    }

输出:

技术图片

速度:

 技术图片

5)快速排序

A.介绍:

是对冒泡排序的一种改进。

B.思想:

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

C.图示:

技术图片

 

D.代码

package com.offcn.sort;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

//快速排序
public class QuickSort {
    public static void main(String[] args){
        int[] arr = {-9,78,0,23,-567,70};
        quickSort(arr,0,arr.length-1);
        System.out.println(Arrays.toString(arr));
        //快速排序的速度测试
        int[] arrTime = new int[80000];
        for(int i = 0; i < arrTime.length;i++){
            arrTime[i] = (int)(Math.random()*8000000);
        }
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String format = sdf.format(date);
        System.out.println("排序前的时间为"+format);

        quickSort(arrTime,0,arrTime.length-1);

        Date date1 = new Date();
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String format1 = sdf1.format(date1);
        System.out.println("排序后的时间为"+format1);
    }
    //left表示数组最小下标,right表示数组最大下标
    public static void quickSort(int[] arr,int left,int right){
        int l = left;//左下标
        int r = right;//右下标
        //中轴值
        int pivot = arr[(left+right)/2];
        int temp = 0;
        while (l < r){
            //找出左边比中轴值大的数字
            while (arr[l] < pivot){
                l+=1;
            }
            //找出右边比中轴值小的数字
            while (arr[r] > pivot){
                r-=1;
            }
            //如果l++,r--后,l的坐标比右边的大了或者相等了,说明已经遍历左右已经遍历完毕
           if(l >= r){
                break;
            }
            //交换
            temp= arr[l];
            arr[l] = arr[r];
            arr[r] = temp;
            //如果交换完,arr[l] == pivot,r前移
            if(arr[l] == pivot){
                r-=1;
            }
            //如果交换完,arr[] == pivot,l后移
            if(arr[r] == pivot){
                l+=1;
            }
        }
        //如果l==r,表示都遍历到中轴的下标了,需要把位置错开
        //此时l为中轴右侧最小小标,r为中轴左侧最大下标
        if(l == r){
            l+=1;
            r-=1;
        }
        //向左递归
        if(left < r){
            quickSort(arr,left,r);
        }
        //向右递归
        if(right > l){
            quickSort(arr,l,right);
        }
    }
}

E.输出:

技术图片

速度:

技术图片

 

 6)归并排序

A.介绍:

是利用归并的思想实现的排序方法,该算法采用经典的分治策略(分治法将问题分成一些小的问题然后递归求解,而治的阶段则将分的阶段得到的各答案修补在一起)

B.思想:

技术图片

 

技术图片

C.代码

package com.offcn.sort;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

//归并排序
public class MergeSort {
    public static void main(String[] args){
        int[] arr = {8,4,5,7,1,3,6,2};
        int[] temp = new int[arr.length];
        mergeSort(arr,0,arr.length-1,temp);
        System.out.println("归并排序后"+ Arrays.toString(arr));
        //归并排序的速度测试
        int[] arrTime = new int[80000];
        int[] temp2 = new int[arrTime.length];
        for(int i = 0; i < arrTime.length;i++){
            arrTime[i] = (int)(Math.random()*8000000);
        }
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String format = sdf.format(date);
        System.out.println("排序前的时间为"+format);

        mergeSort(arrTime,0,arrTime.length-1,temp2);

        Date date1 = new Date();
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String format1 = sdf1.format(date1);
        System.out.println("排序后的时间为"+format1);
    }
    //分合
    public static void mergeSort(int[] arr,int left,int right,int[] temp){
        if(left < right){
            int mid = (left+right)/2;
            //向左递归分解
            mergeSort(arr,left,mid,temp);
            //向右递归分解
            mergeSort(arr,mid+1,right,temp);
            //合并
            merge(arr,left,mid,right,temp);
        }
    }
    //合并
    /**
     * @param arr 排序的原始数组
     * @param left 左边有序序列的最小索引
     * @param mid   中间索引
     * @param right 右边有序序列的最大索引
     * @param temp 中转数组
     */
    public static void merge(int[] arr,int left,int mid,int right,int[] temp){
        //i作为左边有序序列的最小下标
        int i = left;
        //j作为右边有序序列的最小下标
        int j = mid+1;
        //t是中转数组的下标
        int t = 0;
        //(一)把左右两边的有序序列填充到中转数组中
        while (i <= mid&& j <= right){
            //如果左边的数比右边的小,小的放入temp[t]中
            if(arr[i] <= arr[j]){
                temp[t] = arr[i];
                t+=1;
                i+=1;

            }else{
                temp[t] = arr[j];
                t+=1;
                j+=1;
            }
        }
        //(二)如果一边已经存放完毕,另一边还有数据,则依次存放即可
        while (i <= mid){
            temp[t] = arr[i];
            t+=1;
            i+=1;
        }
        while (j <= right){
            temp[t] = arr[j];
            t+=1;
            j+=1;
        }
        //(三)把temp数组中的元素拷贝到arr,temp下标从0开始,但是arr下标要从left开始,最后才是一个数组
        int q = 0;
        //如left = 2,right = 3
        int arrLeft = left;
        while (arrLeft <= right){
            arr[arrLeft] = temp[q];
            q+=1;
            arrLeft+=1;
        }
    }
}

D.输出:

技术图片

速度:

技术图片

 

 7)基数排序

A.介绍:

基数排序属于分配式排序,又称“桶子法”,它是通过键值的各个位的值,将要排序的元素分配至某些桶中,达到排序的作用。基数排序法是属于稳定性的排序,也是桶排序的扩展

B.思想:

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

C.图示:

技术图片

技术图片

技术图片

 

 

 技术图片

D.代码

package com.offcn.sort;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

//基数排序,有负数时尽量不使用基数排序
public class RedixSort {
    public static void main(String[] args){
        int[] arr = {53,3,542,748,14,214};
        redixSort(arr);
        //基数排序的速度测试
        int[] arrTime = new int[80000];
        for(int i = 0; i < arrTime.length;i++){
            arrTime[i] = (int)(Math.random()*8000000);
        }
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String format = sdf.format(date);
        System.out.println("排序前的时间为"+format);

        redixSort(arrTime);

        Date date1 = new Date();
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String format1 = sdf1.format(date1);
        System.out.println("排序后的时间为"+format1);

    }
    public static void redixSort(int[] arr){
        //先得到数组中最大数是几位数
        //拿到最大数
        int max = arr[0];
        for(int i = 1;i < arr.length;i++){
            if(arr[i] > max){
                max = arr[i];
            }
        }
        //是几位数
        int maxLength = (max+"").length();
        //定义一个二维数组,总共十个桶,每个桶内有多少数未知,所以定为arr.length
        int[][] bucket = new int[10][arr.length];
        //记录每个桶具体有多少数
        int[] bucketCount = new int[10];
        //总共循环maxLength次
        for(int i = 0,n = 1; i < maxLength;i++,n*=10){
            //对数组中的数字都进行判断,拿到相应的值
            for(int j = 0;j < arr.length;j++){
                //对元素中的个十百位进行处理
                int num = arr[j] /n % 10;
                //num表示是第一个桶,bucketCount[num]表示该桶下第几个元素,第一个默认为0下标
                bucket[num][bucketCount[num]] = arr[j];
                //放入一个,下标加1
                bucketCount[num]++;
            }
            //根据桶的顺序,把元素再存入原数组中
            int index = 0;
            //有几个桶循环几遍
            for(int k = 0;k < bucket.length;k++){
                //如果i桶里有元素
                if(bucketCount[k] != 0){
                    //循环bucketCount[k]次
                    for(int m = 0;m < bucketCount[k];m++){
                        //数据存入原数组中
                        arr[index] = bucket[k][m];
                        index++;
                    }
                }
                //把元素放入原数组后,把当前桶的元素个数置为0;
                bucketCount[k] = 0;
            }
            System.out.println(""+(i+1)+"次排序:"+ Arrays.toString(arr));
        }
    }
}

E.输出:

技术图片

速度:

技术图片

 

数据结构和算法--6排序算法

标签:分治策略   记录   过程   flag   输出   ext   select   稳定性   amp   

原文地址:https://www.cnblogs.com/bai3535/p/12524100.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!