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

    数据结构:数据(基本类型(int,float,char))的组织方式

    算法复杂度

    时间复杂度:用来估计算法运行时间的一个单位;O(n)、O(1) 常见于for循环, 或者log(n)—常见于while循环。循环减半时复杂度为log(n)

           常见时间复杂度排序  O(1) < O(logn)< O(n) < O(n^log n) < O(n^2) < O(n^2 log n ) < O(n^3)

    timeit模块,测试python代码的执行速度;

    空间复杂度:估算算法内存占用大小的单位;"空间换时间";  O(1),O(n)

    算法:完成算法基础模块后,算法优化是关键点(方法:查找算法模块中重复或者无效计算,用内层加判断替换)

    递归算法:调用自身,结束条件 --- 汉诺塔,斐波那契数列

    列表查找:顺序查找(for循环),二分查找(数据候选区二分data[:0],查找范围缩减一半)

                      排序l初级:冒泡、选择、插入;-------  思想:数据分区(有序区/无序区,已查找/未查找),数据比较,数据换位

                      排序高级:快速排序、堆排序、归并排序

     python语言使用的内置排序方法是timsort,原理基于归并排序

    #冒泡排序:列表中每相邻的两个数,如果前面的比后面的大,则互相替换位置
    def bubble_sort(li):
    for i in range(len(li)-1): # i 表示第N趟,一共n或者n-1趟
    exchange = False
    for j in range(len(li) - i - 1): #第i趟,无序区【0,n-i-1】 j 表示箭头 0- n-i-2
    if li[j] > li[j+1]:
    li[j],li[j+1] = li[j+1],li[j]
    exchange = True
    if not exchange:
    break

    #选择排序:选择最小的数排在第一的位置
    def select_sort(li):
    for i in range(len(li)-1): #n 或者n-1 趟
    min_pos = i #第i趟无序区范围 i~最后 #min_pos 更新为无序区最小值位置
    for j in range(i+1,len(li)):
    if li[j] < li[min_pos]:
    min_pos = j
    li[i],li[min_pos] = li[min_pos],li[i]
    #插入排序:挪位置,不断地将尚未排好序的数插入到已经排好序的部分。
    def insert_sort(li):
    for i in range(1,len(li)): #i表示摸到的牌的下标
    tmp = li[i] #摸到的牌
    j = i - 1 #排好序的最后一张牌的位置
    while j >= 0 and li[j] > tmp: #只要往后挪就循环, 2个条件都得到满足
    li[j+1] = li[j] #如果 j = -1 停止挪,如果li[j] 小了,停止挪
    j -= 1 #j位置在循环结束时要么是 -1,要么是一个比tmp小的值
    li[j+1] = tmp

     位运算: & | - ^ ~

    快速排序:取一个元素P,列表被P分成两部分,左边比P小,右边比P大,递归完成排序
    import sys 
    sys.setrecursionlimit(5000) #设置递归深度
    def quick_sort(li):
    _quick_sort(li,0,len(li)-1)
    def _quick_sort(li,left,right):
        if left < right:
            mid = partition(li,left,right)
            _quick_sort(li,left,mid-1)
            _quick_sort(li,mid+1,right)
    
    def partition(li,left,right):
        tmp = li[left]
        while left < right:
            while left < right and li[right] >= tmp:
                right -= 1
            li[left] = li[right]
            while left < right and li[left] <= tmp:
                left += 1
            li[right] = li [left]
        li[left] = tmp
        return left
    #归并排序 两个有序列表合并成一个有序列表  :先分解,后排序,分而治之
    def merge(li,low,mid,high):
        i = low
        j = mid +1
        li_tmp = []
        while i <= mid and j <= high:
            if li[i] <= li[j]:
                li_tmp.append(li[i])
                i += 1
            else:
                li_tmp.append(li[j])
                j += 1
        while i <= mid:
            li_tmp.append(li[i])
            i += 1
        while j <= high:
            li_tmp.append(li[i])
            j += 1
        for i in range(low,high+1):
            li[i] = li_tmp[i-low]
            
    def merge2list(li1,li2):
        li = []
        i = 0
        j = 0
        while i < len(li1) and j < len(li2):
            if li1[i] <= li2[j]:
                li.append(li1[i])
                i += 1
            else:
                li.append(li2[j])
                j += 1
        while i < len(li1):
            li.append(li1[i])
            i += 1
        while j < len(li2):
            li.append(li2[j])
            j += 1
        return li
    #先递归,后归并
    def merge_sort(li,low,high):
    if low < high:
    mid = (low + high)//2 #先分解
    merge_sort(li,low,mid)
    merge_sort(li,mid+1,high)
    merge(li,low,mid,high) #归并合并

    li = [10,4,6,3,8,2,5,7]
    merge_sort(li,0,len(li)-1)
    print(li)

    堆排序前传———树与二叉树

    树是一种数据结构,是一种可以递归定义的数据结构,是有n个节点组成的集合

    树的概念:根节点、叶子节点、深度、孩子节点/父节点,子树

    def sift(data,low,high):
        i = low  # i 最开始指向根节点
        j = 2*i + 1 # j 开始是左孩子
        tmp = data[i] # 把堆顶存起来
        while j <= high: #只要j位置有数
            if j <high and data[j] <data [j+1]:  #如果右孩子有且比较大
                j += 1 # j指向右孩子
            if tmp < data[j]:
                data[i] = data[j]
                i = j  # 往下看一层
                j = 2*i +1 
            else: #tmp更大,把tmp放在i的位置上
                data[i] = tmp #把tmp放在某一级领导位置上
                break
        data [i] = tmp  # 把tmp放在叶子节点上
    
    def heap_sort(data):
        n = len(data)
        for i in range(n//2 -1,-1,-1): # i 表示建堆时调整部分根的下标
            sift(data,i,n-1) #建堆完成
        for i in range(n -1,-1,-1): #i指向当前堆最后一个元素
            data[0],data[i] = data [i],data[0]
            sift(data,0,i-1) # i-1是新的high
    
    # python内置堆模块
    import heapq
    import random
    li = list(range(20))
    random.shuffle(li)
    heapq.heapify(li) #建堆
    heapq.heappop(li)  #弹出最小值
    n = len(li)
    for i in range(n):
        print(heapq.heappop(li),end = ',')

     

    希尔排序:
    def
    insert_sort(li,d): for i in range(d,len(li)): tmp = li[i] j = i - d while j >= 0 and li[j]> tmp: li[j+d] = li[j] j -= d li[j+d] = tmp def shell_sort(li): d = len(li)//2 while d > 0: insert_sort(li,d) d = d//2 li = list(range(1000)) random.randint(li) insert_sort(li)
    计数排序
    def
    count_sort(li,max_num = 100): count = [0 for _ in range(max_num +1)] for val in li: count[val] += 1 li.clear() for i,v in enumerate(count): for _ in range(v): li.append(i)

    栈:数据集合,只能在一端进行插入或删除操作的列表,特点是后进先出(last-in,first_out)。栈的基本操作:进栈push,出栈pop,取栈顶gettop。

    队列:数据集合,仅允许在列表一端进行插入,另一端进行删除。插入的一端是队尾,删除的称为队头。先进先出。

    迷宫找路
    dirs = [ lambda x,y:(x-1,y) # lambda x,y:(x,y+1) # lambda x,y:(x+1,y) # lambda x,y:(x,y-1) # ] def solve_maze(x1,y1,x2,y2): stack = [] stack.append((x1,y1)) maze[x1][y1] = 2 while len(stack) > 0: # 当栈不空时循环 cur_node = stack[-1] if cur_node == (x2,y2): #如果到终点了 print(stack) return True for d in dirs: next_node = d(*cur_node) if maze[next_node[0]][next_node[1]] ==0: stack.append(next_node) maze[next_node[0]][next_node[1]] = 2 # 2表示已经走过的点 break else: stack.pop() else: print('无路') return False
    • 冒泡排序和插入排序是最基础的,面试官有时候喜欢拿它们来考察你的基础知识,并且看看你能不能快速地写出没有 bug 的代码。
    • 归并排序、快速排序和拓扑排序的思想是解决绝大部分涉及排序问题的关键,我们将在这节课里重点介绍它们。
    • 堆排序和桶排序,本节课不作深入研究,但有时间的话一定要看看,尤其是桶排序,在一定的场合中(例如知道所有元素出现的范围时),能在线性的时间复杂度里解决战斗

    冒泡排序(Bubble Sort)

    基本思想

    给定一个数组,我们把数组里的元素通通倒入到水池中,这些元素将通过相互之间的比较,按照大小顺序一个一个地像气泡一样浮出水面。
    实现

    每一轮,从杂乱无章的数组头部开始,每两个元素比较大小并进行交换,直到这一轮当中最大或最小的元素被放置在数组的尾部,然后不断地重复这个过程,直到所有元素都排好位置。其中,核心操作就是元素相互比较。
    例题分析

    给定数组 [2, 1, 7, 9, 5, 8],要求按照从左到右、从小到大的顺序进行排序。 
    解题思路

    从左到右依次冒泡,把较大的数往右边挪动即可。空间复杂度是 O(1)

    插入排序(Insertion Sort)

    基本思想

    不断地将尚未排好序的数插入到已经排好序的部分。空间复杂度是 O(1),时间复杂度是 O(n2)
    特点

    在冒泡排序中,经过每一轮的排序处理后,数组后端的数是排好序的;而对于插入排序来说,经过每一轮的排序处理后,数组前端的数都是排好序的。
    例题分析

    对数组 [2, 1, 7, 9, 5, 8] 进行插入排序。
    解题思路

    首先将数组分成左右两个部分,左边是已经排好序的部分,右边是还没有排好序的部分,刚开始,左边已排好序的部分只有第一个元素 2。接下来,我们对右边的元素一个一个进行处理,将它们放到左边。

    归并排序(Merge Sort)

    基本思想

    核心是分治,就是把一个复杂的问题分成两个或多个相同或相似的子问题,然后把子问题分成更小的子问题,直到子问题可以简单的直接求解,最原问题的解就是子问题解的合并。归并排序将分治的思想体现得淋漓尽致。空间复杂度就是 O(n)。归并排序也是稳定的排序算法
    实现

    一开始先把数组从中间划分成两个子数组,一直递归地把子数组划分成更小的子数组,直到子数组里面只有一个元素,才开始排序。
    排序的方法就是按照大小顺序合并两个元素,接着依次按照递归的返回顺序,不断地合并排好序的子数组,直到最后把整个数组的顺序排好。

    快速排序(Quick Sort)

    基本思想

    快速排序也采用了分治的思想。
    实现

    把原始的数组筛选成较小和较大的两个子数组,然后递归地排序两个子数组。

    拓扑排序(Topological Sort)

    基本思想

    和前面介绍的几种排序不同,拓扑排序应用的场合不再是一个简单的数组,而是研究图论里面顶点和顶点连线之间的性质。拓扑排序就是要将这些顶点按照相连的性质进行排序。
    要能实现拓扑排序,得有几个前提:
    图必须是有向图、图里面没有环,拓扑排序一般用来理清具有依赖关系的任务。

    • 将问题用一个有向无环图(DAG, Directed Acyclic Graph)进行抽象表达,定义出哪些是图的顶点,顶点之间如何互相关联。
    • 可以利用广度优先搜索或深度优先搜索来进行拓扑排序。

    相关资源: 数据结构与算法

    天才是百分之一的灵感,加百分之九十九的汗水,但那百分之一的灵感往往比百分之九十九的汗水来的重要
  • 相关阅读:
    0909 作业
    20190909 pycharm快捷键与变量
    20190906 计算机基础
    0905 计算机组成原理
    day 08 作业
    20190902 函数
    20190827 文件操作
    获取多段线上圆弧的中心点 半径
    读取ini配置文件
    CStatic设置位图
  • 原文地址:https://www.cnblogs.com/Christbao/p/12283836.html
Copyright © 2011-2022 走看看