哈希表

In [3]:
# 创建哈希表
def make_hashtable(size):
    table = []
    for unused in range(0, size):
        table.append([])
    return table
# 计算哈希值
def hash_string(s, size):
    h = 0
    for c in s:
         h = h + ord(c)
    return h % size
# 获取key的值列表(条目)
def hashtable_get_bucket(htable, key):
    return htable[hash_string(key, len(htable))]
# helper:获取条目
def get_entry(htable, key):
    bucket = hashtable_get_bucket(htable, key)
    for entry in bucket:
        if entry[0] == key:
            return entry
# 更新条目中的值
def hashtable_update(htable, key, value):
    if get_entry(htable, key):
        get_entry(htable, key)[1] = value 
    hashtable_get_bucket(htable, key).append([key, value])
# 查找值
def hashtable_lookup(htable, key):
    if get_entry(htable, key):
        return get_entry(htable, key)[1]
    return None
In [4]:
# test_case
table = make_hashtable(10)
hashtable_update(table, 'Python', 'Monty')
hashtable_update(table, 'CLU', 'Barbara Liskov')
hashtable_update(table, 'JavaScript', 'Brendan Eich')
hashtable_update(table, 'Python', 'Guido van Rossum')
print hashtable_lookup(table, 'Python')
#>>> Guido van Rossum
Guido van Rossum

网页搜索、排名算法

网页收集、存储、查找

In [1]:
# 读取网页数据
#def get_page(url):
 #   try:
  #      import urllib
   #     return urllib.urlopen(url).read()
    #except:
     #   return ''
In [9]:
# 获取所有链接,通过索引存储数据

## 获取第一个链接和该链接结束位置
def get_next_target(page):
    start_link = page.find(('<a href='))
    if start_link == -1:
        return None, 0
    start_quote = page.find('"', start_link)
    end_quote = page.find('"', start_quote + 1)
    url = page[start_quote + 1:end_quote]
    return url, end_quote
## 通过循环,获取当前页面的所有链接
def get_all_links(page):
    links = []
    while True:
        url, end_quote = get_next_target(page)
        if url:
            links.append(url)
            page = page[end_quote:]
        else:
            break
    return links

## 创建关键字、链接、点击量的索引
### index-->[[keyword,[[url,num],...]],...]
### helper:记录用户点击数
def record_user_click(index, keyword, url):
    urls = lookup(index, keyword)
    if url:
        for entry in urls:
            if entry[0] == url:
                entry[1] = entry[1] + 1
### helper:增:添加链接和关键字至索引    
def add_to_index(index, keyword, url):
    if keyword in index and url not in index[keyword]:
            index[keyword].append(url)
    else:
         index[keyword] = [url]
    
def add_page_to_index(index, url, content):
    words = content.split()
    for word in words:
        add_to_index(index, word, url)
        
## 爬取所有链接
### helper:合并两个列表,并排除重复项
def union(p, q):
    for e in q:
        if e not in p:
            p.append(e)
            
def crawl_web(seed, max_depth):
    tocrawl = [seed] # 待爬取
    crawled = [] # 已爬取
    next_page = [] # 本层链接列表
    depth = 0 #爬取层数
    index = {} # 关键字索引
    while tocrawl and depth <= max_depth:
        page = tocrawl.pop()
        if page not in crawled:
            content = get_page(page)
            add_page_to_index(index, page, content)
            union(next_page, get_all_links(content))
            crawled.append(page)
        if not tocrawl:
            tocrawl, next_page = next_page, []
            depth += 1
    return index
# 查找
def lookup(index, keyword):
    if keyword in index:
        return index[keyword]
    else:
        return None
In [15]:
# %%timeit
# test_case
def get_page(url):
    try:
        if url == "http://www.udacity.com/cs101x/index.html":
            return '''<html> <body> This is a test page for learning to crawl!
<p> It is a good idea to
<a href="http://www.udacity.com/cs101x/crawling.html">
learn to crawl</a> before you try to
<a href="http://www.udacity.com/cs101x/walking.html">walk</a> or
<a href="http://www.udacity.com/cs101x/flying.html">fly</a>.</p></body></html>'''

        elif url == "http://www.udacity.com/cs101x/crawling.html":
            return '''<html> <body> I have not learned to crawl yet, but I am
quite good at  <a href="http://www.udacity.com/cs101x/kicking.html">kicking</a>.
</body> </html>'''

        elif url == "http://www.udacity.com/cs101x/walking.html":
            return '''<html> <body> I cant get enough
<a href="http://www.udacity.com/cs101x/index.html">crawling</a>!</body></html>'''

        elif url == "http://www.udacity.com/cs101x/flying.html":
            return '<html><body>The magic words are Squeamish Ossifrage!</body></html>'
    except:
        return ""
    return ""
#print get_page('http://www.udacity.com/cs101x/index.html')
#print crawl_web('http://www.udacity.com/cs101x/index.html', 0)
#index = crawl_web('http://www.udacity.com/cs101x/index.html',10)
#print lookup(index, 'good')
#record_user_click(index, 'good', 'http://www.udacity.com/cs101x/crawling.html')
#print lookup(index, 'good')
['http://www.udacity.com/cs101x/index.html', 'http://www.udacity.com/cs101x/crawling.html']
['http://www.udacity.com/cs101x/index.html', 'http://www.udacity.com/cs101x/crawling.html']

实现网页排名算法

In [16]:
# 改写crawl_web,使返回index和graph
def crawl_web(seed):
    tocrawl = [seed]
    crawled = []
    index = {}
    graph = {} # url:[list of pages it links to]
    while tocrawl:
        page = tocrawl.pop()
        if page not in crawled:
            content = get_page(page)
            add_page_to_index(index, page, content)
            outlinks = get_all_links(content)
            
            graph[page] = outlinks
            
            union(tocrawl, outlinks)
            crawled.append(page)
    return index, graph
In [22]:
# 计算排名
def compute_ranks(graph):
    d = 0.8 # damping factor
    numloops = 10
    
    ranks = {}
    npages = len(graph)
    for page in graph:
        ranks[page] = 1.0/npages
    
    for i in range(0, numloops):
        newranks = {}
        for page in graph:
            newrank = (1 - d) / npages
            
            for node in graph:
                if page in graph[node]:
                    newrank = newrank + d*ranks[node]/len(graph[node])
                    
            newranks[page] = newrank
        ranks = newranks
    return ranks
In [26]:
# 搜索获得最佳网页
def lucky_search(index, ranks, keyword):
    pages = lookup(index, keyword)
    if not pages:
        return None
    best_page = pages[0]
    for candidate in pages:
        if ranks[candidate] > ranks[best_page]:
            best_page = candidate
    return best_page

quicksort算法

In [33]:
# 随机选取中间值,将小于等于它的列入左列表,大于它的列入右列表,逐层分解,最后
# 按照左列表+中间值+右列表的方式,逐层合并。
# 需要用到递归。简单起见,取第一个值为中间值
def quicksort(urls,ranks):
    if len(urls) < 2:
        return urls
    pivot = urls[0]
    lower = []
    greater = []
    for url in urls[1:]:
        if ranks[url] >= ranks[pivot]:
            lower.append(url)
        else:
            greater.append(url)
    return quicksort(lower, ranks) + [pivot] + quicksort(greater, ranks)

def ordered_search(index, ranks, keyword):
    if keyword not in index:
        return None
    return quicksort(index[keyword], ranks)
In [34]:
# test_case
cache = {
   'http://udacity.com/cs101x/urank/index.html': """<html>
<body>
<h1>Dave's Cooking Algorithms</h1>
<p>
Here are my favorite recipes:
<ul>
<li> <a href="http://udacity.com/cs101x/urank/hummus.html">Hummus Recipe</a>
<li> <a href="http://udacity.com/cs101x/urank/arsenic.html">World's Best Hummus</a>
<li> <a href="http://udacity.com/cs101x/urank/kathleen.html">Kathleen's Hummus Recipe</a>
</ul>

For more expert opinions, check out the 
<a href="http://udacity.com/cs101x/urank/nickel.html">Nickel Chef</a> 
and <a href="http://udacity.com/cs101x/urank/zinc.html">Zinc Chef</a>.
</body>
</html>






""", 
   'http://udacity.com/cs101x/urank/zinc.html': """<html>
<body>
<h1>The Zinc Chef</h1>
<p>
I learned everything I know from 
<a href="http://udacity.com/cs101x/urank/nickel.html">the Nickel Chef</a>.
</p>
<p>
For great hummus, try 
<a href="http://udacity.com/cs101x/urank/arsenic.html">this recipe</a>.

</body>
</html>






""", 
   'http://udacity.com/cs101x/urank/nickel.html': """<html>
<body>
<h1>The Nickel Chef</h1>
<p>
This is the
<a href="http://udacity.com/cs101x/urank/kathleen.html">
best Hummus recipe!
</a>

</body>
</html>






""", 
   'http://udacity.com/cs101x/urank/kathleen.html': """<html>
<body>
<h1>
Kathleen's Hummus Recipe
</h1>
<p>

<ol>
<li> Open a can of garbanzo beans.
<li> Crush them in a blender.
<li> Add 3 tablespoons of tahini sauce.
<li> Squeeze in one lemon.
<li> Add salt, pepper, and buttercream frosting to taste.
</ol>

</body>
</html>

""", 
   'http://udacity.com/cs101x/urank/arsenic.html': """<html>
<body>
<h1>
The Arsenic Chef's World Famous Hummus Recipe
</h1>
<p>

<ol>
<li> Kidnap the <a href="http://udacity.com/cs101x/urank/nickel.html">Nickel Chef</a>.
<li> Force her to make hummus for you.
</ol>

</body>
</html>

""", 
   'http://udacity.com/cs101x/urank/hummus.html': """<html>
<body>
<h1>
Hummus Recipe
</h1>
<p>

<ol>
<li> Go to the store and buy a container of hummus.
<li> Open it.
</ol>

</body>
</html>




""", 
}

def get_page(url):
    if url in cache:
        return cache[url]
    else:
        return None

index , graph = crawl_web('http://udacity.com/cs101x/urank/index.html') 

if 'http://udacity.com/cs101x/urank/index.html' in graph:
    print graph['http://udacity.com/cs101x/urank/index.html']
#>>> ['http://udacity.com/cs101x/urank/hummus.html',
#'http://udacity.com/cs101x/urank/arsenic.html',
#'http://udacity.com/cs101x/urank/kathleen.html',
#'http://udacity.com/cs101x/urank/nickel.html',
#'http://udacity.com/cs101x/urank/zinc.html']

index, graph = crawl_web('http://udacity.com/cs101x/urank/index.html')
ranks = compute_ranks(graph)
print ranks

#>>> {'http://udacity.com/cs101x/urank/kathleen.html': 0.11661866666666663,
#'http://udacity.com/cs101x/urank/zinc.html': 0.038666666666666655,
#'http://udacity.com/cs101x/urank/hummus.html': 0.038666666666666655,
#'http://udacity.com/cs101x/urank/arsenic.html': 0.054133333333333325,
#'http://udacity.com/cs101x/urank/index.html': 0.033333333333333326,
#'http://udacity.com/cs101x/urank/nickel.html': 0.09743999999999997}

print lucky_search(index, ranks, 'Hummus')
#>>> http://udacity.com/cs101x/urank/kathleen.html

print lucky_search(index, ranks, 'the')
#>>> http://udacity.com/cs101x/urank/nickel.html

print lucky_search(index, ranks, 'babaganoush')
#>>> None

print ordered_search(index, ranks, 'Hummus')
#>>> ['http://udacity.com/cs101x/urank/kathleen.html',
#    'http://udacity.com/cs101x/urank/nickel.html',
#    'http://udacity.com/cs101x/urank/arsenic.html',
#    'http://udacity.com/cs101x/urank/hummus.html',
#    'http://udacity.com/cs101x/urank/index.html']

print ordered_search(index, ranks, 'the')
#>>> ['http://udacity.com/cs101x/urank/nickel.html',
#    'http://udacity.com/cs101x/urank/arsenic.html',
#    'http://udacity.com/cs101x/urank/hummus.html',
#    'http://udacity.com/cs101x/urank/index.html']


print ordered_search(index, ranks, 'babaganoush')
#>>> None
['http://udacity.com/cs101x/urank/hummus.html', 'http://udacity.com/cs101x/urank/arsenic.html', 'http://udacity.com/cs101x/urank/kathleen.html', 'http://udacity.com/cs101x/urank/nickel.html', 'http://udacity.com/cs101x/urank/zinc.html']
{'http://udacity.com/cs101x/urank/kathleen.html': 0.11661866666666663, 'http://udacity.com/cs101x/urank/zinc.html': 0.038666666666666655, 'http://udacity.com/cs101x/urank/hummus.html': 0.038666666666666655, 'http://udacity.com/cs101x/urank/arsenic.html': 0.054133333333333325, 'http://udacity.com/cs101x/urank/index.html': 0.033333333333333326, 'http://udacity.com/cs101x/urank/nickel.html': 0.09743999999999997}
http://udacity.com/cs101x/urank/kathleen.html
http://udacity.com/cs101x/urank/nickel.html
None
['http://udacity.com/cs101x/urank/kathleen.html', 'http://udacity.com/cs101x/urank/nickel.html', 'http://udacity.com/cs101x/urank/arsenic.html', 'http://udacity.com/cs101x/urank/hummus.html', 'http://udacity.com/cs101x/urank/index.html']
['http://udacity.com/cs101x/urank/nickel.html', 'http://udacity.com/cs101x/urank/arsenic.html', 'http://udacity.com/cs101x/urank/hummus.html', 'http://udacity.com/cs101x/urank/index.html']
None

类

In [1]:
## 编写一个迭代器
class FibIterable:
    """
    this class is a generates a well known sequence of numbers 
    """
    def __init__(self,iLast=1,iSecondLast=0,iMax=50):
        self.iLast = iLast 
        self.iSecondLast = iSecondLast
        self.iMax = iMax  #cutoff
    def __iter__(self):
        return self    # because the object is both the iterable and the itorator
    def next(self):
        iNext = self.iLast + self.iSecondLast
        if iNext > self.iMax:
            raise StopIteration()
        self.iSecondLast = self.iLast
        self.iLast = iNext
        return iNext

o = FibIterable()
for i in o:
    print(i)
1
2
3
5
8
13
21
34
In [ ]: