排序算法相关知识总结

8 篇文章 0 订阅
2 篇文章 0 订阅

冒泡排序

1.比较相邻两个元素,如果第一个比第二个大,就交换他们两个;
2.对每一对相邻元素作同样的工作,从开始第一对到结尾最后一对,这样在最后的元素就会是最大的数;
3.重复以上步骤,直到排序完成.

import java.util.Arrays;

public class bubbleSort {
    public static void main(String[] args) {
        Integer[] arr=new Integer[]{4,2,7,1,8,23,4,15,62,1};
        sort(arr);
        System.out.println(Arrays.toString(arr));
    }

    public static <T extends Comparable<T>>void sort(T [] arr){
        if (arr.length==0){
            return;
        }
        for (int i=0;i<arr.length;i++){
            boolean flag=true;//标记是否进行了交换,未交换为true
            for (int j=0;j<arr.length-i-1;j++){
                if (arr[j].compareTo(arr[j+1])>0){
                    //比较当前下标元素与下一下标元素大小,弱小于下一下标元素则交换
                    swap(arr,j,j+1);
                    flag=false;//发生了交换,标识变为false
                }
            }
            if(flag){//flag为true时没有发生交换,判断为排序结束
                break;
            }
        }
    }
    public static <T>void swap(T [] arr,int index1,int index2){
        T temp=arr[index1];
        arr[index1]=arr[index2];
        arr[index2]=temp;
    }
}

冒泡排序的特性

平均时间复杂度:O(n^2)
平均空间复杂度:O(1)
稳定性:稳定

基数排序

适用于给数值型数据进行排序

1.从低位/高位开始将待排序的数按照这一位的值放到相应的编号为0~9的桶中;
2.等到低位排完得到一个子序列,再将这个序列按照次低位的大小进入相应的桶中;
3.一直排到最高位为止,数组排序完成。
个位数如下:
在这里插入图片描述
十位数如下:
在这里插入图片描述

import java.util.Arrays;
import java.util.Vector;

public class LSDSort {
    public static void main(String[] args) {
        int[] arr={14, 21, 12, 31, 4, 12, 4, 57};
        LSDSort(arr);
        System.out.println(Arrays.toString(arr));
    }
    public static void LSDSort(int a[]) {
        int max = a[0];
        for (int i = 1; i < a.length; i++) {
            if (a[i] > max)
                max = a[i];
        }
        int len = 0; // 存贮最大的数的位数,用来判断需要进行几轮基数排序
        while (max > 0) {
            max = max / 10;
            len++;
        }

        for (int pos = 0; pos < len; pos++) // 按位数运行几次,每次都分裂成10份,在顺序链接
        {
            // 以下内容应为每次运行时,分割成0-9 个桶,然后顺序链接
            @SuppressWarnings("unchecked")
            Vector<Integer> num[] = new Vector[10];
            for (int i = 0; i < num.length; i++) {
                num[i] = new Vector<Integer>();
            }

            int gap = 1; // 用来取出当前的对应的位数的数
            for (int i = 0; i < pos; i++) {
                gap = gap * 10;
            }

            for (int i = 0; i < a.length; i++) // 对每一个数进行判断位数
            {
                int x = 0; // 用来表示当前的位数上的数的大小
                x = a[i] / gap;
                x = x % 10;
                num[x].add((Integer)a[i]);
            }
            // 将排序的结果顺序连接起来
            int count = 0;
            for (int i = 0; i < num.length; i++) {
                for (int j = 0; j < num[i].size(); j++) {
                    a[count++] = (int)num[i].get(j);
                }
            }
        }
    }
}

基数排序的特性

平均时间复杂度:O(d(n+r))

r表示基数,d表示位数

平均空间复杂度:O(n+r)
稳定性:稳定

选择排序

1.首先在未排序的序列中找到最小/最大的元素,存放在排序序列的起始/末尾位置;
2.然后再从剩余的元素中继续寻找最小/最大的元素,和已排序好的队列末尾/队头进行交换,
3.循环以上步骤,直到所有的元素都排序完毕。

import java.util.Arrays;

public class selectSort {
    public static void main(String[] args) {
        Integer [] arr={5,4,12,75,6,1,5,69,42,3};
        sort(arr);
        System.out.println(Arrays.toString(arr));
    }
    public static  <T extends Comparable<T>> void sort(T [] arr){
        if (arr.length==0)  return;
        int minIndex=0;//标记最小值的下标
        for (int i=0;i<arr.length;i++){
            minIndex=i;
            for(int j=i+1;j<arr.length;j++){
                if (arr[minIndex].compareTo(arr[j])>0){
                    //获取本次循环最小值的下标
                    minIndex=j;
                }
            }
            swap(arr,minIndex,i);//将当前最小值放在拍好序的队列后
        }
    }
    public static <T> void swap(T [] arr,int index1,int index2){
        T temp=arr[index1];
        arr[index1]=arr[index2];
        arr[index2]=temp;
    }

}

选择排序的特性

平均时间复杂度:O(n^2)
平均空间复杂度:O(1)
稳定性:不稳定

插入排序

import java.util.Arrays;
public class insertSort {
    public static void main(String args[])
    {
        Integer arr[] = {12, 11, 5, 13, 34, 5, 6, 56, 14};
        sort(arr);
        System.out.println(Arrays.toString(arr));
    }
    public static<T extends Comparable<T>> void sort(T arr[])
    {
        for (int i=1; i<arr.length; i++)
        {
            T temp = arr[i];
            int j = i-1;

            while (j>=0 && arr[j].compareTo(temp)>0)
            //拿获取到的当前下标的值去拍好序的队列里找到对应的位置,进行插入
            {
                arr[j+1] = arr[j];//第一次循环j+1即i对应位置
                j = j-1;
            }
            arr[j+1] = temp;
        }
    }
}

图片来自GeeksForGeeks
*

图片来源于GeeksForGeeks

插入算法的特性

平均时间复杂度:O(n^2)
平均空间复杂度:O(1)
稳定性: 稳定

折半插入排序

折半插入排序即在将数据插入排序好的数据队列中时,采用二分的方式查找对应位置,这里不做代码展示。

希尔排序

选择增量(数组长度/2)进行分组;缩小增量继续以增量/2 的方式进行分组。{n/2,(n/2)/2,(n/2)/4,…,1}增量序列。

1.选择一个增量序列,按照增量序列个数 m,进行 m 趟排序。
2.每趟排序根据对应的增量次数分别进行元素的分组操作,对组内进行直接插入排序操作。
3.继续下一个增量,分别进行分组直接插入操作。
4.重复第三个步骤,直到增量变成 1,所有元素在一个分组内,希尔排序结束。
在这里插入图片描述

import java.util.Arrays;

public class shellSort {
    public static void main(String[] args) {
        Integer[] arr = {12, 4, 65, 13, 7, 4, 15, 16, 23};
        shell(arr.length, arr);
        System.out.println(Arrays.toString(arr));
    }
    public static <T extends Comparable<T>> void shell(int partition, T[] arr) {
        if (arr.length==0)  return;
        for (int i = partition / 2; i > 0; i /= 2) {
            sort(arr, i);
        }
    }
    public static <T extends Comparable<T>> void sort(T[] arr, int gap) {
        int i = gap, j = 0;//j表示分组下的前一个下标,i表示下一个下标
        for (;i < arr.length; i++) {
            T temp = arr[i];//记录当前i下标的元素,方便交换
            for (j = i - gap; j >= 0; j -= gap) {
                if (temp.compareTo(arr[j]) < 0) {//当i下标元素比j下标元素小时,进行交换(升序)
                    arr[j + gap] = arr[j];//j+gap表示该分组下当前j下标的下一位元素
                } else {
                    break;//如果满足条件,说明该组元素已排好序了,跳出循环
                }
            }
            arr[j + gap] = temp;//最后一次循环后j-gap,当前j+gap为最后一次循环时的j
        }
    }
}

希尔排序的特性

时间复杂度:O(n^1.3~2)
平均空间复杂度: O(1)
稳定性分析: 不稳定

归并排序

1.开始以间隔为 1 的进行归并,即第一个元素跟第二个进行归并,第三个与第四个进行归并;
2. 然后,再以间隔为 2 的进行归并,1-4 进行归并,5-8 进行归并;
3. 再以 22 的间隔,同理,直到 2k 超过数组长度为止。
4. 当不够两组进行归并时,如果超过 k 个元素,仍然进行归并;如果剩余元素不超过 k 个元素,那么直接复制给中间数组。
在这里插入图片描述

import java.util.Arrays;

public class mergeSort {
    public static void main(String[] args) {
        Integer [] arr={12,4,2,15,35,37,4,7,12,23,42,1,62,1,3};
        merge(arr);
        System.out.println(Arrays.toString(arr));
    }
    public static <T extends Comparable<T>> void merge(T [] arr){
        if (arr.length==0)  return;
        for(int i=1;i<arr.length;i*=2){//从1开始分归并段,再逐次乘2作为归并段的跨度
            sort(arr,i);
        }
    }
    public static <T extends Comparable<T>> void sort(T [] arr,int len){
        //找出前后两个归并段的开头和末尾,进行两两归并排序
        int low1=0,high1=low1+len-1;
        int low2=high1+1;
        int high2=low2+len-1>arr.length-1?arr.length-1:low2+len-1;
        T[] brr=(T[])new Comparable[arr.length];   //创建中间数组
        int i=0;
        while(low2<arr.length){//确保有两个归并段
            while(low1<=high1&&low2<=high2){//确保归并段有数据
                if(arr[low1].compareTo(arr[low2])>0){//谁小先放谁
                    brr[i++]=arr[low2++];
                }else{//相等的情况先放前面的数据,确保稳定性
                    brr[i++]=arr[low1++];
                }
            }
            while(low1<=high1){//将第一段剩余数据直接存放
                brr[i++]=arr[low1++];
            }
            while(low2<=high2){//将第二段剩余数据直接存放
                brr[i++]=arr[low2++];
            }
            //将归并段下标后移,开始新的相邻归并段排序
            low1=high2+1;
            high1=low1+len-1;
            low2=high1+1;
            high2=low2+len-1>arr.length-1?arr.length-1:low2+len-1;
        }
        while(low1<arr.length){//如果不满足两个归并段,直接拷贝数据
            brr[i++]=arr[low1++];
        }
        for(i=0;i<arr.length;i++){//将排好序的数据替换原有数据
            arr[i]=brr[i];
        }
        brr=null;//将中间数组置空
    }
}

归并排序的特性

平均时间复杂度:O(nlogn)
平均空间复杂度:O(n)
稳定性:稳定

堆排序

1.先将初始数组建成一个大根堆,此堆为初始的无序;
2.再将关键字最大的记录 R1和无序区的最后一个记录 R[n]交换,由此得到新的无序区 R[1…n-1]和有 序区 R[n]。由于交换后新的根 R[1]可能违反堆性质,故应将当前无序区 R[1…n-1]调整为堆。然后再次将 R[1…n-1]中关键字最大的记录 R[1]和该区间的最后一个记录 R[n-1]交换,由此得到新的无序区 R[1…n-2]和有 序区 R[n-1…n],同样要将 R[1…n-2]调整为堆。
3.直到无序区只有一个元素为止。

import java.util.Arrays;

public class heapSort {
    public static void main(String[] args) {
        Integer [] arr={12,4,2,15,35,37,4,7,12};
        heapSort(arr);
        System.out.println(Arrays.toString(arr));
    }
    public static <T extends Comparable<T>>void heapSort(T[] arr){
        int i=0;
        int len=arr.length-1;
        for(i=(len-1)/2;i>=0;i--){//i 代表要调整根节点的下标
            adjust(arr, i, len);//最大堆建立好了
        }
        int temp=0;
        for(i=0;i<arr.length;i++){
            //0 下标 根保存最大值
            // arr[0]和堆中相对的"最后"元素进行交换
            swap(arr,0,len-i);
            adjust(arr, 0, len-i-1);
        }
    }
    private static <T>void swap(T[] arr,int index1,int index2){
        T temp = arr[index1];
        arr[index1] = arr[index2];
        arr[index2] = temp;
    }
    private static <T extends Comparable<T>>void adjust(T[] arr,int start,int end){
        T temp=arr[start];
        for(int i=2*start+1;i<=end;i=2*i+1){
            if(i+1<=end && arr[i].compareTo(arr[i+1]) < 0){
                i++;//i 指向两个子节点中较大的值
            }
            if(temp.compareTo(arr[i]) < 0){
                arr[start]=arr[i];
                start=i;
            }
            else{
                break;
            }
        }
        arr[start]=temp;
    }
}

堆排序的特性

平均时间复杂度:O(nlogn)
平均空间复杂度:O(1)
稳定性:不稳定

快速排序

1.选择基准:在待排序列中,按照某种方式挑出一个元素,作为 “基准”(pivot) ;
2.分割操作:以该基准在序列中的实际位置,把序列分成两个子序列。此时,在基准左边的元素都比该基准小,在基准右边 的元素都比基准大 ;
3.递归地对两个序列进行快速排序,直到序列为空或者只有一个元素。

public class quickSort{
    public static void main(String[] args) {
        Integer[]arr=new Integer[]{1,2,12,57,1,3,35,4,21};
        sort(arr,0,arr.length-1);
        System.out.println(Arrays.toString(arr));
    }
    public static <T extends Comparable<T>> void sort(T[] arr,int left,int right){
       int part=swap(arr,left,right);
       //分治策略解题,基准左侧,右侧分别进行快速排序
       if(left+1<part)
           sort(arr,left,part-1);
       if(part+1<right)
           sort(arr,part+1,right);
    }
    public static <T extends Comparable<T>> int swap(T[] arr,int left,int right) {
        T temp = arr[left];
        while (left < right) {
            while (left < right && arr[right].compareTo(temp) > 0)//找到比基准小的元素下标
                right--;
            if (left == right)//遍历完了,跳出循环
                break;
            else{//否则进行交换
                arr[left]=arr[right];
            }
            while(left<right&&arr[left].compareTo(temp)<=0){//找到比基准大的下标
                left++;
            }
            if(left==right) 
                break;
            else{
                arr[right]=arr[left];
            }
        }
        arr[left]=temp;
        return left;
    }
}

快速排序的特性

平均时间复杂度:O(nlogn)
平均空间复杂度:O(1)
稳定性:不稳定

快速排序的优化

基准的选择
方法一:固定位置
选择第一位或者最后一位作为基准

方法二:随机选取基准

方法三:三数取中
一般的做法是使用,左端,右端,中心的三个数,取其中的中值作为基准。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值