一、算法介绍

1、 算法是什么

    算法是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制。也就是说,能够对一定规范的输入,在有限时间内获得所要求的输出。如果一个算法有缺陷,或不适合于某个问题,执行这个算法将不会解决这个问题。不同的算法可能用不同的时间、空间或效率来完成同样的任务。一个算法的优劣可以用空间复杂度与时间复杂度来衡量。

 

2、时间复杂度

   在计算机科学中,算法的时间复杂度是一个函数,它定性描述了该算法的运行时间。这是一个关于代表算法输入值的字符串的长度的函数。时间复杂度常用大O符号表述,不包括这个函数的低阶项和首项系数。

  一般情况下,算法中基本操作重复执行的次数是问题规模n的某个函数,用T(n)表示,若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f(n)的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数。记作T(n)=O(f(n)),称O(f(n))为算法的渐进时间复杂度(O是数量级的符号 ),简称时间复杂度。

    常见时间复杂度单位:效率从上到下变低,
        O(1)    简单的一次运算(常数阶)
        O(n)    一次循环(线性阶)
        O(n^2)     两个循环(平方阶)

        O(logn)    循环减半
        O(nlogn)    一个循环加一个循环减半
        O(n^2logn)
        O(n^3)


  一般情况下,随着n的增大,T(n)增长最慢的算法为最优算法

  O(1) 常数阶 < O(logn) 对数阶 < O(n) 线性阶 < O(nlogn) < O(n^2) 平方阶 < O(n^3) < { O(2^n) < O(n!) < O(n^n)

Python之基础算法介绍

 

 Python之基础算法介绍

 

 

大O推导法:

  1. 用常数1取代运行时间中的所有加法常数
  2. 在修改后的运行函数中,只保留最高阶项
  3. 如果最高阶项存在且不是1,则去除与这个项相乘的常数

比如:

这是一段C的代码
#include "stdio.h"
 
int main()
{
    int i, j, x = 0, sum = 0, n = 100;    /* 执行1次 */
    for( i = 1; i <= n; i++)
    {
        sum = sum + i;     /* 执行n次 */
        for( j = 1; j <= n; j++)
        {
            x++;                /* 执行n*n次 */
            sum = sum + x;      /* 执行n*n此 */
        }
    }
    printf("%d", sum);            /* 执行1次 */
}

分析:

执行总次数 = 1 + n + n*n + n*n + 1 = 2n+ n + 2

根据大O推导法:

1.用常数 1 取代运行时间中的所有加法常数:执行总次数为: 2n+ n + 1

2.在修改后的运行次数函数中,只保留最高阶项,这里的最高阶是 n 的二次方: 执行总次数为: 2n2

3.如果最高阶项存在且不是 1 ,则去除与这个项相乘的常数,这里 n 的二次方不是 1 所以要去除这个项的相乘常数:执行总次数为: n2

因此最后我们得到上面那段代码的算法时间复杂度表示为: O(n2)

 

3、空间复杂度

    空间复杂度是用来评估算法内存占用大小的单位
    
    空间换时间:如果需要增快算法的速度,需要的空间会更大

 

二、python实现常见的排序算法

前三种比较LowB,后三种比较NB

前三种时间复杂度都是O(n^2),后三种时间复杂度都是O(nlog(n))

 

1、冒泡(交换)排序

原理:列表中两个相邻的数,如果前一个数比后一个数大,就做交换。一共需要遍历列表的次数是len(lst)-1
时间复杂度:O(n^2)

Python之基础算法介绍

def bubble_sort(lst):
    for i in range(len(lst) - 1):  # 这是需要循环遍历多少次
        for j in range(len(lst) - 1 - i):  # 每次数组中的无序区
            if lst[j] > lst[j + 1]:
                lst[j], lst[j + 1] = lst[j + 1], lst[j]


lst = [1, 2, 44, 3, 5]
bubble_sort(lst)
print(lst)

 

优化:如果在循环的时候,有一次没有进行交换,就表示数列中的数据已经是有序的
时间复杂度:最好情况是0(n),只遍历一次,一般情况和最坏情况都是O(n^2)

def bubble_sort(lst):
    for i in range(len(lst)-1):     # 这是需要循环遍历多少次
        change = False      # 做一个标志变量
        for j in range(len(lst)-1-i):   # 每次数组中的无序区
            if lst[j] >lst[j+1]:
                lst[j],lst[j+1] = lst[j+1],lst[j]
                change = True   # 每次遍历,如果进来排序的话,就会改变change的值
        if not change:  # 如果change没有改变,那就表示当前的序列是有序的,直接跳出循环即可
            return
 
 
lst = [1, 2, 44, 3, 5]
bubble_sort(lst)
print(lst)

 

2、选择排序

原理:每次遍历找到当下数组最小的数,并把它放到第一个位置,下次遍历剩下的无序区,记录剩余列表中最小的数,继续放置

时间复杂度 O(n^2)

方法一:

def select_sort(lst):
    for i in range(len(lst) - 1):  # 当前需遍历的次数
        min_loc = i  # 当前最小数的位置
        for j in range(i + 1, len(lst)):  # 无序区
            if lst[j] < lst[min_loc]:  # 如果有更小的数
                lst[min_loc], lst[j] = lst[j], lst[min_loc]  # 把最小的数交换到当前最小数的位置(索引)


lst = [1, 2, 44, 3, 5]
select_sort(lst)
print(lst)

 

方法二:

def select_sort(lst):
    for i in range(len(lst) - 1):  # 当前需遍历的次数
        min_loc = i  # 当前最小数的位置
        for j in range(i + 1, len(lst)):  # 无序区
            if lst[j] < lst[min_loc]:  # 如果有更小的数
                min_loc = j  # 最小数的位置改变
        if min_loc != i:
            lst[i], lst[min_loc] = lst[min_loc], lst[i]  # 把最小数和无序区第一个数交换


lst = [1, 2, 44, 3, 5]
select_sort(lst)
print(lst)

 

3、插入排序

原理:列表分为有序区和无序区,有序区是一个相对有序的序列,就是说在有序区内,是已经排序好了的,最初有序区只有一个元素,每次从无序区选择一个值,插入到有序区,直到无序区为空

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

原理图

Python之基础算法介绍

def insert_sort(lst):
    for i in range(1, len(lst)):  # 无序区从1开始向前跟有序区比较、插入  (有序区初始有一个值)
        for j in range(i, 0, -1):  # 如果无序区的值小于前一个元素,交换位置
            if lst[j] < lst[j - 1]:
                lst[j], lst[j - 1] = lst[j - 1], lst[j]
            else:
                break


lst = [12, 15, 9, 20, 6, 31, 24]
insert_sort(lst)
print(lst)

 

4、快速排序

思路:取第一个元素,让它归位,就是放到一个位置,使它左边的都比它小,右边的都比它大,然后递归完成排序

设要排序的数组是A[0]……A[N-1],首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,
然后将所有比它小的数都放到它左边,所有比它大的数都放到它右边,这个过程称为一趟快速排序。
值得注意的是,快速排序不是一种稳定的排序算法,也就是说,多个相同的值的相对位置也许会在算法结束时产生变动。


一趟快速排序的算法是:
1)设置两个变量i、j,排序开始的时候:i=0,j=N-1
2)以第一个数组元素作为关键数据,赋值给key,即key=A[0]
3)从j开始向前搜索,即由后开始向前搜索(j--),找到第一个小于key的值A[j],将A[j]和A[i]的值交换
4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]的值交换
5)重复第3、4步,直到i==j; (3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,
使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。
算法思路

相关文章: