算法基础

来源:互联网 发布:linux gre over ipsec 编辑:程序博客网 时间:2024/06/08 12:54

算法定义

算法(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 arraydef 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 firstdef 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()
0 0
原创粉丝点击