数据结构与算法

程序 = 数据结构+算法

时间复杂度是用来估计算法运行时间的一个式子(单位)

一般来说(与机器与问题规模有关),时间复杂度高的算法比时间复杂度低的算法慢

常见的时间复杂度排序

O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<O(n2logn)<O(n3)

复杂问题的时间复杂度

O(n!)

O(2n)

O(nn)

判断时间复杂度

确定问题规模

循环减半过程——logn

k层关于n的循环——nk

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

空间复杂度的表示方式与时间复杂度完全一样

算法使用了几个变量:O(1)

算法使用了长度为1的一维列表:O(n)

算法使用了m行n列的二维列表:O(mn)

空间换时间

1.递归

调用自身

结束条件

def fun1(n):
    if n > 0:
        print(n)
        fun1(n-1)

def fun2(n):
    if n > 0:
        fun2(n-1)
        print(n)

fun1(3)
print('-'*30)
fun2(3)

递归问题:汉诺塔问题:

def hanoi(n,a,b,c):
    if n>0:
        hanoi(n-1,a,c,b)
        print("moving from %s to %s" % (a,c))
        hanoi(n-1,b,a,c)

hanoi(3,'A','B','C')

汉诺塔移动次数递推式

h(x)=2h(x-1)+1

2.列表查找

输入:列表、待查找元素

输出:元素下标,未查找到时返回(None或者-1)

内置列表查找元素:index( )

(1)顺序查找:也叫线性查找,从列表的第一个元素开始,顺序进行搜索,直到找到元素或者搜索到列表的最后一个元素为止。

时间复杂度:O(n)

def linear_search(li,val):
    for ind,v in enumerate(li):
        if v == val:
            return ind
    else:
        return None

print(linear_search([1,2,3,4,5,6],5))

# 时间复杂度:O(n)

(2)二分查找:又叫折半查找,从有序列表的初始候选区li[0:n]开始,通过对待查找的值与候选区中间值的比较,可以使候选区减少一半

时间复杂度:O(logn)

def binary_search(li,val):
    left = 0
    right = len(li)-1
    while left <= right: # 候选区有值
        mid = (left + right) // 2
        if li[mid] == val:
            return mid
        elif li[mid] > val: # 待查找的值在mid左侧
            right = mid -1
        else: # li[mid] < val: # 待查找的值在mid右侧
            left = mid +1
    else:
        return None

print(binary_search([1,2,3,4,5,6,7,8,9],3))


3.排序

将一组无序的记录序列调整为有序的记录序列

列表排序:将无序列表转换为有序列表

输入:列表

输出:有序列表

升序与降序

内置排序函数:sort( )

(1)冒泡排序

默认升序排序

列表每相邻的两个数,如果前面的数比后面的大,则交换这两个数

一趟排序完成后,无序区减少一个数,有序区增加一个数

时间复杂度:O(n2)

import random
def bubble_sort(li):
    for i in range(len(li)-1): # 第几趟
        exchange = False
        for j in range(len(li)-i-1): # 每一趟的指针从0开始
            if li[j] > li[j+1]: # 箭头指的数大于后面的一个数
                li[j+1],li[j] = li[j],li[j+1]  # 则交换
                exchange = True
        print(li)
        if not exchange:
            return



# li = [random.randint(0,10000) for i in range(10)]
li = [1,2,3,4,33,5]
print(li)
bubble_sort(li)
print(li)

(2)选择排序

def select_sort_simple(li):
    li_new = []
    for i in range(len(li)):
        min_val = min(li)
        li_new.append(min_val)
        li.remove(min_val)
    return li_new

# 复杂度:O(n*n)
def select_sort(li):
    for i in range(len(li)-1): # 第几趟,第i趟的无序区的第一个数的下标是i
        min_loc = i # 假定无序区的第一个数是最小的数
        for j in range(i+1,len(li)): # 遍历无序区
            if li[j] < li[min_loc]: # 判断寻找最小的数
                min_loc = j # 找到最小的数记录最小的数的下标
        li[min_loc],li[i]  = li[i],li[min_loc] # 将找到的最小的数的下标与无序区的第一个数换位置
        print(li)


li = [22,11,2,5,56,67,88,44,55,6]
print(li)
select_sort(li)
print(li)

(3)插入排序

初始时手里只有一张牌,每次从无序区摸一张牌,插到手里已有牌的正确位置

时间复杂度:O(n2)

插入排序升序程序

def insert_sort(li):
    for i in range(1,len(li)): # i表示摸到的牌的下标,第一张牌默认为手里的牌(下标为0的位置),所以摸到的牌从1开始
        tmp = li[i] #tmp表示摸到的牌,使摸到的牌不能被覆盖
        j = i-1 # j指的就是手里的牌
        while j >= 0 and li[j] > tmp: #手里的牌为第一张或者之后并且摸到的牌比手里的小
            li[j+1] = li[j] # 将牌往右移
            j -= 1 # j从左向右遍历
        li[j+1] = tmp #摸到的牌比手里的牌大,将摸到的牌插入到比他小的牌的位置
        print(li)
#关键在于找插入位置
#区分有序区和无序区
li = [1,6,2,8,99,23,22,44,55]
print(li)
insert_sort(li)
print(li)







插入排序降序程序

def insert_sort(li):
    for i in range(1,len(li)): # i表示摸到的牌的下标,第一张牌默认为手里的牌(下标为0的位置),所以摸到的牌从1开始
        tmp = li[i] #tmp表示摸到的牌,使摸到的牌不能被覆盖
        j = i-1 # j指的就是手里的牌
        while j >= 0 and li[j] < tmp: #手里的牌为第一张或者之后并且摸到的牌比手里的小
            li[j+1] = li[j] # 将牌往右移
            j -= 1 # j从左向右遍历
        li[j+1] = tmp #摸到的牌比手里的牌大,将摸到的牌插入到比他小的牌的位置
        print(li)
#关键在于找插入位置
#区分有序区和无序区
li = [1,6,2,8,99,23,22,44,55]
print(li)
insert_sort(li)
print(li)







全部评论

相关推荐

purcoter:虚拟货币预测正确率百分之99,还要找工作干嘛,不早就财富自由了
点赞 评论 收藏
分享
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务