數據結構之鏈表與哈希表


一 什么是鏈表

鏈表是由一系列節點組成的元素集合。每個節點包含兩部分,數據域item和指向一下個節點的指針next。通過節點之間相互連接,最終串聯成一個鏈表

 二 鏈表的操作

1 創建鏈表

頭插法:

class Node:
    def __init__(self, item):
        self.item = item
        self.next = None


def create_linklist(li):
    head = Node(li[0])
    for element in li[1:]:
        node = Node(element)
        node.next = head
        head = node
    return head

尾插法:

2 鏈表的遍歷

def print_linklist(lk):
    while lk:
        print(lk.item, end=',')
        lk = lk.next


print_linklist(lk)

3 鏈表的插入與刪除

插入:

p.next = curNode.next
curNode.next = p

刪除:

#刪除:
p = curNode.next
curNode.next = p.next  #當前節點的下一個指向就指向他下一個的下一個
del p 

 三 雙向鏈表

雙鏈表的每個節點有兩個指針:一個指向后一個節點,另一個指向前一個節點。

class Node(object):
    def __init__(self, item=None):
        self.item = item
        self.next = None
        self.prior = None

1 雙向鏈表的結點插入

p.next = curNode.next
curNode.next.prior = p
p.prior = curNode
curNode.next = p

2 雙向鏈表的刪除

p = curNode.next
curNode.next = p.next
p.next.prior = curNode
del p

 四 哈希表

哈希表是一個通過哈希函數來計算數據存儲位置的數據結構,通常支持如下操作:

  • insert(key, value):插入鍵值對(key,value)
  • get(key): 如果存在鍵為key的鍵值對則返回其value, 否則返回空值
  • delete(key): 刪除鍵為key的鍵值對

1 直接尋址表

當關鍵字的全域U比較小時,直接尋址是一種簡單而有效的方法。

 

直接尋址技術缺點: 

  • 當域U很大時,需要消耗大量內存,很不實際
  • 如果域U很大而實際出現的key很少,則大量空間被浪費
  • 無法處理關鍵字不是數字的情況

2 哈希

改進直接尋址表:哈希(Hashing)

  • 構建大小為m的尋址表T
  • key為k的元素放到h(k)位置上
  • h(k)是一個函數,其將域U映射到表T[0,1,...,m-1]

哈希表(Hash Table,又稱為散列表),是一種線性表的存儲結構。哈希表由一個直接尋址表和一個哈希函數組成。哈希函數h(k)將元素關鍵字k作為自變量,返回元素的存儲下標。

假設有一個長度為7的哈希表,哈希函數h(k)=k%7。元素集合{14,22,3,5}的存儲方式如下圖。

比如h(k)=k%7, h(0)=h(7)=h(14)=...

 五 解決哈希沖突

由於哈希表的大小是有限的,而要存儲的值的總數量是無限的,因此對於任何哈希函數,都會出現兩個不同元素映射到同一個位置上的情況,這種情況叫做哈希沖突。

比如h(k)=k%7, h(0)=h(7)=h(14)=...

1 開放尋址法

開放尋址法:如果哈希函數返回的位置已經有值,則可以向后探查新的位置來存儲這個值。

線性探查:如果位置i被占用,則探查i+1, i+2,……

二次探查:如果位置i被占用,則探查i+12,i-12,i+22,i-22,……

二度哈希:有n個哈希函數,當使用第1個哈希函數h1發生沖突時,則嘗試使用h2,h3,……

2 拉鏈法

拉鏈法:哈希表每個位置都連接一個鏈表,當沖突發生時,沖突的元素將被加到該位置鏈表的最后。

3 常見的哈希函數

除法哈希法: h(k) = k % m

乘法哈希法: h(k) = floor(m*(A*key%1))

全域哈希法: ha,b(k) = ((a*key + b) mod p) mod m a,b=1,2,...,p-1

六 哈希表的應用---集合和字典

字典與集合都是通過哈希表來實現的
a = {'name':'Alex', 'age':18, 'gender':'Man'}
使用哈希表存儲字典, 通過哈希函數將字典映射為下標。假設h('name') =3, h('age')=1, h('gender')=4, 則哈希表存儲為[None, 18,None, 'Alex', 'Man']
如果發生哈希沖突,則通過拉鏈法或開發尋址方法解決

class LinkList:
    class Node:
        def __init__(self, item=None):
            self.item = item
            self.next = None

    class LinkListIterator:
        def __init__(self, node):
            self.node = node

        def __next__(self):
            if self.node:
                cur_node = self.node
                self.node = cur_node.next
                return cur_node.item
            else:
                raise StopIteration

        def __iter__(self):
            return self

    def __init__(self, iterable=None):
        self.head = None
        self.tail = None
        if iterable:
            self.extend(iterable)

    def append(self, obj):
        s = LinkList.Node(obj)
        if not self.head:
            self.head = s
            self.tail = s
        else:
            self.tail.next = s
            self.tail = s

    def extend(self, iterable):
        for obj in iterable:
            self.append(obj)

    def find(self, obj):
        for n in self:
            if n == obj:
                return True
        else:
            return False

    def __iter__(self):
        return self.LinkListIterator(self.head)

    def __repr__(self):
        return "<<" + ", ".join(map(str, self)) + ">>"


# 類似於集合的結構
class HashTable:
    def __init__(self, size=10):
        self.size = size
        self.T = [LinkList() for i in range(self.size)]

    def h(self, k):
        return k % self.size

    def insert(self, k):
        i = self.h(k)
        if self.find(k):
            print("Duplicated Insert.")
        else:
            self.T[i].append(k)

    def find(self, k):
        i = self.h(k)
        return self.T[i].find(k)

se = HashTable()

se.insert(10)
se.insert(11)
se.insert(12)
se.insert(100)
se.insert(200)
se.insert(300)

print(se.find(14))
print(se.T[0])

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM