數據結構與算法(一):一些基礎吧

 數據結構和算法是什麼?html

算法啊,就是獨立存在的一種解決問題的一個思想node

算法的五大特性:python

  • 輸入:算法具備0個或者多個輸入
  • 輸出:算法至少有1個或者多個輸出
  • 有窮性:算法在有限的步驟以後會自動結束而不會無限循環,而且每個步驟能夠在可接受的時間內完成。
  • 肯定性:算法中的每一步都有肯定的含義,不會出現二義性
  • 可行性:算法的每一步都是可行的,也就是說每一步都可以執行有限的次數完成

引入:首先,咱們先來看一道題算法

注意:這裏的^2表明 平方 數據結構

# 三重循環
for a in range(0, 1001):
    for b in range(0, 1001):
        for c in range(0, 1001):
            if a**2 + b**2 == c**2 and a+b+c == 1000:
                print("a, b, c: %d, %d, %d" % (a, b, c))
最容易想到的一種方法

而後,咱們調用time模塊進行一個簡單的計時app

import time

start_time = time.time()

最容易想到的一種方法

end_time = time.time()

print("執行時間:",end_time-start_time)

因而呢,你就會驚奇的發現竟然總共執行了200多秒.......數據結構和算法

咱們優化一下代碼ide

import time

start_time = time.time()

# 注意是兩重循環
for a in range(0, 1001):
    for b in range(0, 1001-a):
        c = 1000 - a - b
        if a**2 + b**2 == c**2:
            print("a, b, c: %d, %d, %d" % (a, b, c))

end_time = time.time()

print("執行時間:",end_time-start_time)

而後看一下結果........函數

僅僅只執行了0.x秒,形成這個的緣由僅僅只是我去掉了一層的循環性能

 兩種算法,爲什麼會有如此之大的差距呢?

算法效率的衡量

1.執行時間反應算法的效率:實現算法程序的執行時間能夠反應出算法的效率,即算法的優劣

2.但靠時間比較算法的優劣比不必定可靠:硬件的基礎一樣會影響執行的時間

時間複雜度與"大O記法"

大O記法:對於單調的整數函數f,若是存在一個整數函數g和實常數c>0,使
得對於充分大的n總有f(n)<=c*g(n),就說函數g是f的一個漸近函數(忽略常
數),記爲f(n)=O(g(n))。也就是說,在趨向無窮的極限意義下,函數f的增加
速度受到函數g的約束,亦即函數f與函數g的特徵類似。
時間複雜度:假設存在函數g,使得算法A處理規模爲n的問題示例所用時間爲
T(n)=O(g(n)),則稱O(g(n))爲算法A的漸近時間複雜度,簡稱時間複雜度,
記爲T(n)

對大O算法的理解

對於算法進行特別具體的細緻分析雖然很好,但在實踐中的實際價值有限。對於
算法的時間性質和空間性質,最重要的是其數量級和趨勢,這些是分析算法效率
的主要部分。而計量算法基本操做數量的規模函數中那些常量因子能夠忽略不
計。例如,能夠認爲3n2和100n2屬於同一個量級,若是兩個算法處理一樣規
模實例的代價分別爲這兩個函數,就認爲它們的效率「差很少」,都爲n2級。

最壞時間的複雜度

  • 算法完成工做最少須要多少基本操做,即最優時間複雜度
  • 算法完成工做最多須要多少基本操做,即最壞時間複雜度
  • 算法完成工做平均須要多少基本操做,即平均時間複雜度

咱們主要關注算法的最壞狀況,即最壞時間複雜度

時間複雜度的幾條基本計算規則

  • 基本格式,只有常數項,認爲其時間複雜度爲O(1)
  • 順序結構,時間複雜度按加法進行計算
  • 循環結構,時間複雜度按乘法進行計算
  • 分支結構,時間複雜度取最大值
  • 判斷一個算法的效率時,每每只須要關注操做數量的最高次項,其它次要項和常數項能夠忽略
  • 在沒有特殊說明時,咱們所分析的算法時間複雜度都是指最壞時間複雜度

仍是上面那個算法例子

1.

for a in range(0, 1001):
    for b in range(0, 1001):
        for c in range(0, 1001):
            if a**2 + b**2 == c**2 and a+b+c == 1000:
                print("a, b, c: %d, %d, %d" % (a, b, c))

三次循環,他的時間複雜度爲:T(n) = O(n*n*n) = O(n3

2.

for a in range(0, 1001):
    for b in range(0, 1001-a):
        c = 1000 - a - b
        if a**2 + b**2 == c**2:
            print("a, b, c: %d, %d, %d" % (a, b, c))

兩次循環,他的時間複雜度爲:T(n) = O(n*n*(1+1)) = O(n*n) = O(n2)

因而可知啊,咱們嘗試的第二種算法要比第一種算法的時間複雜度要好得多

常見的時間複雜度

注意:常常將log2n(以2爲底的對數)簡寫成logn

所消耗的時間從小到大

 O(1) < O(logn) < O(n) < O(nlogn) < O(n2) < O(n3) < O(2n) < O(n!) < O(nn)

 Python內置類型性能分析

 timeit模塊

 timeit模塊能夠用來測試一小段Python代碼的執行速度

  • Timer是測量小段代碼執行速度的類
  • stmt參數是要測試的代碼語句(statment)
  • setup參數是運行代碼時須要的設置
  • timer參數是一個定時器函數,與平臺有關

timeit.Timer.timeit(number=1000000)

List的測試操做

def t1():
    l = []
    for i in range(1000):
        l = l + [i]

def t2():
    l = []
    for i in range(1000):
        l.append(i)

def t3():
    l = [i for i in range(1000)]

def t4():
    l = list(range(1000))


from timeit import Timer



test1 = Timer("t1()","from __main__ import t1")
print('result1:',test1.timeit(number=100),'seconds')


test2 = Timer("t2()","from __main__ import t2")
print('result2:',test2.timeit(number=100),'seconds')


test3 = Timer("t3()","from __main__ import t3")
print('result3:',test3.timeit(number=100),'seconds')


test4 = Timer("t4()","from __main__ import t4")
print('result4:',test4.timeit(number=100),'seconds')

因爲時間的問題,在這裏我每一個只測試了100次,number=100

即便次數很少們也能明顯的看出速度的差距。

pop的測試操做

from timeit import Timer

x = list(range(1000000))
pop_test1 = Timer("x.pop(0)","from __main__ import x")
print("POP Test1:",pop_test1.timeit(number=1000))

x = list(range(1000000))
pop_test2 = Timer("x.pop()","from __main__ import x")
print("POP Test2:",pop_test2.timeit(number=1000))

此時結果:

結果很是的明顯:pop最後一個元素的效率遠遠高於pop第一個元素

 數據結構

問題:咱們若是用Python中的類型來保存一個班的學生信息呢?若是想要快速的經過學生姓名獲取到其餘的信息呢?

實際上當咱們在思考這個問題的時候,咱們已經用到了數據結構。列表和字典均可以存儲一個班的學生信息,可是想要在列表
中獲取一名同窗的信息時,就要遍歷這個列表,其時間複雜度爲O(n),而使用字典存儲時,可將學生姓名做爲字典的鍵,學
生信息做爲值,進而查詢時不須要遍歷即可快速獲取到學生信息,其時間複雜度爲O(
1)。
咱們爲了解決問題,須要將數據保存下來,而後根據數據的存儲方式來設計算法實現進行處理,那麼數據的存儲方式不一樣就
會致使須要不一樣的算法進行處理。咱們但願算法解決問題的效率越快越好,因而咱們就須要考慮數據究竟如何保存的問
題,這就是數據結構。 在上面的問題中咱們能夠選擇Python中的列表或字典來存儲學生信息。列表和字典就是Python內建幫咱們封裝好的兩種
數據結構。

概念

數據是一個抽象的概念,將其進行分類後獲得程序設計語言中的基本類型。如:int,float,char等。

數據元素之間不是獨立的,存在這特定的關係,這些關係即是結構。

數據結構指數據對象中數據元素之間的關係。

Python中給咱們提供了不少現成的數據結構類型,這些系統本身定義好的,不須要咱們本身去定義的數據結構叫作Python的內置數據結構,好比:列表、元組、字典。而有些數據組織方式,Python系統類並無直接的定義,須要咱們本身去定義實現這些數據則組織方式,這些數據組織方式稱之爲Python拓展數據結構,好比棧、隊列等

算法與數據結構的區別

數據結構只是靜態的描述了數據元素之間的關係。

高效的程序須要在數據結構的基礎上設計和選擇算法

程序 = 數據結構 + 算法

總結:算法是爲了解決實際問題而設計的,數據結構是算法須要處理的問題的載體

 

抽象的數據類型

抽象數據類型(ADT)的含義是指一個數學模型以及定義在此數據模型上的一組操做。即把數據類型和數據類型上的運算捆在一塊兒,進行封裝。引入抽象數據類型的目的是把數據類型表示和數據類型上運算的實現與這些數據類型和運算在程序中的引用隔開,使它們互相獨立。

最經常使用的數據運算:

  • 插入
  • 刪除
  • 修改
  • 查找
  • 排序

順序表

在程序中,常常須要將一組(一般是同爲某個類型的)數據元素做爲總體管理和使用,須要建立這樣的元素組,用變量去記錄他們,傳進傳出函數等。一組數據中包含的元素個數可能發生變化(能夠增長或者刪除元素)

 

對於這種需求,最簡單的解決方案即是將這樣一組元素當作一個序列,用元素在序列中的位置和順序,表示時間應用中的某種有意義的信息,或者表示數據之間的某種關係。

 

這樣一組序列元素的組織形式,咱們能夠將其抽象爲線性表。一個線性表是某類元素的一個集合,還記錄着元素之間的一種順序關係。

線性表是最基本的數據結構之一,在實際程序中應用的很是普遍,它還常常被用做更復雜的數據結構的實現基礎。

根據線性表的實際存儲方式,分爲兩種實現模型:

  • 順序表,將元素順序的存放在一塊連續的存儲區裏,元素間的順序關係由他們的存儲順序天然表示
  • 鏈表,將元素存放在經過連接構造起來的一系列存儲塊中

 順序表詳解

Python中的順序表

Python中的list和tuple兩種類型均採用了順序表的實現技術,既有順序表的全部性質。

tuple是不可變類型,即一個不變的順序表,所以不支持改變其內部狀態的任何操做,而其餘方面,則與list類似

list的基本實現技術

Python標準類型list就是一種元素個數可變的線性表,能夠加入和刪除元素,並在各類操做中維持已有的順序(即保序),並且還具備如下的行爲特徵:

  • 基於下標(位置)的高效元素訪問和更新,時間複雜度應該是O(1),爲知足該特徵,應該採用順序表技術,表中元素保存在一塊連續的存儲區中。
  • 容許任意加入元素,並且在不斷加入元素的過程當中,表對象的標識(函數id獲得的值)不變。爲了知足該特徵,就必須能更換元素存儲區,而且爲保證更換存儲區時list對象的標識id不變,只能採用分離式實現技術。

在Python的官方實現中,list就是一種採用分離式技術實現的動態順序表。這就是爲啥用list.append(x) (或list.insert(len(list),x),即尾部插入)比在指定位置插入元素的效率高的緣由。

在Python的官方中,list的實現採用了以下的策略:在創建空表(或者很小的表)時,系統分配一塊能容納8個元素的存儲
區;在執行插入操做(insert或者append)時,若是元素存儲區滿了就換一塊4倍大的存儲區。但若是此時的表已經很大
了(閾值爲50000),則改變策略,採用加一倍的方法。引入這種改策略的方式,是爲了不出現過多的空閒的存儲位置。

 鏈表

 

爲何須要鏈表?

順序表的構建須要預先知道數據大小來申請連續的存儲空間,而在進行擴充時又須要進行數據的搬遷,因此使用起來並非很
靈活。

鏈表結構能夠充分利用計算機內存空間,實現靈活的內存動態管理。

鏈表的定義

鏈表(Linked list)是一種常見的基礎數據結構,是一種線性表,可是不像順序表同樣連續存儲數據,而是在每個節點(數據存儲單元)裏存放下一個節點的位置信息(即地址)。

單向鏈表

 單向鏈表也叫作單鏈表,是鏈表中最簡單的一種形式,它每一個節點包含兩個域,一個信息域(元素域)和一個鏈表域。這個鏈表指向鏈表種的下一個節點,而最後一個節點則指向了一個空值。

 

  • 表元素域elem用來存放具體的數據
  • 鏈表域next用來存放下一個節點的位置(Python的標識)
  • 變量p指向鏈表的頭節點(首節點)的位置,從p觸發去找表中的節點。

 節點的實現(一個例子):

class SingleNode(object):
    '''單鏈表的節點'''
    def __init__(self,item):
        #_item用於存放數據文件
        self.item = item
        #_next是下一個節點的標識
        self._next = None

單鏈表的操做:

  •  is_empty()    鏈表是否爲空
  • length()    鏈表長度
  • travel()   遍歷整個鏈表
  • add(item)       鏈表頭部添加元素
  • append(item)  鏈表尾部添加元素
  • insert(pos,item)    在指定位置添加元素
  • remove(item)      刪除節點
  • search(item)        查找節點是否存在

單鏈表的實現(一個例子):

class SingleLinkList(object):
    '''單鏈表'''
    def __init__(self):
        self._head = None

    def is_empty(self):
        '''判斷鏈表是否爲空'''
        return self._head == None

    def length(self):
        '''鏈表長度'''
        cur = self._head    #初始時指向頭節點
        count = 0
        #尾節點指向None,當未達到尾部時
        while cur != None:
            count += 1
            cur = cur.next
        return count

    def travel(self):
        '''遍歷鏈表'''
        cur = self._head
        while cur != None:
            print(cur.item)
            cur = cur.next
        print('')

頭部添加元素的方法:

def add(self,item):
    '''頭部添加元素'''
    #先建立一個保存item值的節點
    node = SingleNode(item)
    #將新節點的連接域next指向頭節點,即_head指向的位置
    node.next = self._head
    # 將鏈表的頭_head指向新節點
    self._head = node

 尾部添加元素的方法:

def append(self,item):
    '''尾部添加元素'''
    node = SingleNode(item)
    #首先判斷鏈表是否爲空,如果空鏈表,則將_head指向新的節點
    if self.is_empty():
        self._head = node

    #如果不爲空,則找到尾部,將尾部的next指向新的節點
    else:
        cur = self._head
        while cur.next != None:
            cur = cur.next
        cur.next = node

指定位置添加元素

def insert(self,pos,item):
    '''指定位置添加元素'''
    #若指定位置pos爲第一個元素以前,則執行頭部插入
    if pos <= 0:
        self.add(item)

    #若指定位置超過鏈表尾部,則執行尾部插入
    elif pos > (self.length()-1):
        self.append(item)
    
    #找到指定的位置
    else:
        node = SingleNode(item)
        count = 0
        #pre用來指向指定位置pos的前一個位置pos-1,初始從頭節點開始移動到指定位置
        pre = self._head
        while count < (pos-1):
            count += 1
            pre = pre.next
        #先將新節點node的next指向插入位置的節點
        node.next = pre.next
        #將插入位置的前一個節點的next指向新節點
        pre.next = node

刪除節點

    def remove(self,item):
        """刪除節點"""
        cur = self._head
        pre = None
        while cur != None:
            # 找到了指定元素
            if cur.item == item:
                # 若是第一個就是刪除的節點
                if not pre:
                    # 將頭指針指向頭節點的後一個節點
                    self._head = cur.next
                else:
                    # 將刪除位置前一個節點的next指向刪除位置的後一個節點
                    pre.next = cur.next
                break
            else:
                # 繼續按鏈表後移節點
                pre = cur
                cur = cur.next

查找節點是否存在

    def search(self,item):
        """鏈表查找節點是否存在,並返回True或者False"""
        cur = self._head
        while cur != None:
            if cur.item == item:
                return True
            cur = cur.next
        return False

鏈表與順序表的對比

鏈表失去了順序表隨機讀取的優勢,同時鏈表因爲增長了節點的指針域,空間開銷比較大,但對於存儲空間的使用要相對靈活。

鏈表與順序表的各類操做複雜度以下:

注意雖然表面看起來複雜度都是 O(n),可是鏈表和順序表在插入和刪除時進行的是徹底不一樣的操做。鏈表的主要耗時操做是
遍歷查找,刪除和插入操做自己的複雜度是O(1)。順序表查找很快,主要耗時的操做是拷貝覆蓋。由於除了目標元素在尾部
的特殊狀況,順序表進行插入和刪除時須要對操做點以後的全部元素進行先後移位操做,只能經過拷貝和覆蓋的方法進行。

單向循環鏈表

單列表的一個變形是單向循環鏈表,鏈表中最後一個節點的next域再也不爲None,而是執行鏈表的頭節點

操做:

  • is_empty()判斷鏈表是否爲空
  • length()返回鏈表的長度
  • trave()遍歷
  • add(item)在頭部添加一個節點
  • append(item)在尾部添加一個節點
  • insert(pos,item)在指定位置pos添加節點
  • remove(item)刪除一個節點
  • search(item)查找節點是否存在

實現:

#單項循環列表
class Node(object):
    """節點"""
    def __init__(self, item):
        self.item = item
        self.next = None


class SinCycLinkedlist(object):
    """單向循環鏈表"""
    def __init__(self):
        self._head = None

    def is_empty(self):
        """判斷鏈表是否爲空"""
        return self._head == None

    def length(self):
        """返回鏈表的長度"""
        # 若是鏈表爲空,返回長度0
        if self.is_empty():
            return 0
        count = 1
        cur = self._head
        while cur.next != self._head:
            count += 1
            cur = cur.next
        return count

    def travel(self):
        """遍歷鏈表"""
        if self.is_empty():
            return
        cur = self._head
        print(cur.item)
        while cur.next != self._head:
            cur = cur.next
            print(cur.item)
        print("")


    def add(self, item):
        """頭部添加節點"""
        node = Node(item)
        if self.is_empty():
            self._head = node
            node.next = self._head
        else:
            #添加的節點指向_head
            node.next = self._head
            # 移到鏈表尾部,將尾部節點的next指向node
            cur = self._head
            while cur.next != self._head:
                cur = cur.next
            cur.next = node
            #_head指向添加node的
            self._head = node

    def append(self, item):
        """尾部添加節點"""
        node = Node(item)
        if self.is_empty():
            self._head = node
            node.next = self._head
        else:
            # 移到鏈表尾部
            cur = self._head
            while cur.next != self._head:
                cur = cur.next
            # 將尾節點指向node
            cur.next = node
            # 將node指向頭節點_head
            node.next = self._head

    def insert(self, pos, item):
        """在指定位置添加節點"""
        if pos <= 0:
            self.add(item)
        elif pos > (self.length()-1):
            self.append(item)
        else:
            node = Node(item)
            cur = self._head
            count = 0
            # 移動到指定位置的前一個位置
            while count < (pos-1):
                count += 1
                cur = cur.next
            node.next = cur.next
            cur.next = node

    def remove(self, item):
        """刪除一個節點"""
        # 若鏈表爲空,則直接返回
        if self.is_empty():
            return
        # 將cur指向頭節點
        cur = self._head
        pre = None
        # 若頭節點的元素就是要查找的元素item
        if cur.item == item:
            # 若是鏈表不止一個節點
            if cur.next != self._head:
                # 先找到尾節點,將尾節點的next指向第二個節點
                while cur.next != self._head:
                    cur = cur.next
                # cur指向了尾節點
                cur.next = self._head.next
                self._head = self._head.next
            else:
                # 鏈表只有一個節點
                self._head = None
        else:
            pre = self._head
            # 第一個節點不是要刪除的
            while cur.next != self._head:
                # 找到了要刪除的元素
                if cur.item == item:
                    # 刪除
                    pre.next = cur.next
                    return
                else:
                    pre = cur
                    cur = cur.next
            # cur 指向尾節點
            if cur.item == item:
                # 尾部刪除
                pre.next = cur.next

    def search(self, item):
        """查找節點是否存在"""
        if self.is_empty():
            return False
        cur = self._head
        if cur.item == item:
            return True
        while cur.next != self._head:
            cur = cur.next
            if cur.item == item:
                return True
        return False

測試:

ll = SinCycLinkedlist()
ll.add(1)
ll.add(2)
ll.append(3)
ll.insert(2, 4)
ll.insert(4, 5)
ll.insert(0, 6)
print("length:",ll.length())
ll.travel()
print(ll.search(3))
print(ll.search(7))
ll.remove(1)
print("length:",ll.length())
ll.travel()

結果:


雙向鏈表

 雙向鏈表又稱爲「雙面列表」。

每個節點都有連個連接:一個指向前一個節點,當此節點成爲第一個節點時,指向空值;而另外一個指向下一個節點,當此節點爲最後一個節點時,指向空值。

操做:

  • is_empty()鏈表是否爲空
  • length()鏈表長度
  • travel()遍歷鏈表
  • add(item)鏈表頭部添加
  • append(item)鏈表尾部添加
  • insert(pos,item)鏈表指定位置添加
  • remove(item)刪除指定節點
  • search(item)查找節點是否存在
#雙向鏈表
class Node(object):
    """雙向鏈表節點"""
    def __init__(self, item):
        self.item = item
        self.next = None
        self.prev = None


class DLinkList(object):
    """雙向鏈表"""
    def __init__(self):
        self._head = None

    def is_empty(self):
        """判斷鏈表是否爲空"""
        return self._head == None

    def length(self):
        """返回鏈表的長度"""
        cur = self._head
        count = 0
        while cur != None:
            count += 1
            cur = cur.next
        return count

    def travel(self):
        """遍歷鏈表"""
        cur = self._head
        while cur != None:
            print(cur.item)
            cur = cur.next
        print("")

    def add(self, item):
        """頭部插入元素"""
        node = Node(item)
        if self.is_empty():
            # 若是是空鏈表,將_head指向node
            self._head = node
        else:
            # 將node的next指向_head的頭節點
            node.next = self._head
            # 將_head的頭節點的prev指向node
            self._head.prev = node
            # 將_head 指向node
            self._head = node

    def append(self, item):
        """尾部插入元素"""
        node = Node(item)
        if self.is_empty():
            # 若是是空鏈表,將_head指向node
            self._head = node
        else:
            # 移動到鏈表尾部
            cur = self._head
            while cur.next != None:
                cur = cur.next
            # 將尾節點cur的next指向node
            cur.next = node
            # 將node的prev指向cur
            node.prev = cur



    def search(self, item):
        """查找元素是否存在"""
        cur = self._head
        while cur != None:
            if cur.item == item:
                return True
            cur = cur.next
        return False

    def insert(self, pos, item):
        """在指定位置添加節點"""
        if pos <= 0:
            self.add(item)
        elif pos > (self.length() - 1):
            self.append(item)
        else:
            node = Node(item)
            cur = self._head
            count = 0
            # 移動到指定位置的前一個位置
            while count < (pos - 1):
                count += 1
                cur = cur.next
            # 將node的prev指向cur
            node.prev = cur
            # 將node的next指向cur的下一個節點
            node.next = cur.next
            # 將cur的下一個節點的prev指向node
            cur.next.prev = node
            # 將cur的next指向node
            cur.next = node

    def remove(self, item):
        """刪除元素"""
        if self.is_empty():
            return
        else:
            cur = self._head
            if cur.item == item:
                # 若是首節點的元素便是要刪除的元素
                if cur.next == None:
                    # 若是鏈表只有這一個節點
                    self._head = None
                else:
                    # 將第二個節點的prev設置爲None
                    cur.next.prev = None
                    # 將_head指向第二個節點
                    self._head = cur.next
                return
            while cur != None:
                if cur.item == item:
                    # 將cur的前一個節點的next指向cur的後一個節點
                    cur.prev.next = cur.next
                    # 將cur的後一個節點的prev指向cur的前一個節點
                    cur.next.prev = cur.prev
                    break
                cur = cur.next
具體實現代碼

操做:

ll = DLinkList()
ll.add(1)
ll.add(2)
ll.append(3)
ll.insert(2, 4)
ll.insert(4, 5)
ll.insert(0, 6)
print("length:",ll.length())
ll.travel()
print(ll.search(3))
print(ll.search(4))
ll.remove(1)
print("length:",ll.length())
ll.travel()

結果:


棧,有些地方稱爲堆棧,是一種容器,能夠存入數據元素、訪問元素、刪除元素、他的特色在於只能容許容器的一端top,進行加入數據push和輸出數據pop。沒有了位置的概念,保證任什麼時候候能夠訪問、刪除的元素都是此前最後存入的那個元素,肯定了一種默認的訪問順序。

因爲棧數據結構只容許在一端進行操做,於是按照後進先出的原理運做

棧的操做:

  • Stack()建立一個新的空棧
  • push(item)添加一個元素item到棧頂
  • pop(item)彈出棧頂元素
  • peek()返回棧頂元素
  • is_empty()判斷棧是否爲空
  • size()返回棧的元素個數
class Stack(object):
    """"""
    def __init__(self):
         self.items = []

    def is_empty(self):
        """判斷是否爲空"""
        return self.items == []

    def push(self, item):
        """加入元素"""
        self.items.append(item)

    def pop(self):
        """彈出元素"""
        return self.items.pop()

    def peek(self):
        """返回棧頂元素"""
        return self.items[len(self.items)-1]

    def size(self):
        """返回棧的大小"""
        return len(self.items)

if __name__ == "__main__":
    stack = Stack()
    stack.push("hello")
    stack.push("world")
    stack.push("nullnull")
    print(stack.size())
    print(stack.peek())
    print(stack.pop())
    print(stack.pop())
    print(stack.pop())
代碼實現

隊列

 隊列(queue)是隻容許在一端進行插入操做,而在另外一端進行刪除操做的線性表。

 隊列是一種先進先出的線性表

操做:

  • Queue()建立一個空的隊列
  • enqueue(item)往隊列中添加一個item元素
  • dequeue()從隊列頭部刪除一個元素
  • is_empty()判斷一個隊列是否爲空
  • size()返回隊列的大小

實現:

class Queue(object):
    """隊列"""
    def __init__(self):
        self.items = []

    def is_empty(self):
        return self.items == []

    def enqueue(self, item):
        """進隊列"""
        self.items.insert(0,item)

    def dequeue(self):
        """出隊列"""
        return self.items.pop()

    def size(self):
        """返回大小"""
        return len(self.items)

if __name__ == "__main__":
    q = Queue()
    q.enqueue("hello")
    q.enqueue("world")
    q.enqueue("nullnull")
    print(q.size())
    print(q.dequeue())
    print(q.dequeue())
    print(q.dequeue())
隊列的實現

雙端隊列

 是一種具備隊列和棧的性質的數據結構。

 雙端隊列中的元素能夠從兩端彈出,其限定插入和刪除操做在表的兩端進行。雙端隊列能夠在隊列任意一端入隊和   出對。

操做:

  • Deque()建立一個空的雙端隊列
  • add_front(item)從對頭加入一個item元素
  • add_rear(item)從隊尾加入一個item元素
  • remove_front()從對頭刪除一個item元素
  • remove_rear()從隊尾刪除一個item元素
  • is_empty()判斷雙端隊列是否爲空
  • size()返回隊列的大小

實現:

class Deque(object):
    """雙端隊列"""
    def __init__(self):
        self.items = []

    def is_empty(self):
        """判斷隊列是否爲空"""
        return self.items == []

    def add_front(self, item):
        """在隊頭添加元素"""
        self.items.insert(0,item)

    def add_rear(self, item):
        """在隊尾添加元素"""
        self.items.append(item)

    def remove_front(self):
        """從隊頭刪除元素"""
        return self.items.pop(0)

    def remove_rear(self):
        """從隊尾刪除元素"""
        return self.items.pop()

    def size(self):
        """返回隊列大小"""
        return len(self.items)


if __name__ == "__main__":
    deque = Deque()
    deque.add_front(1)
    deque.add_front(2)
    deque.add_rear(3)
    deque.add_rear(4)
    print(deque.size())
    print(deque.remove_front())
    print(deque.remove_front())
    print(deque.remove_rear())
    print(deque.remove_rear())
具體代碼實現
相關文章
相關標籤/搜索