csdn_spider/blog/ds19991999/原创-- 算法图解笔记.md

6.8 KiB
Raw Permalink Blame History

原创

算法图解笔记

算法图解笔记

目录

算法简介

二分法查找,输入一个有序列表返回元素位置或null。
一般而言,对于包含n个元素的列表用二分法查找最多需要

      l 
     
    
      o 
     
     
     
       g 
      
     
       2 
      
     
    
      n 
     
    
   
     log_2 n 
    
   
 log2n</strong>
def binary_search(list, item):
    low = 0
    high = len(list) - 1

    while low &lt;= high:
        mid = (low + high) // 2
        if list[mid] == item:
            return mid
        elif list[mid] &gt; item:
            high = mid - 1
        else:
            low = mid + 1
    return None

binary_search.py

选择排序

由于数组的结构在内存中是连续的,添加新元素十分麻烦,链表的优势在于插入新元素;
数组的优势在于元素的随机访问。也就是说数组和链表在插入和读取元素的时间复杂度刚好互补
selectSort

def findSmallest(arr):
    smallest = arr[0]
    smallest_index = 0
    for i in range(1,len(arr)):
        if arr[i] &lt; smallest:
            smallest = arr[i]
            smallest_index = i
    return smallest_index


def selectSort(arr):
    newArr = []
    for i in xrange(len(arr)):
        smallest = findSmallest(arr)
        newArr.append(arr.pop(smallest))
    return newArr

我的写法

def selectSort2(arr):
    n = len(arr)
    for i in range(n):
        for j in range(i, n):
            if arr[j] &lt; arr[i]:
                arr[i], arr[j] = arr[j], arr[i]
    return arr

时间复杂度为

     O 
    
   
     ( 
    
    
    
      n 
     
    
      2 
     
    
   
     ) 
    
   
  
    O(n^2) 
   
  
O(n2)

递归

递归函数要有基线条件和递归条件,否则会无限循环.

看一个阶乘函数的实现:

def fact(x):
    if x == 1:return 1
    else: return x*fact(x-1)

快速排序

快速排序是分而治之的策略quickSort

分而治之

def quickSort(arr):
    if len(arr)&lt;2:
        return arr
    else:
        pivot = arr[0]
        less = [i for i in arr[1:] if i &lt;= pivot]
        greater = [i for i in arr[1:] if i &gt; pivot]
        return quickSort(less)+[pivot]+quickSort(greater)   

这么看来比严版快排好理解多了,严版是用两个指针和一个基准值将数组划分成两部分,可以说时间复杂度确实小了不少。

def quickSort2(arr, left, right):
    if left&gt;=right:
        return arr
    
    low = left
    high = right
    key = arr[left]

    while left &lt; right:
        while left &lt; right and arr[right] &gt;= key:
            right -= 1
        arr[left] = arr[right]
        while left &lt; right and arr[left] &lt;= key:
            left += 1
        arr[right] = arr[left]

    arr[left] = key

    quickSort2(arr, low, left-1)
    quickSort2(arr, left+1, high)
    return arr

散列表

散列函数将输入映射到数字。它必须是一致的它将不同的输入映射到不同的数字。Python实现了散列表的实现——字典。
散列表是提供DNS解析这种功能的方式之一。

一个简单的投票:

voted = {}
def check_voter(name):
    if voted.get(name):
        print "kick them out!"
    else:
        voted[name] = True
        print "let them vote!"


将散列表用作缓存,缓存是一种常用的加速方式,缓存的数据则存储在散列表中。

cache = {}
def get_page(url):
    if cache.get(url):
        return cache[url]
    else:
        data = get_data_from_server(url)
        cache[url] = data
        return data


冲突的解决方法:将两个键映射到同一个位置,就在这个位置存储一个链表。为避免冲突,需要好的散列函数和较低的填充因子。

填装因子=散列表包含的元素数/位置总数一旦填充因子大于0.7,就开始调整撒列表长度。

在平均条件下,散列表的时间复杂度为

     O 
    
   
     ( 
    
   
     1 
    
   
     ) 
    
   
  
    O(1) 
   
  
O(1),在最糟糕的情况下,时间复杂度为 
 
  
   
   
     O 
    
   
     ( 
    
   
     n 
    
   
     ) 
    
   
  
    O(n) 
   
  
O(n)

广度优先搜索

图由节点——边组成。可以通过散列表将节点映射到其所有邻居,散列表是无序的。

graph = {}
graph["you"] = ["alice", "bob", "claire"]
graph["alice"] = ["peggy", "anuj"]
... 

创建一个队列,用于存储要检查的人,从队列中弹出一个人,检查他是否是芒果销售商,否的坏将这个人所有的另据加入队列。

from collections import deque
search_deque = deque()
search_deque += graph["you"]

def person_is_seller(name):
    return name[-1] == "m"

while search_deque:
    person = search_deque.popleft()
    if person_is_seller(persson):
        return True
    else:
        search_deque += graph[person]
return False


但是这种方法有缺陷,检查会有重复。应该检查完一个人,就将其标记。

def search(name):
    search_queue = deque()
    search_queue += graph[name]
    searched = []
    while search_queue:
        person = search_queue.popleft()
        if not person in searched:
            if person_is_seller(persson):
                return True
            else:
                search_queue += graph[person]
                searched.append(person)
     return False

时间复杂度为

     O 
    
   
     ( 
    
   
     V 
    
   
     + 
    
   
     E 
    
   
     ) 
    
   
  
    O(V+E) 
   
  
O(V+E)边数和人数

狄克斯特拉算法

def find_lowest_cost_node(costs):
    lowest_cost = float("inf")
    lowest_cost_node = None
    for node in costs:
        cost = costs[node]
        if cost &lt; lowest_cost and node not in processed:
            lowest_cost = cost
            lowest_cost_node = node
     return lowest_cost_node


贪婪算法

就是每步都选择最优解,最终得到全局的最优解。

NP完全问题

动态规划

与上一章对应,贪婪算法得到的可能不是最优解,而动态规划可以得到最优解。动态规划先解决子问题,再逐步解决大问题。