zoukankan      html  css  js  c++  java
  • 算法基础

    算法定义

    算法(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()
    
  • 相关阅读:
    Redis 常用命令整理
    TCP系列01—概述及协议头格式
    TCP/IP详解--TCP网络传输数据包1460MSS和1448负载
    TCP中报文段大小(MSS)、MTU
    DNS 过滤脚本
    TCP SYN Cookies – DDoS defence
    python virtualenv venv 虚拟环境
    git 命令总结
    王兴三横四纵
    获取国税门户可供下载的资源文档
  • 原文地址:https://www.cnblogs.com/cmustard/p/6769913.html
Copyright © 2011-2022 走看看