算法笔记(二) 排序之冒泡排序和快速排序

冒泡排序

思路

1.循环获取列表每一个元素

2.将该元素与其它元素比较交换,筛选出最大元素

代码

java版本

/**
 * Created by lilongsheng on 2017/6/20.
 */
public class BubbleSort {
    public static void main(String[] args) {
        int[] score = {11, 64, 33, 79, 55, 66, 77, 23};
        bubbleSort(score);
    }

    public static void bubbleSort(int[] score) {
        //外层循环n-1次
        for (int i = 1; i < score.length; i++) {
            StringBuilder sb = new StringBuilder();
            int temp = 0;
            for (int j = 0; j < score.length - i; j++) {
                sb.append(" O ");
                if (score[j] > score[j + 1]) {
                    temp = score[j + 1];
                    score[j + 1] = score[j];
                    score[j] = temp;
                }
            }
            System.out.println(sb.append(" ").append(score[score.length-i]));
        }
        for (int a = 0; a < score.length; a++) {
            System.out.print(score[a] + "\t");
        }
    }
}

效果如下:
这里写图片描述

python版本


  1 def bubble_sort(scores):
  2         for i in range(len(scores)-1,-1,-1):
  3                 for j in range(i):
  4                         if (scores[j] > scores[j+1] ):
  5                                 scores[j+1],scores[j] = scores[j],scores[j+1]
  6 
  7         for m in scores:
  8                 print(m)

复杂度

时间

       时间复杂度即循环的次数,外层循环n-1次,内层循环最好为1次,最坏为n次,由此可推出为1到2的和,为如下图:
这里写图片描述

时间复杂度图形

这里写图片描述

空间

       它的空间复杂度是占用额外空间内存,循环里面只用到了一个temp临时变量,即空间复杂度为O(1)

实际应用

       据说冒泡排序是最慢的排序算法,可以当做给初学者讲解for循环、分析算法复杂度时的案例来讲,冒泡排序的作用远不止这些,它的思想值得我们学习,如果没有冒泡排序后面的各种优化排序也就不能够被发明出来,冒泡排序在算法中的地位好比 “Hello World” 在编程语言中的地位,理解了Hello World也就理解了冒泡。

快速排序

思路

代码

java版本

/**
 * Created by lilongsheng on 2017/6/20.
 */
public class QuickSort {

    public static void main(String[] args) {
        int[] arrayData = new int[]{26, 53, 67, 48, 57, 13, 48, 32, 60, 50 };

        QuickSort qs = new QuickSort();
        qs.quickSort(arrayData,0,9);

        for (int i : arrayData){
            System.out.println(i);
        }
    }

    /**
     * 快速排序一个已知数组
     * @param arrayData
     * @param left
     * @param right
     */
    public void quickSort(int[] arrayData,int left,int right){
        //出口必须有,否则right会减成负数,程序死循环
        if (right <= left) return;
        //选择轴值
        int pivot = selectPivot(left,right);
        //轴值与数组元素换位置(任意位置即可)
        swap(arrayData,pivot,right);
        //根据轴值分成两组
        pivot = partition(arrayData,left,right);
        //左边数组继续分组
        quickSort(arrayData,left,pivot-1);
        //右边数组继续分组
        quickSort(arrayData,pivot+1,right);

    }

    /**
     * 轴值选取(影响排序性能,可优化)
     * @param left
     * @param right
     * @return
     */
    public int selectPivot(int left,int right){
        return (left + right) / 2;
    }

    public void swap(int[] arrayData,int pivot,int right){
        int temp = arrayData[right];
        arrayData[right] = arrayData[pivot] ;
        arrayData[pivot] = temp;
    }

    /**
     * 根据轴值对数组分为大小两组
     * @param arrayData
     * @param left
     * @param right
     * @return
     */
    public int partition(int[] arrayData,int left,int right){

        int l = left;
        int r = right;
        int temp = arrayData[r];
        //从左右两端像中间循环
        while (l < r){
            //从左像右找 大于等于轴值得数据
            while ( arrayData[l] <= temp && l < r){
                l++;
            }
            if (l < r){
                arrayData[r] = arrayData[l];
                r--;
            }
            //从右像左找 小于等于轴值得数据
            while ( arrayData[r] >= temp && l < r){
                r--;
            }
            if (l < r){
                arrayData[l] = arrayData[r];
                l++;
            }
        }
        //循环结束时 l = r ,即轴值位置
        arrayData[l] = temp;

        return l;
    }
}

python版本

 1 # 快速排序入口函数
  2 def quick_sort(datas,left,right):
  3         print('开始快速排序')
  4         # 出口
  5         if (right <= left ): return
  6         # 选取轴值(可以自定义位置)
  7         pivot = select_pivot(left,right)
  8         print('轴值=='+str(pivot))
  9         # 将轴值与任何一个值互换
 10         swap(datas,pivot,right)
 11 
 12         # 计划轴值新位置
 13         pivot = partition(datas,left,right)
 14         print('pivot==' + str(pivot))
 15 
 16         quick_sort(datas,left,pivot-1)
 17         quick_sort(datas,pivot+1,right)
 18 
 19         for x in datas:
 20                 print('x='+str(x))
 21 
 22 
 23 # 选取轴值方法
 24 def select_pivot(left,right):
 25         return int((left + right) / 2)
  1 # 快速排序入口函数
  2 def quick_sort(datas,left,right):
  3         print('开始快速排序')
  4         # 出口
  5         if (right <= left ): return
  6         # 选取轴值(可以自定义位置)
  7         pivot = select_pivot(left,right)
  8         print('轴值=='+str(pivot))
  9         # 将轴值与任何一个值互换
 10         swap(datas,pivot,right)
 11 
 12         # 计划轴值新位置
 13         pivot = partition(datas,left,right)
 14         print('pivot==' + str(pivot))
 15 
 16         quick_sort(datas,left,pivot-1)
 17         quick_sort(datas,pivot+1,right)
 18 
 19         for x in datas:
 20                 print('x='+str(x))
 21 
 22 
 23 # 选取轴值方法
 24 def select_pivot(left,right):
 25         return int((left + right) / 2)
 26 
 27 # 将轴值与任意一个数字交换
 28 def swap(datas,pivot,right):
 29         datas[pivot],datas[right] = datas[right],datas[pivot]
 30 
 31 # 根据轴值充分分组
 32 def partition(datas,left,right):
 33         l = left
 34         r = right
 35         temp = datas[r]
 36 
 37         while (l < r):
 38                 # 从左像右遍历,如果有大于轴值得,移动到右侧
 39                 while ( datas[l] <= temp and l < r ):
 40                         l += 1
 41                 if ( l < r ):
 42                         datas[r] = datas[l]
 43                         r -= 1
 44                 # 从右侧向左遍历,如果有小雨轴值得,移动到左侧
 45                 while ( datas[r] >= temp and l < r ):
 46                         r -= 1
 47                 if ( l < r ):
 48                         datas[l] = datas[r]
 49                         l += 1
 50 
 51         datas[l] = temp
 52         # 返回轴值位置,l = r
 53         return l
 54 
 55 
 56 # 1. python 实现注意  print 时 注意str 变量不能默认类型转换  python是动态类型语言
 57 # 2. python 语言的i++  i-- 类似语法不支持,使用 i-=1 表示 i-- ,   i+=1 表示 i++

复杂度

时间

  • 最坏:O(n2)
  • 平均:O(nlogn)
  • 最好:O(nlogn)

空间

-均分时:O(logn)
关于复杂度的推导在后续文章中继续介绍。

实际应用

       对于某个排序算法的应用其实并不多,查了一下资料是否使用某个算法要结合其它条件来选取,比如n的大小、是否稳定、是否有序、辅助空间大小等等,综合内外因素来选取具体某个排序算法或者组合算法。

思考:

1.冒泡排序与快速排序之间的关系?

       快速排序可以看做是冒泡排序的优化,它运用了分治法的基础思想,每次分治法分组时利用的是比较交换排序,可以这样理解:冒泡 + 分治 + 分组 = 快速。

2.快速排序是如何想出来的?

       快速排序由C. A. R. Hoare在1962年提出,距离现在已经有近60年,为什么会有人能想出来这么快的算法呢,任何新方法新技术的产生都是在原有基础上的创新或优化,各行各业亦如此,想必发明快速排序的作者对冒泡排序和其它理论基础知识廖记于心。
       很多优秀的算法都是重复利用以前的计算结果而不用重新计算提高效率,快速排序之所以快是因为考虑到了两个问题
- 分治分组
- 怎么分

       怎么分对于快速排序是重点,快速排序中通过选取一个值将数组分为小于该数的数组和大于该数的数组,每次排序既把选取元素的位置确定了,也基本确定了左右元素的活动范围,因此,它的排序效率很高。

如何优化快速排序?

       优化快速排序还需要从它的特点入手,怎么分组的问题,分组时越精准那么以后排序的次数也就越少,从理论上说可以选取任意数组中元素,我们选取的元素越能靠近中间值元素,排序越少。

3.学习发明轮子的思想?

       知识只有转化生产力才能有价值,学富五车也不如将其部分应用于实践,想要将自己所学应用于实践就必须知道它的本质特性、融会贯通,对于算法也是如此,如果只死记硬背一些算法应付考试,就不能够在生活中、工作中发挥出其价值来,最终发挥其作用才是我们不断学习的动力。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章