排序算法:冒泡、选择、插入

经典排序算法

  • 一张图概括十大经典排序算法:
    在这里插入图片描述

个人理解每种排序算法应该掌握的几点

  • 1. 实现思路

  • 2. 会写代码:

  • 3. 时间复杂度

    • (1)时间频度 :一个算法执行所耗费的时间,从理论上是不能算出来的,必须上机运行测试才能知道。但我们不可能也没有必要对每个算法都上机测试,只需知道哪个算法花费的时间多,哪个算法花费的时间少就可以了。并且一个算法花费的时间与算法中语句的执行次数成正比例,哪个算法中语句执行次数多,它花费时间就多。一个算法中的语句执行次数称为语句频度或时间频度。记为T(n)。
    • (2)时间复杂度 在刚才提到的时间频度中,n称为问题的规模,当n不断变化时,时间频度T(n)也会不断变化。但有时我们想知道它变化时呈现什么规律。为此,我们引入时间复杂度概念。 一般情况下,算法中基本操作重复执行的次数是问题规模n的某个函数,用T(n)表示,若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f(n)的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数。记作T(n)=O(f(n)),称O(f(n)) 为算法的渐进时间复杂度,简称时间复杂度。
    • 简单理解时间复杂度:就是算法中语句执行的次数。
        1. 算法中语句执行次数为一个常数,即时间频度 T(n) = [常数],则时间复杂度为 O(1)。
        2. 对于时间频度 T(n) = 2n+10 ,T(n)=n+12,则时间复杂度为O(n)
        3. 对于时间频度 T(n)=n^2+3n+4 与 T(n)=4n2+2n+1,则时间复杂度为O(n2)
  • 4. 空间复杂度:空间复杂度是指算法在计算机内执行时所需存储空间的度量。在排序算法中,则是指为了实现排序所需要的临时开辟的空间数量。

    • 空间复杂度 O ( 1 ) O(1) O(1):如果算法执行所需要的临时空间不随着某个变量n的大小而变化,即此算法空间复杂度为一个常量,可表示为 O(1)
    • 空间复杂度 O ( n ) O(n) O(n):这段代码中,第一行new了一个数组出来,这个数据占用的大小为n,这段代码的2-6行,虽然有循环,但没有再分配新的空间,因此,这段代码的空间复杂度主要看第一行即可,即 S(n) = O(n)
    • int[] m = new int[n]
      for(i=1; i<=n; ++i)
      {
         j = i;
         j++;
      }
      
  • 5. 稳定性:考察排序算法的时候有一个很重要的特性,就是算法的稳定性——假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,ri=rj,且ri在rj之前,而在排序后的序列中,ri仍在rj之前,则称这种排序算法是稳定的;否则称为不稳定的。

1.冒泡排序

  • 实现思路

    • 比较相邻的元素。如果第一个比第二个大,就交换它们两个;
      对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
      针对所有的元素重复以上的步骤,除了最后一个;
      重复步骤1~3,直到排序完成。
      
  • 示例:设想被排序的数组R[1…N]垂直竖立,将每个数据元素看作有重量的气泡,根据轻气泡不能在重气泡之下的原则,从下往上扫描数组R,凡扫描到违反本原则的轻气泡,就使其向上"漂浮",如此反复进行,直至最后任何两个气泡都是轻者在上,重者在下为止。

    • 49 13 13 13 13 13 13 13
      
      38 49 27 27 27 27 27 27
      
      65 38 49 38 38 38 38 38
      
      97 65 38 49 49 49 49 49
      
      76 97 65 49 49 49 49 49
      
      13 76 97 65 65 65 65 65
      
      27 27 76 97 76 76 76 76
      
      49 49 49 76 97 97 97 97
      
  • 图片理解:
    在这里插入图片描述

  • Java代码实现:

    public class BubbleSort {
        public static void BubbleSort(int[] arr) {
            int temp;//定义一个临时变量
            for(int i=0;i<arr.length-1;i++){//冒泡趟数   
                for(int j=0;j<arr.length-i-1;j++){      
                    if(arr[j+1]<arr[j]){                
                        temp = arr[j];
                        arr[j] = arr[j+1];
                        arr[j+1] = temp;
                    }
                }
            }
        }
        
        public static void main(String[] args) {
            int arr[] = new int[]{1,6,2,2,5};
            BubbleSort.BubbleSort(arr);
            System.out.println(Arrays.toString(arr));
        }
    }
    
  • 时间复杂度:假设有n个数据,寻找比较的次数

    • 最好情况:O(n)

      2 3 4 5 6 7 8 9   n-1
      

      冒泡排序的优化:

      public static void BubbleSort(int[] arr) {
              int temp;//定义一个临时变量
              boolean flag = false;
              for(int i=0;i<arr.length-1;i++){//冒泡趟数   //n-1
                  for(int j=0;j<arr.length-i-1;j++){      //n-2,n-3...,1=(n-2)n/2
                      if(arr[j+1]<arr[j]){
                          temp = arr[j];
                          arr[j] = arr[j+1];
                          arr[j+1] = temp;
                          flag = true;
                      }
                  }
                  if(!flag) {
                      break;
                  }
              }
          }
      
    • 最坏情况:O(n^2)

      9 8 7 6 5 4 3 2 1    n=9
      开始交换:
      8 7 6 5 4 3 2 1 [9]  n-1 = 8
      7 6 5 4 3 2 1 [8 9]  n-2 = 7
      。
      。
      。
      2 1 [3 4 5 6 7 8 9]   2
      1 [2 3 4 5 6 7 8 9]   1
      比较次数:((n-1+1)*n)/2 = n^2 / 2
      
    • 平均时间复杂度:O(n^2)

  • 空间复杂度: O(1)

  • 稳定性:稳定

2.选择排序

  • 实现思路:

    • 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
      再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
      重复第二步,直到所有元素均排序完毕。
      
  • 示例:

        初始关键字 [49 38 65 97 76 13 27 49]
    
        第一趟排序后 13 [38 65 97 76 49 27 49]
    
        第二趟排序后 13 27 [65 97 76 49 38 49]
    
        第三趟排序后 13 27 38 [97 76 49 65 49]
    
        第四趟排序后 13 27 38 49 [49 97 65 76]
    
        第五趟排序后 13 27 38 49 49 [97 97 76]
    
        第六趟排序后 13 27 38 49 49 76 [76 97]
    
        第七趟排序后 13 27 38 49 49 76 76 [ 97]
    
    最后排序结果 13 27 38 49 49 76 76 97
    
  • 图片理解:

在这里插入图片描述

  • Java代码实现:

    public class Selection
    {
    	public static void main(String[] args)
    	{
    		int[] ins = {2,3,5,1,23,6,78,34};
    		int[] ins2 = sort(ins);
    		for(int in: ins2){
    			System.out.println(in);
    		}
    	}
    	
    	public static int[] sort(int[] ins){
    		int n = ins.length-1;//经过n-1次提取最小最大值
    		
    		for(int i=0; i<n; i++){//控制选择的次数
    			int min_index = i;
    			
    			for(int j=i+1; j<n; j++){ //取最小值
    				if(ins[j]<ins[i]){
    					min_index = j;  
    				}
    			}
    			if(min_index != i){  //交换位置
    				int temp = ins[i];
    				ins[i] = ins[min_index];
    				ins[min_index] = temp;
    			}
    		}
    		return ins;
    	}
    }
    
  • 时间复杂度:

    • 最好情况:O(n^2)

    • 最坏情况:O(n^2)

    • 平均时间复杂度:O(n^2)

      9 8 7 6 5 4 3 2 1 n=9
      
      [1] 8 7 6 5 4 3 2 9  n-1=8
      [1 2] 7 6 5 4 3 8 9  n-2=7
      ...
      [1 2 3 4 5 6 7] 8 9  2
      [1 2 3 4 5 6 7 8] 9  1
      
      比较次数:
      
  • 稳定性:由于选择排序的方式是选择出最小的元素然后再交换,所以在交换的过程中,一个较小的元素位于两个较大的相同元素后面时,那两个相同元素中位于前面的那一个就会被交换到后面去,这时原数组的顺序就会被打乱,所以选择排序是一种不稳定排序

    1 12 12 4 5 6 7 8
    
    第一趟: 1 12 12 3 4 5 6 7 8
    第二趟: 1 3 12 12 4 5 6 7 8
    

3.插入排序

  • 实现思路:

    1.将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。
    
    2.从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)
    
  • 示例:

    每次将一个待排序的数据元素,插入到前面已经排好序的数列中的适当位置,使数列依然有序;直到待排序数据元素全部插入完为止。
    
    [初始关键字] [49] 38 65 97 76 13 27 49
    
         J=2(38) [38 49] 65 97 76 13 27 49
    
         J=3(65) [38 49 65] 97 76 13 27 49
    
         J=4(97) [38 49 65 97] 76 13 27 49
    
         J=5(76) [38 49 65 76 97] 13 27 49
    
         J=6(13) [13 38 49 65 76 97] 27 49
    
         J=7(27) [13 27 38 49 65 76 97] 49
    
         J=8(49) [13 27 38 49 49 65 76 97]
    

在这里插入图片描述

  • Java代码实现:

    package work;
    
    import java.sql.Array;
    import java.util.Arrays;
    
    public class Test {
    
        public static void main(String[] args) {
            int [] a = {1,23,12,12,22,31,12,25};
            insertionSort(a,a.length);
            System.out.println(Arrays.toString(a));
        }
    
        // 插入排序,a表示数组,n表示数组大小
        public static void insertionSort(int[] a, int n) {
            if (n <= 1) return;
    
            for (int i = 1; i < n; ++i) {
                int value = a[i];
                int j = i - 1;
                // 查找插入的位置
                for (; j >= 0; --j) {
                    if (a[j] > value) {
                        a[j+1] = a[j];  // 数据移动
                    } else {
                        break;
                    }
                }
                a[j+1] = value; // 插入数据
            }
        }
    }
    
    
  • 时间复杂度:

    • 最好情况:O(n)

      [13 27 38 49 49 65 76 97]  n-1
      
    • 最坏情况:O(n^2)

      [97 87 76 65 54 43 32 21]
      
      第一趟:1
      第二趟:2
      ...
      第n-1趟:n-1
      
      比较次数:n^2/2
      
    • 平均时间复杂度:O(n^2)

  • 稳定性:稳定

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值