算法基础

算法定义

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

时间复杂度

时间频度

一个算法执行所耗费的时间,从理论上是不能算出来的,必须上机运行测试才能知道。但我们不可能也没有必要对每个算法都上机测试,只需知道哪个算法花费的时间多,哪个算法花费的时间少就可以了。并且一个算法花费的时间与算法中语句的执行次数成正比例,哪个算法中语句执行次数多,它花费时间就多。一个算法中的语句执行次数称为语句频度或时间频度。记为T(n)。

时间复杂度

刚才提到的时间频度中,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)) 为算法的渐进时间复杂度,简称时间复杂度。n一般就是执行的次数,f(n)就是问题的规模

常见的时间复杂度

按数量级递增排列,常见的时间复杂度有:
常数阶O(1), 对数阶O(log2n), 线性阶O(n), 线性对数阶O(nlog2n), 平方阶O(n^2), 立方阶O(n^3),…, k次方阶O(n^k), 指数阶O(2^n) 。

常用排序

名称复杂度说明备注
冒泡排序Bubble Sort O(N*N) 将待排序的元素看作是竖着排列的“气泡”,较小的元素比较轻,从而要往上浮  
插入排序Insertion sort O(N*N) 逐一取出元素,在已经排序的元素序列中从后向前扫描,放到适当的位置 起初,已经排序的元素序列为空
选择排序 O(N*N) 首先在未排序序列中找到最小元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小元素,然后放到排序序列末尾。以此递归。  
快速排序Quick Sort O(n *log2(n)) 先选择中间值,然后把比它小的放在左边,大的放在右边(具体的实现是从两边找,找到一对后交换)。然后对两边分别使用这个过程(递归)。  
堆排序 HeapSort O(n *log2(n)) 利用堆(heaps)这种数据结构来构造的一种排序算法。堆是一个近似完全二叉树结构,并同时满足堆属性:即子节点的键值或索引总是小于(或者大于)它的父节点。 近似完全二叉树
箱排序 Bin Sort O(n) 设置若干个箱子,把关键字等于 k 的记录全都装入到第k 个箱子里 ( 分配 ) ,然后按序号依次将各非空的箱子首尾连接起来 ( 收集 ) 。 分配排序的一种:通过” 分配 ” 和 ” 收集 ” 过程来实现排序。

冒泡排序

冒泡排序详情
python代码

def bubble(array):
    count=0
    length=len(array)

    exchange=length-1 #从0索引的
    while exchange!=0:
        length=exchange
        exchange=0
        for i in range(length):
            if array[i]>array[i+1]:
                temp=array[i+1]
                array[i+1]=array[i]
                array[i]=temp
                exchange=i+1  #exchange索引后的序列为顺序列表
        count+=1
        # print '第%d轮'%count,

    return array

选择排序

思想

选择排序的思想非常直接,不是要排序么?那好,我就从所有序列中先找到最小的,然后放到第一个位置。之后再看剩余元素中最小的,放到第二个位置……以此类推,就可以完成整个的排序工作了。可以很清楚的发现,选择排序是固定位置,找元素。相比于插入排序的固定元素找位置,是两种思维方式。不过条条大路通罗马,两者的目的是一样的。

代码

def select_sort(array):
    length=len(array)
    for i in range(0,length):
        index=i   #记录最最小值的索引
        for j in range(i+1,length):
            if array[index]>array[j]:
                index=j
        if (index!=i):
            temp=array[index]
            array[index]=array[i]
            array[i]=temp
    return array

插入排序

给定一个记录序列(r1,r2,…,rn),其相应的关键码分别是(k1,k2,…kn),排序是将这些记录排列成顺序为(r s1,r s2,… r sn)的一个序列,使得相应的关键码满足ks1<=ks2<=..<=ksn。

直接插入排序

思想

直接插入排序是插入排序中最简单的排序方法,类似于玩纸牌的时候整理手中纸牌的过程,其基本思想是:以此将待排序序列中的每一个记录插入到一个已经排好序的序列中,直到全部记录都排好序。(在排序问题中,通常讲数据元素称为记录)

排序过程

  1. 将整个待排序的记录序列划分为有序区和无序区,初始时有序区为待排序记录系列中的第一个记录,无序区包括所有剩余待排序的记录
  2. 将无序区的第一个记录插入到有序区的合适位置中,从而使无序区减少一个记录,有序区增加一个记录。
  3. 重复执行(2),直到无序区中没有记录为止

    将第一个记录看成是初始有序区,然后从第二个记录起依次插入到这个有序区中,直到将第n个记录插入完毕

for(i=2;i<=n;i++){
    插入第i个记录
}

一般情况下,在i-1个记录的有序区r[1]~r[i-1]中插入一个记录r[i]时,首先要查找r[i]的正确插入位置,最简单的,可以采用顺序查找,为了在寻找插入位置的过程中避免数组下标越界,在r[0]处设置“哨兵”,在自i-1起前往查找的过程中,同时后移记录

r[0]=r[i]
for(j=i-1;r[0]<r[j];j--){
    r[j+1]=r[j]
}

退出循环,说明找到了插入的位置,因为r[j]刚刚比较完毕,所以r[j+1]为正确的插入位置,将待差记录插入到有序表中:

r[j+1]=r[0]

代码实现

def insert_sort_1(array):
    # 设置哨兵位
    array.insert(0, 0)
    length = len(array)
    # 有序表的插入
    for i in range(2, length):
        array[0] = array[i]
        for j in range(i - 1, 0, -1):
            # 元素往后移
            if array[0] < array[j]:
                array[j + 1] = array[j]
            else:
                array[j + 1] = array[0]
                break
            #判断这个数是不是最小的
            if array[0]<array[1]:
                array[1]=array[1]

    return array[1:]

折半插入排序

分析直接插入排序算法,由于寻找插入位置的操作是在有序区进行的,因此可以通过折半查找来实现,由此进行的插入排序称为折半插入排序

代码实现

def insert_sort_2(array):
    "折半插入排序"
    array.insert(0,0)
    length=len(array)
    for i in range(2,length):
        array[0]=array[i]
        #在有序表中折半查找
        low=1
        high=i-1
        while low<=high:
            mid=(high+low)/2
            if array[0]>array[mid]:low=mid+1
            else:high=mid-1
        #找到了位置
        #移动记录
        for j in range(i-1,low-1,-1):
            array[j+1]=array[j]
        print 'array=%s,mid=%s,low=%s,high=%s'%(array[0],mid,low,high),
        """
        或者:
        for j in range(i,low,-1):
            array[j]=array[j-1]
        """
        array[low]=array[0]
        print array[1:]
    return array[1:]

希尔排序

希尔排序是对直接插入排序的一种改进,改进的着眼点是:
1. 若待排序记录按照关键码记录基本有序,直接插入排序的效率很高
2. 由于直接插入排序算法简单,则在待排序记录个数较少时,效率也很高

基本思想:

先将整个待排序记录序列分隔成若干个子序列,在子序列内分别进行直接插入排序,待整个序列基本有序的时候,在对全体记录进行一次直接插入排序

代码:

快速排序

快速排序详情
python代码

#coding:utf-8

"快速排序"
def quick_sort(array,first,end):
    if(first<end):
        "递归调用"
        "[23,13,35,6,19,50,28]----->[19, 13, 6, 23, 35, 50, 28]一次划分后的结果"
        pivot=partions(array,first,end)  #接受返回的轴值的索引
        #递归的对右侧的子序列进行快速排序
        quick_sort(array,pivot+1,end)
        #递归的对左侧的子序列进行快速排序
        quick_sort(array,first,pivot-1)

    return array

def partions(array,first,end):
    "一次划分"
    while first<end:
        #进行右侧扫描
        while first<end and array[first]<array[end]:end-=1
        #在右侧找到了一个比轴值小的数,交换这两个数,然后这个数(包括这个数)
        # 前面的就排好了,最后让first加1
        if(array[first]>array[end]):
            temp=array[first]
            array[first]=array[end]
            array[end]=temp
            first+=1

        #进行左侧扫描
        while first<end and array[first]<array[end]:first+=1
        #在左侧找到了一个比轴值的大的数,将这个数和轴值交换,然后这个数后面的数就排好了,让end减1
        if array[first]>array[end]:
            temp=array[first]
            array[first]=array[end]
            array[end]=temp
            end-=1

    #return array
    "返回轴值的索引"
    return first

def main():
    array=[23,13,35,6,19,50,28]
    pass
    print partions(array,0,6) #[19, 13, 6, 23, 35, 50, 28]一次划分后的结果

    print quick_sort(array,0,6) #[6, 13, 19, 23, 28, 35, 50]


if __name__ == '__main__':
    main()
原文地址:https://www.cnblogs.com/cmustard/p/6769913.html