[剑指offer]十大排序算法

接前文七大搜索算法,这次对排序算法进行总结。

复杂度

复杂度

1.冒泡排序

相邻两元素比较并交换位置,走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素列已经排序完成。
冒泡排序

Java实现

public class BubbleSort {
    public static int[] Sort(int[] l){
        int temp;
        for(int i=0;i<l.length-1;i++){
            for (int j=0;j<l.length-1-i;j++){
                if(l[j]>l[j+1]){
                    temp=l[j];
                    l[j]=l[j+1];
                    l[j+1]=temp;
                }
            }
        }
        return l;
    }

    public static void main(String[] args) {
        int[] l=new int[]{4654,47864,1565,7132,3,5,7,6};
        int[] sort = BubbleSort.Sort(l);
        for (int i :
                sort) {
            System.out.println(i);
        }
    }
}

2.选择排序

每次从未排序的元素中选出最值,放到已排序元素的末尾。
选择排序

Java实现

public class SelectionSort {
    public static int[] Sort(int[ ] l){
        int temp;
        int index ;
        for(int i=0;i<l.length-1;i++){
            index=i;
            for(int j=i+1;j<l.length;j++){
                if(l[index]>l[j]){
                    index=j;
                }
            }
            temp=l[i];
            l[i]=l[index];
            l[index]=temp;
        }
        return l;
    }

    public static void main(String[] args) {
        int[] l=new int[]{4654,47864,1565,7132,3,5,7,6};
        int[] sort = SelectionSort.Sort(l);
        for (int i :
                sort) {
            System.out.println(i);
        }
    }
}

3.插入排序

插入排序是一种最简单的排序方法,它的基本思想是将一个记录插入到已经排好序的有序表中,从而一个新的、记录数增1的有序表。
在这里插入图片描述

Java实现

public class InsertionSort {
    public static int[] Sort(int[] l){
        for(int i=0;i< l.length-1;i++){
            int temp=l[i+1];
            int j=i+1;
            while (j>0&&temp<l[j-1]){
                l[j]=l[j-1];
                j--;
            }
            l[j]=temp;
        }
        return l;
    }

    public static void main(String[] args) {
        int[] l=new int[]{4654,47864,1565,7132,3,5,7,6};
        int[] sort = InsertionSort.Sort(l);
        for (int i :
                sort) {
            System.out.println(i);
        }
    }
}

4.希尔排序

希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至 1 时,整个文件恰被分成一组,算法便终止。
在这里插入图片描述

Java实现

public class ShellSort {
    public static int[] Sort(int [] l){
        int step=l.length/2;
        while (step >= 1){
            for (int i = step; i < l.length; i++) {
                int val = l[i];
                int j = i - step;
                for (; j >= 0; j -= step){
                    if (l[j] > val){
                        l[j + step] = l[j];
                    }
                    else {
                        break;
                    }
                }
                l[j + step] = val;
            }
            step = step / 2;

        }
        return l;
    }

    public static void main(String[] args) {
        int[] l = new int[]{4654, 47864, 1565, 7132, 3, 5, 7, 6};
        int[] sort = ShellSort.Sort(l);
        for (int i :
                sort) {
            System.out.println(i);
        }
    }
}

5.归并排序

归并排序(Merge Sort)是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。
在这里插入图片描述

Java实现

public class MergeSort {
    public static int[] Sort(int[] arr){

        int []temp = new int[arr.length];//在排序前,先建好一个长度等于原数组长度的临时数组,避免递归中频繁开辟空间
        sort(arr,0,arr.length-1,temp);
        return arr;
    }

    private static void sort(int[] arr,int left,int right,int []temp){
        if(left<right){
            int mid = (left+right)/2;
            sort(arr,left,mid,temp);//左边归并排序,使得左子序列有序
            sort(arr,mid+1,right,temp);//右边归并排序,使得右子序列有序
            merge(arr,left,mid,right,temp);//将两个有序子数组合并操作
        }
    }

    private static void merge(int[] arr,int left,int mid,int right,int[] temp){
        int i = left;//左序列指针
        int j = mid+1;//右序列指针
        int t = 0;//临时数组指针
        while (i<=mid && j<=right){
            if(arr[i]<=arr[j]){
                temp[t++] = arr[i++];
            }else {
                temp[t++] = arr[j++];
            }
        }
        while(i<=mid){//将左边剩余元素填充进temp中
            temp[t++] = arr[i++];
        }
        while(j<=right){//将右序列剩余元素填充进temp中
            temp[t++] = arr[j++];
        }
        t = 0;
        //将temp中的元素全部拷贝到原数组中
        while(left <= right){
            arr[left++] = temp[t++];
        }
    }

    public static void main(String[] args) {
        int[] l = new int[]{4654, 47864, 1565, 7132, 3, 5, 7, 6};
        int[] sort = MergeSort.Sort(l);
        for (int i :
                sort) {
            System.out.println(i);
        }
    }
}

6.快速排序

基本思想

快速排序算法通过多次比较和交换来实现排序,其排序流程如下:
(1)首先设定一个分界值,通过该分界值将数组分成左右两部分。
(2)将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。
(3)然后,左边和右边的数据可以独立排序。
(4)重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。
在这里插入图片描述

public class QuickSort {
    public static int[] Sort(int arr[],int start,int end) {
        int pivot = arr[start];
        int i = start;
        int j = end;
        while (i<j) {
            while ((i<j)&&(arr[j]>pivot)) {
                j--;
            }
            while ((i<j)&&(arr[i]<pivot)) {
                i++;
            }
            if ((arr[i]==arr[j])&&(i<j)) { //这个判断是为了防止重复元素陷入死循环
                i++;
            } else {
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
        if (i-1>start) arr=Sort(arr,start,i-1);
        if (j+1<end) arr=Sort(arr,j+1,end);
        return (arr);
    }

    public static void main(String[] args) {
        int[] l = new int[]{4654, 6, 1565, 7132, 3, 5, 7, 6};
        int[] sort = QuickSort.Sort(l,0,7);
        for (int i :
                sort) {
            System.out.println(i);
        }
    }
}

7.堆排序

基本思想

(1)将无序数组建为最大堆
(2)将堆顶元素与最后一个元素交换
(3)将堆大小减一,并使剩余元素仍构成最大堆
(4)重复以上操作
在这里插入图片描述

Java实现

public class HeapSort {
    private static void heapify(int[] l,int n,int i){
        int largest=i;
        int lson=i*2+1;
        int rson=i*2+2;
        if(lson<n&&l[lson]>l[largest]){
            largest=lson;
        }
        if(rson<n&&l[rson]>l[largest]){
            largest=rson;
        }
        if(largest!=i){
            int temp;
            temp=l[largest];
            l[largest]=l[i];
            l[i]=temp;
            heapify(l,n,largest);
        }
    }


    private static void Sort(int[] l,int n){
        //建堆
        for (int i = n/2-1; i >=0 ; i--) {
            heapify(l,10,i);
        }
        //排序
        for (int i = n-1; i >0 ; i--) {
            int temp;
            temp=l[i];
            l[i]=l[0];
            l[0]=temp;
            heapify(l,i,0);
        }
    }

    public static void main(String[] args) {
        int[] l={2,3,8,1,4,9,10,7,16,14};
        Sort(l,10);
        for (int i : l) {
            System.out.println(i);
        }
    }
}

8.计数排序

基本思想

(1)找出待排序的数组中最大和最小的元素
(2)统计数组中每个值为i的元素出现的次数,存入数组C的第i项
(3)对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加)
(4)反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1
在这里插入图片描述

Java实现

public class CountingSort {
    public static int[] Sort(int[] l){
        int min=l[0];
        int max=l[0];
        for (int i = 1; i < l.length; i++) {
            if(min>l[i]){
                min=l[i];
            }
            if(max<l[i]){
                max=l[i];
            }
        }
        int K=max-min+1;
        int[] Aux=new int[K];
        for (int i = 0; i < K; i++) {
            Aux[i]=0;
        }
        for (int i = 0; i < l.length; i++) {
            Aux[l[i]-min]++;
        }
        int i=0;
        for (int j = 0; j < K; j++) {
            while(Aux[j]>0){
                l[i++]=min;
                Aux[j]--;
            }
            min++;
        }
        return l;
    }

    public static void main(String[] args) {
        int[] l={2,3,8,1,4,9,10,7,16,14};
        Sort(l);
        for (int i : l) {
            System.out.println(i);
        }
    }
}

9.基数排序

基本思想

直接看图很好理解。基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。
在这里插入图片描述

Java实现

public class RadixSort {
    public static int[] Sort(int[] l){

        int max=l[0];
        for (int i = 0; i < l.length; i++) {
            if(max<l[i]){
                max=l[i];
            }
        }
        for (int i=1; max/i>0 ;i*=10) {
            int[] count=new int[10];
            int[] templ=new int[l.length];
            for (int j = 0; j < l.length; j++) {
                int num=(l[j]/i)%10;
                count[num]++;
            }
            for (int j = 1; j < 10; j++) {
                count[j]+=count[j-1];
            }
            for (int j = l.length-1; j >=0 ; j--) {
                templ[count[(l[j]/i)%10]-1]=l[j];
                count[(l[j]/i)%10]--;
            }
            System.arraycopy(templ, 0, l, 0, l.length);
        }
        return l;
    }

    public static void main(String[] args) {
        int[] l=new int[]{4654,47864,1565,7132,3,5,7,6};
        Sort(l);
        System.out.println(Arrays.toString(l));
    }
}

10.桶排序

基本思想

实际上计数和基数排序都是运用了桶排序的思想。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。为了使桶排序更加高效,我们需要做到这两点:

(1)在额外空间充足的情况下,尽量增大桶的数量
(2)使用的映射函数能够将输入的 N 个数据均匀的分配到 K 个桶中
同时,对于桶中元素的排序,选择何种比较排序算法对于性能的影响至关重要。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值