算法基础

一、什么是算法

  算法:一个计算过程,解决问题的方法。

  程序 = 数据结构 + 算法

二、时间复杂度

  时间复杂度:用来评估算法效率的一个东西

print('Hello World!')        O(1)

for i in range(n):            O(n)
    print('Hello World!')     

for i in range(n):            O(n²)
    for j in range(n):    
        print('Hello World!') 

for i in range(n):            O(n³)
    for j in range(n):    
        for k in range(n):
            print('Hello World!') 

while n>1:            O(log₂n)或者O(logn)
print(n)
n= n//2

  时间复杂度是用来估计算法运行时间的一个式子(单位),一般来说,时间复杂度高的算法比复杂度低的算法慢

  常见的时间复杂度(按效率排序)

    O(1)<O(logn)<O(n)<O(nlogn)<O(n²)<O(n²logn)<O(n³)

  不常见的的时间复杂度:O(n!),O(2ⁿ),O(nⁿ)

 如何快速的判断时间复杂度:

  1.循环减半的过程     O(logn)

  2.几层循环就是n的几次方的复杂度

三、空间复杂度

  空间复杂度:用来评估算法内存占用大小的一个式子

  因为内存空间越来越大,相应时间要求越来越高,一般采用‘空间换时间’作为基本策略

四、列表查找

  列表查找:从列表中查找指定元素的索引/下标      输入:列表和要查找的元素    输出:索引/下标/未找到

  列表的查找分为:顺序查找和二分查找

    1.顺序查找:从列表的第一个元素进行查找,顺序搜索,直到找到位置 (时间复杂度为O(n))

    2.二分查找:从有序列表的候选区开始,通过比对查找值和候选区中间的的大小,渐渐缩小候选区大小,即查找范围逐步缩小  (时间复杂度为O(logn))

例子: 代码实现顺序列表中查找某个值所在的索引位置。

li = list(range(200,100000,10))
def bin_search(li,value):
    low = 0
    high = len(li) -1
    while low <= high:
        mid = (low + high) // 2
        if li[mid] > value:
            high = mid - 1
        elif li[mid] < value:
            low = mid + 1
        else:
            return mid
    return None

if __name__ == '__main__':
    mid = bin_search(li,10001)
    print(mid)
    if mid:
        print(li[mid])
使用while实现
# 使用递归实现
li = list(range(200,100000,10))
def bin_search(li,value,low=0,high=len(li)-1):
    mid = (low + high) // 2
    if low <= high and li[mid] > value:
        return bin_search(li,value,low,mid-1)
    elif low <= high and li[mid] < value:
        return bin_search(li,value,mid+1,high)
    elif li[mid] == value:
        return mid
    else:
        return None

if __name__ == '__main__':
    mid = bin_search(li,1000)
    print(mid)
    if mid:
        print(li[mid])
使用递归实现

备注:假设排序的时间复杂度为O(nlogn),如果对列表进行一次查找建议使用顺序查找,需要对列表进行多次查找操作建议先排序,后反复进行二分查找。

五、列表排序

排序方法:冒泡排序、选择排序、插入排序、快速排序、堆排序、归并排序、希尔排序

  1.冒泡排序(时间复杂度O(n²))

    原理:一趟分别两两比较大小,一趟结束后无序区中最大的元素放到无序区的最后,也是有序区的最前。

import random
def bubble_sort(li):
    for i in range(len(li)-1):    # 趟数
        for num in range(len(li)-i-1):
            if li[num]>li[num+1]:
                li[num],li[num+1] = li[num+1],li[num]


if __name__ == '__main__':
    li = list(range(50, 10000, 3))
    random.shuffle(li)
    bubble_sort(li)
    print(li)
冒泡排序代码

   冒泡排序优化:在执行排序的一趟中没有进行交换,则此时序列以及是有序,可以直接结算算法。(时间复杂度O(n²))

  2.选择排序

    原理:一趟遍历最小的元素放到第一个位置,反复进行

import random
def select_sort(li):
    for i in range(len(li)-1):  # 这里的-1表示最后一个可以不用进行排序
        mid = i
        for j in range(i+1,len(li)):  # 这里没有-1
            if li[mid] > li[j]:
                mid = j
        li[i],li[mid] = li[mid],li[i]
if __name__ == '__main__':
    li = list(range(50, 1000, 1))
    random.shuffle(li)
    select_sort(li)
    print(li)
选择排序

  3.插入排序(时间复杂度O(n²))

    要点: 每次取出的牌和手中有序的牌

# 插入排序
import random
def inster_sort(li):
    for i in range(1,len(li)):
        j = i-1
        mid = li[i]   # 拿到的牌
        while j >= 0 and mid < li[j]:
            li[j+1] = li[j]
            j -= 1
        li[j+1] = mid

if __name__ == '__main__':
    li = list(range(50, 100000, 13))
    random.shuffle(li)
    inster_sort(li)
    print(li)
插入排序

小结:冒泡排序,选择排序,插入排序   

      时间复杂度O(n²)

      空间复杂度O(1)

  4.快速排序  事件复杂度O(nlogn)

    快速排序思路:一、取一个元素P(第一个元素),使元素p归位;

           二、列表被p分成两部分,左边都比p小,右边都比p大;  

           三、递归完成排序;(即整理和递归)

# 快速排序
import random
def partiton(li,low,high):
    mid = li[low]
    while low < high:
        while low < high and li[high] >= mid:
            high -= 1
        li[low] = li[high]
        while low < high and li[low] <= mid:
            low += 1
        li[high] = li[low]
    li[low] = mid
    return low

def quick_sort(li, low, high):
    if low < high:
        mid = partiton(li,low,high)
        quick_sort(li,low,mid-1)
        quick_sort(li,mid+1,high)

if __name__ == '__main__':
    li = list(range(0, 1000000))
    random.shuffle(li)
    quick_sort(li, 0, len(li)-1)
    print(li)
快速排序

快速排序存在两个问题:

  1.最坏情况

  2.递归最大深度    通过sys.setrecursionlimit(100)可以设置递归深度

解决办法:

  1.随机生成比对值版本的快速排序,即:不取第一个值作为对比值,使用列表中随机的值来先和第一值进行交换,然后在继续进行操作。存在最坏情况,只是没法人为设计出来。

六、高级排序

堆排序

  堆排序基础:

  树: 树是一种数据结构   比如:目录结构

    树的基本概念:根节点,叶子节点,树的深度(高度),树的度,孩子节点,父节点,子树。

  二叉树:度不超过2的树(节点最多有两个叉)

    满二叉树:除最后一层无子节点外,每一层上的所有结点都有两个子结点二叉树。

    完全二叉树:叶节点只能出现在最下层和次下层,并且最下面一层的结点都集中在该层最左边的若干位置的二叉树

  二叉树的存储方式:

    链式存储和顺序存储

  堆排序:

    大根堆:一棵完全二叉树,满足任一节点都比其孩子节点大。

    小根堆:一棵完全二叉树,满足任一节点都比其孩子节点小。

  堆排序过程:

    1.建立堆。

    2.得到堆顶元素,为最大元素。

    3.去掉堆顶,将对最后一个元素放到堆顶,此时可通过一次调整重新使堆有序。

    4.堆顶元素为第二大元素。

    5.重复步骤3,直到堆变为空。

  堆排序注意事项:

    1.在调整各个子树的时候,子节点的位置可以方便的设置为整个树最有一个节点。(重要)

  堆排序代码:

# 向下调整
def sift(li, low, high):
    i = low
    j = 2 * i + 1
    tmp = li[low]
    while j <= high:
        if j + 1 <= high and li[j] < li[j + 1]:
            j = j + 1
        if tmp < li[j]:
            li[i] = li[j]
            i = j
            j = 2 * i + 1
        else:
            break
    li[i] = tmp


def heap_sort(li):
    for i in range(len(li) // 2 - 1, -1, -1):  # 依次调整每棵子树
        sift(li, i, len(li) - 1)
    for i in range(len(li) - 1, -1, -1):    # 挨个出数
        li[0],li[i] = li[i],li[0]
        sift(li, 0, i - 1)

if __name__ == '__main__':
    li = [6, 8, 1, 9, 3, 0, 7, 2, 4, 5]
    heap_sort(li)
    print(li)
# 堆排序
def sift(list_obj, low, high):  # 调整树
    tmp = list_obj[low]
    i = low
    j = 2 * i + 1
    while j <= high:
        if j < high and list_obj[j] < list_obj[j + 1]:
            j = j + 1
        if tmp < list_obj[j]:
            list_obj[i] = list_obj[j]
            i = j
            j = 2 * i + 1
        else:
            break
    list_obj[i] = tmp


def heap_sort(list_obj):
    for i in range(len(list_obj) // 2 - 1, -1, -1):  # 调整各个子树
        sift(list_obj, i, len(list_obj) - 1)
    for i in range(len(list_obj) - 1, -1, -1):  # 大的数换到最后,继续调整树
        list_obj[0], list_obj[i] = list_obj[i], list_obj[0]
        sift(list_obj, 0, i - 1)


if __name__ == '__main__':
    list_obj = [6, 8, 1, 9, 3, 0, 7, 2, 4, 5]
    heap_sort(list_obj)
    print(list_obj)
堆排序

 

posted @ 2017-11-07 05:57  40块钱抓娃娃  阅读(184)  评论(0编辑  收藏  举报