スタックとキューの理論的基礎

スタックとキューの理論的基礎

1. スタックとキューの違い

(1) Python のリストは連結リストの形式で実装されるため、Python のリストを作成する際にデータ構造やリストの長さを指定する必要がなく、それに応じて配列も作成時に宣言する必要があります。
. データ型、配列の長さも指定する必要があります

(2) メモリアドレス:
リスト: 不連続
配列: 連続

(3) データ型
リスト: 内部の要素は任意のデータ型にすることができます
配列: 同じ型

配列内のデータ型はすべて同じであるため、配列内のすべての項目は同じデータ型を持ち、演算は各要素に対して同じように動作します。したがって、配列は、多数の同種のデータ型を扱う場合に非常に役立ちますPython は各要素のデータ型の詳細を個別に記憶する必要がないため、配列はリストよりも高速で、使用するメモリも少なくなります。

  • スタックとキューは 2 つの基本的なデータ構造であり、どちらもコンテナ タイプです。2 つの違いは次のとおりです。
    スタック: 後入れ先出し
    ここに画像の説明を挿入します

キュー: 先入れ先出し
ここに画像の説明を挿入します

注: スタックとキューは、特定の位置にある要素をクエリして操作することはできません。しかし、彼らの配置はきちんとしている

2. Pythonでのスタックの実装

スタックの場合、Python の組み込みリスト実装を使用できます。リストは線形配列であり、最後に要素を挿入および削除するのにかかる時間は O(1) であり、スタックの要件と非常に一致しています。もちろん、リストを使用することもできます。スタックの実装コード (Python の組み込みリストを使用) は実装が簡単で、次のとおりです。

class Stack(object):
    def __init__(self):
        self.stack = []
    
    def push(self,value):  #进栈
        self.stack.append(value)
    
    def pop(self):   #出栈
        if self.stack:
            self.stack.pop()
        else:
            raise LookupError('stack is empty') #无效数据查询
    
    def is_empty(self): ##判断栈是否为空
        return bool(self.stack)
    
    def top(self): #取出栈中最新的元素
        return self.stack[-1]

3. キューの実装

キューのデータ構造を実装するために次のリンク リストを定義します。
ここに画像の説明を挿入します

左側がキューの先頭を指し、右側がキューの末尾を指すようにヘッド ノードを定義します。これにより、要素の挿入と要素の取り出しが両方とも O(1) 操作になることが保証されます。この種のリンク リストを使用してキューを実装すると非常に便利です。

class Head(object):
    def __init__(self):
        self.left = None
        self.right = None

    def Node(object):
        def __init__(self,value):
            self.value = value
            self.next = None

class queue(object):
    def __init__(self):
        #初始化节点
        self.head = Head()
    
    def enqueue(self,value):
        #插入一个元素
        newnode = Node(value)
        p = self.head
        if p.right:
            #如果head节点的右边不为None,
            #说明队列中有其他元素
            temp = p.right
            temp.next = newnode
            p.right = newnode
        else:
            #此时说明队列为空
            p.right = newnode
            p.left = newnode
    
    def dequeue(self):
        #取出一个元素
        p = self.head
        if p.left and (p.left == p.right):
            #说明队中只有一个元素
            temp = p.left
            p.left = p.right = None
            return temp.value
        elif p.left and (p.left != p.right):
            #说明队中不只一个元素
            temp = p.left
            p.left = temp.next
            return temp.value
        else:
            #说明队列为空
            raise LookupError('queue is empty!')
    
    def is_empty(self):
        if self.head.left:
            return False
        else:
            return True
    
    def top(self):
        #查询队列中最先入队的元素
        if self.head.left:
            return self.head.left.value
        else:
            raise LookupError('queue is empty!')

4.Python の組み込みヒープ、スタック、キュー

まとめ

ここに画像の説明を挿入します

具体的な用途

heapq ヒープキュー

heapq は組み込みのヒープ構造であり、親ノードの値が常に子ノードよりも大きい完全なバイナリ ツリーの特別な形式です。そのプロパティに従って、Python は heap[k] <= を満たすものを使用できます。 heap[2 * k + 1] < = heap[2 * k + 2] リストを取得します。Heapq は最小ヒープです。最大ヒープを達成したい場合は、いくつかのトリックを使用できます。たとえば、heappush のときにデータ * -1 を入力し、heappop のときにポップされた要素に -1 を乗算します。

import heapq

heap = []
heapq.heappush(heap, 3)
heapq.heappush(heap, 2)
heapq.heappush(heap, 1)
print(heap)  # 输出为 [1, 3, 2]

# 要想有序输出 堆的元素
heapq.heappop(heap) # 输出1
heapq.heappop(heap) # 输出2
heapq.heappop(heap) # 输出3

# 要想输出前n个最大值,前n个最小值,可以使用
heapq.nlargest(n, heap)
heapq.nsmallest(n, heap)
DEQUE 両端キュー

from collections import deque は、スタック関数またはキュー関数を実装できます。両端のキューはキューの先頭と末尾で編集できるため、Python でスタック関数を実装したい場合、最良の選択は deque です。通常の配列構造を使用します。

通常のキュー操作では、キューの最後に要素を挿入し、次に要素を先頭からポップします。

dq = queue()
dq.append(3)  # deque([3])
dq.append(4)  # deque([3, 4])
dq.popleft() # 弹出 3,并且dq为 deque([4])
如果设置为一个栈的话,FILO,那么就是如下的代码

dq = queue()
dq.append(3)  # deque([3])
dq.append(4)  # deque([3, 4])
dq.pop() # 弹出 4,并且dq为 deque([3])

Queue キューはスレッドセーフなパッケージです。このパッケージには、スタック LifoQueue などの多くの構造があります。並行環境で使用する場合は、この構造を使用するのが最善です。スタックが空の場合、最上位のスタックの要素がポップされると、スタックが空でなくなるまでブロックが発生します。

リフォキュー

LifoQueue はプッシュ操作と終了操作を備えたスタック構造で、メソッドはそれぞれ put() と get() であり、LifoQueue() が空の場合は get() がブロックされます。

from queue import LifoQueue

s = LifoQueue()
s.put(3)
s.put(4)
print(s.get()) # 打印4
print(s.get()) # 打印3
print(s.get()) # 一直等待直到s中存在元素,然后就打印退出

Queue は、エンキュー操作とデキュー操作を行うキューです。メソッドはそれぞれ put() と get() で、キューが空の場合、get() はブロックされます。さらに、キューの長さも設定できます。キューの長さが設定されていない場合、またはキューの長さを 0 以下の数値に設定した場合、キューの長さは無限になります。キューの最大長は .maxsize 属性を通じて取得できます。

from queue import Queue

q = Queue()
q.put(3)
q.put(4)
print(q.get()) # 打印3
print(q.get()) # 打印4
print(q.get()) # 一直等待直到q中存在元素,然后就打印退出
print(q.get_nowait()) # 如果队列q为空,那么不会等待,而是输出 Empty 的异常
優先キュー

PriorityQueue は優先キューです。キューの要素はソートされているため、ソートされたシーケンスに優先キューを使用すると、最大または最小の要素を効率的に取得できます。
スケジューリングの問題のシナリオでは、プライオリティ キューがよく使用されます。主に、最大値または最小値を取得する操作とキューに入れる操作が含まれます。プライオリティ キューは、内部で heapq をカプセル化します。違いは、プライオリティ キューがスレッドセーフであることと、プライオリティ キューがスレッドセーフであることです
。環境では、PriorityQueue の使用を選択する必要があります。

from queue import PriorityQueue

pq = PriorityQueue()
pq.put((2, 'name'))
pq.put((1, 'age'))
pq.put((3, 'job'))
while not pq.empty():
    print(pq.get())

"""
输出内容如下
(1, "age")
(2, "name")
(3, "job")
"""
マルチプロセッシング.キュー

キューのマルチプロセス バージョン multiprocessing.Quque。マルチプロセス環境でキューを使用する場合は、 multiprocessing.Queue を選択する必要があります。
そのエンキュー操作とデキュー操作はそれぞれ put() と get() です。


参考文章:
[1] https://blog.csdn.net/weixin_43026262/article/details/104291381
[2] https://www.jianshu.com/p/9b94651534c3
[3] https://zhuanlan.zhihu. com/p/110424854

おすすめ

転載: blog.csdn.net/qq_42859625/article/details/129487213