数据结构与算法(Java+Python实现):排序

https://blog.csdn.net/weixin_30337157/article/details/95953304
https://www.bilibili.com/video/BV1Cz411B7qd?p=17

排序算法的分类

按照不同的排序原则,可以分为以下几类
1)插入排序:直接插入排序希尔排序
2)交换排序:冒泡排序快速排序
3)选择排序:简单(直接)选择排序、树形选择排序、堆排序
4)归并排序
分类标准并不是绝对的,简单排序顾名思义就是比较简单的排序算法,是必须得掌握的

插入排序

  1. 直接插入排序
    就像打扑克牌的时候理手牌的方法
    将所有元素分为已排序的和未排序的两种,然后找到未排序中的第一个元素作为待排序元素
    倒叙遍历已排序元素,以此与待排序元素比较
    直到找到一个元素小于待排序元素,就把待排序元素放到该位置,其他元素向后移动一位
    在这里插入图片描述
    1)Java实现

    public class StraightInsertionSort {
        public static void main(String[] args){
            // 生成一个数组
            int[] numArray = new int[]{4,3,2,10,12,1,5,6};
            // 打印数组
            for(int k = 0; k<numArray.length;k++){
                System.out.println(numArray[k]);
            }
            // 开始排序
            StraightInsertionSort SIS = new StraightInsertionSort();
            SIS.Sort(numArray);
    
        }
    
        public void Sort(int[] a){
            // 排序方法主体
            int tmp = 0;	// 临时遍历,用于存待排序元素
            for(int i=1;i<a.length;i++){
                tmp = a[i];
                for(int j=i-1;j>=0;j--){	// 倒叙比较
                    if(a[j]>tmp){			// 如果前面的数大于待排序数
                        a[j+1] = a[j];
                        a[j] = tmp;
                    }
                    else{
                        break;   // 这个break是很有必要的
                    }
                }
            }
            // 输出排序后的序列
            System.out.println("///");
            for(int k = 0; k<a.length;k++){
                System.out.println(a[k]);
            }
        }
    }
    

    2)Python实现

    #!/usr/bin/python
    def StraightInsertionSort(a):
    	for i in range(1,len(a)):	# 位置i上的就是待排序元素
    		tmp=a[i]
    		for j in range(i-1,-1,-1):
    			if a[j]>tmp:
    				a[j+1]=a[j]
    				a[j]=tmp
    			else:
    				break
    				
    	print(a)
    StraightInsertionSort([4,3,2,10,12,1,5,6])
    

    3)算法分析
    考虑最坏情况,每一个待插入元素都要和前面的所有元素比较并交换位置
    所以比较的次数 = 交换的次数 = (N-1)+(N-2)+(N-3)+…+2+1 = N2/2-N/2
    总执行次数 = (N2/2-N/2)*2 = N2-N
    所以时间复杂度为O(N2)

  2. 希尔排序
    先按照增长量分组,然后对每一组进行简单插入排序
    如下图,h为增长量初始值为5,则9和4为一组,1和8为一组,以此类推进行简单插入排序
    然后减少增长量,直到增长量=1,就成为了简单插入排序了
    h的初始值和减少量一般设定为数组长度/2
    在这里插入图片描述
    1)Java实现

    public class ShellSort {
        public static void main(String[] args) {
            // 生成一个数组
            int[] numArray = new int[]{9, 1, 2, 5, 7, 4, 8, 6, 3};
            // 打印数组
            for (int k = 0; k < numArray.length; k++) {
                System.out.println(numArray[k]);
            }
            // 开始排序
            ShellSort SS = new ShellSort();
            SS.Sort(numArray);
    
        }
    
        public void Sort(int[] a) {
            for (int step = a.length / 2; step >= 1; step /= 2) {
                for (int i = 0; i < a.length; i++) {
                    for (int j = i; j >=step ; j -= step) {
                        if (a[j] < a[j-step]) {
                            int tmp = a[j-step];
                            a[j-step] = a[j];
                            a[j] = tmp;
                        } else break;
                    }
                }
            }
    
            // 输出排序后的序列
            System.out.println("///");
            for (int k = 0; k < a.length; k++) {
                System.out.println(a[k]);
            }
        }
    }
    

    2)Python实现

    def ShellSort(a):
    	# 初始步长
    	step = len(a)//2
    	while step > 0:
    		# 按步长进行插入排序
    		for i in range(step, len(a)):
    			for j in range(i-step,-1,0-step):
    				if a[j]>a[i]:
    					tmp = a[j]
    					a[j]=a[i]
    					a[i]=tmp
    				else:
    					break
    		step = step // 2
    	print(a)
    ShellSort([9, 1, 2, 5, 7, 4, 8, 6, 3])
    

3)算法分析
由于每次排序的增长量都不同,所以暂时只能使用事后分析统计方法来统计,这里就不赘述

交换排序

  1. 冒泡排序
    个人倾向于把冒泡排序称为“最大元素优先排序”
    意思就是每次大循环,都是将当时状态下最大的元素排好序
    在这里插入图片描述

    1)Java实现

    import java.util.Random;
    public class BubbleSort {
        public static void main(String[] args){
        	// 生成一个数组
            int[] numArray = new int[]{4,5,6,3,2,1};
            // 打印数组
            for(int k = 0; k<numArray.length;k++){
                System.out.println(numArray[k]);
            }
            // 开始排序
            BubbleSort BS = new BubbleSort();
            BS.Sort(numArray);
    
        }
        public void Sort(int[] a){
            for(int i=0;i<a.length;i++){
                for(int j=0;j<a.length-i-1;j++){
                    if(a[j]>a[j+1]){
                        int tmp = a[j];
                        a[j] = a[j+1];
                        a[j+1] = tmp;
                    }
                }
            }
            System.out.println("///");
            for(int k = 0; k<a.length;k++){
                System.out.println(a[k]);
            }
        }
    }
    

    2)Python实现

    def BubbleSort(a):
        for i in range(len(a)):
            for j in range(len(a)-i-1):
                if a[j]>a[j+1]:
                    tmp = a[j]
                    a[j] = a[j+1]
                    a[j+1] = tmp
        print(a)
    BubbleSort([4,5,6,3,2,1])
    

    3)算法分析
    冒泡排序使用了两层循环
    考虑最坏情况,每一个待插入元素都要和前面的所有元素比较并交换位置
    所以比较的次数 = 交换的次数 = (N-1)+(N-2)+(N-3)+…+2+1 = N2/2-N/2
    总执行次数 = (N2/2-N/2)*2 = N2-N
    所以时间复杂度为O(N2)

  2. 快速排序

    个人理解为“两头往中间找算法”
    在这里插入图片描述
    1)Java实现

    	public class QuickSort {
        public static void main(String[] args){
            // 生成一个数组
            int[] numArray = new int[]{6,1,2,7,9,3,4,5,8};
            // 开始排序
            Sort(numArray, 0, numArray.length-1);
            // 打印数组
            System.out.println("/");
            for(int k = 0; k<numArray.length;k++){
                System.out.println(numArray[k]);
            }
    
        }
        public static void Sort(int[] a,int low,int high){
            if(low>=high){//跳出递归的条件
                return;
            }
    
            int flag = a[low];
            int right = high;
            int left = low;
            while (left<right){
                while(flag<=a[right] && left<right){
                    right--;
                }
                while(flag>=a[left] && left<right){
                    left++;
                }
                if(left<right){
                    int tmp = a[right];
                    a[right] = a[left];
                    a[left] = tmp;
                }
            }
            a[low] = a[left];
            a[left] = flag;
            Sort(a,low,left-1);
            Sort(a,left+1,high);
        }
    
    }
    

    2)Python实现

        def QuickSort(a, low, high):
            if low >= high:
                return
            left = low
            right = high
            flag = a[low]
    
            while left < right:
                while flag <= a[right] and left < right:
                    right -= 1
                while flag >= a[left] and left < right:
                    left += 1
                if left < right:
                    tmp = a[left]
                    a[left] = a[right]
                    a[right] = tmp
            a[low] = a[left]
            a[left] = flag
    
            Sort.QuickSort(a, low, left - 1)
            Sort.QuickSort(a, left + 1, high)
    

    3)算法分析
    最好情况下,待排序序列本身就是有序的
    此时递归的次数t = log2n,所以时间复杂度T(n)=n*log2n
    最坏情况下,待排序序列是倒序的
    此时T(n)=n2

选择排序:简单(直接)选择排序

根据要排序的位置,来找到相对应大小的元素
以下图为例
首先排位置1的元素,就在后面的元素中找到最小的元素,与第一个元素交换位置
然后找排位置2的元素,就在后面的元素中找第二大的元素,与第二个元素交换位置
在这里插入图片描述
1)Java实现

public class SwapSort {
    public static void main(String[] args){
        // 生成一个数组
        int[] numArray = {6,1,2,7,9,3,4,5,8};
        // 开始排序
        Sort(numArray);
        // 打印数组
        System.out.println("/");
        for(int k = 0; k<numArray.length;k++){
            System.out.println(numArray[k]);
        }

    }
    public static void Sort(int[] a){
        for(int i = 0;i<a.length-1;i++){
             int min = i;
            for(int j=i+1;j<a.length-1;j++){
                if(a[j]<a[min]){
                    min = j;
                }
            }
            int tmp = a[i];
            a[i] = a[min];
            a[min] = tmp;
        }
    }
}

2)Python实现

    def SwapSort(a):
        for i in range(len(a)):
            min = i
            for j in range(min+1,len(a)):
                if a[min]>a[j]:
                    tmp = a[min]
                    a[min]=a[j]
                    a[j]=tmp

3)算法分析
算法中有两层循环,T(n)=n+n*(n-min-1) = O(n2)

归并排序

归并排序的想法其实和快速排序差不多,都是分组
区别就是分组依据不同
快速排序是依靠一个元素的值来分组,比该元素大的一组,比该元素小的一组,所以在分组之前要进行交换的操作
归并排序是考数组的位置来分组,比如下图就直接从中间一刀劈开,分成的两个组其实并没有大小关系
自己称之为“中间劈开后用三个指针一个临时数列归并排序法
在这里插入图片描述
合并时的操作如下图
在这里插入图片描述
在这里插入图片描述

1)Java实现

public class MergeSort {
    public static void main(String[] args){
        // 生成一个数组
        int[] numArray = {6,1,2,7,9,3,4,5,8};
        // 临时数组
        int[] tmpArray = new int[numArray.length];
        // 开始排序,分为两个部分,一个是分开的部分,一个是归并的部分
        Sort(numArray,0,numArray.length-1,tmpArray);
        // 打印数组
        System.out.println("/");
        for(int k = 0; k<numArray.length;k++){
            System.out.println(numArray[k]);
        }

    }
    public static void Sort(int[] a,int low,int high,int[] tmp){
        // 这个函数递归起到的作用其实就只是切分数组而已
        // 真正排序的函数时merge()
        if(low<high){
            int mid = (high+low)/2;
            Sort(a,low,mid,tmp);
            Sort(a,mid+1,high,tmp);
            merge(a,low,mid,high,tmp);
        }


    }
    public static void merge(int[] a,int low,int mid,int high,int[] tmp){
        // 排序且合并两个数组
        // 定义三个指针
        int i = low;
        int p1 = low;
        int p2 = mid+1;
        while (p1<=mid && p2<=high){
            if(a[p1]<a[p2]){
                tmp[i++] = a[p1++];
            }else {
                tmp[i++] = a[p2++];
            }
        }
        while (p1<=mid){
            // 当p1还没有遍历完时,把剩下的元素直接放入tmp中
            tmp[i++] = a[p1++];
        }
        while(p2<=high){
            tmp[i++] = a[p2++];
        }
        for(int index = low;index<=high;index++){
            a[index]= tmp[index];
        }

    }
}

2)Python实现

#!/usr/bin/env python
# -*- coding:utf-8 -*-

def Sort(a, low, high, tmp):
    if low < high:
        mid = (low+high) // 2
        Sort(a, low, mid, tmp)
        Sort(a, mid + 1, high, tmp)
        Merge(a, low, mid, high, tmp)


def Merge(a, low, mid, high, tmp):
    p = low
    pp = mid + 1
    ppp = low  # 指向临时数组的指针
    while p <= mid and pp <= high:
        if a[p] < a[pp]:
            tmp[ppp] = a[p]
            ppp = ppp + 1
            p = p + 1
        else:
            tmp[ppp] = a[pp]
            ppp = ppp + 1
            pp = pp + 1
    # 当p1没有遍历完时
    while p <= mid:
        tmp[ppp] = a[p]
        ppp = ppp + 1
        p = p + 1
    while pp <= high:
        tmp[ppp] = a[pp]
        ppp = ppp + 1
        pp = pp + 1
    # 将临时数组复制到原数组中
    for i in range(low, high+1):
        a[i] = tmp[i]


a = [6, 1, 2, 7, 9, 3, 4, 5, 8]
tmp = [0]*len(a)
Sort(a, 0, len(a) - 1, tmp)
print(a)

# input = input("Press <enter>")

3)算法分析
T(n)=n*(log2n)

排序的稳定性

  1. 稳定性的定义
    数组中有若干元素,其中A元素和B元素相等,并且A元素在B元素前面
    如果使用某种排序算法之后,能保证A元素依然在B元素前面,则称该算法是稳定的
  2. 稳定性的意义
    当一组数据需要多次排序的时候,稳定性很有必要
    比如要排序的内容是一组商品对象,第一次按照价格排序,第二次按照销量排序
    如果使用的排序算法是具有稳定性的,就可以使得相同销量的对象依旧保持着价格高低的顺序展现
    只有销量不同的才需要重新排序,减少系统开销
  3. 常见算法的稳定性
    直接插入排序:最稳定的
    希尔排序:最不稳定的
    冒泡排序:稳定的
    快速排序:不稳定
    直接选择排序:不稳定
    归并排序:稳定
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值