পাইথনে ডিক্স কীভাবে প্রয়োগ করা হয় এবং এগুলি কখন তালিকার চেয়ে খারাপ হয়?


85

আমি আমার কোডটিকে আরও দক্ষ করার জন্য পাইথনে কীভাবে বিভিন্ন ডেটা স্ট্রাকচার প্রয়োগ করা হয় তা খতিয়ে দেখেছি। তালিকাগুলি এবং ডিক্স কীভাবে কাজ করে তা তদন্ত করতে গিয়ে আমি জানতে পেরেছিলাম যে আমি যখন ও (এন) থেকে তালিকাগুলিতে ও (1) এর সময়গুলিকে হ্রাস করতে চাইলে নামগুলি স্থির-দৈর্ঘ্যের অ্যারে হিসাবে কার্যকর করা হয় সেই তালিকাগুলি হ্রাস করতে এবং আনশিফট করতে চাইলে আমি সুবিধা পেতে পারি lists প্রতিবার সামনের দিকে কিছু isোকানো হলে পুরোপুরি অনুলিপি করা ইত্যাদি ...)। আমি যা দেখতে পাচ্ছি না তা হ'ল কোনও ডীক কীভাবে প্রয়োগ করা হয় তার নির্দিষ্টকরণ এবং এর ডাউনসাইড বনাম তালিকার বিশদ। এই দুটি প্রশ্নের মাধ্যমে কেউ আমাকে আলোকিত করতে পারে?

উত্তর:


74

https://github.com/python/cpython/blob/v3.8.1/Modules/_collectionsmodule.c

এ নোডগুলির dequeobjectদ্বিগুণ-সংযুক্ত তালিকার সমন্বয়ে গঠিত block

হ্যাঁ, dequeঅন্যটি উত্তর হিসাবে পরামর্শ হিসাবে একটি হ'ল (দ্বিগুণ) লিঙ্কযুক্ত তালিকা।

বিশদ বিবরণ: এর অর্থ হ'ল পাইথনের তালিকাগুলি কাটা সহ র্যান্ডম-অ্যাক্সেস এবং স্থির দৈর্ঘ্যের ক্রিয়াকলাপগুলির জন্য অনেক ভাল, যখন ডেক্সগুলি প্রান্তিকের বাইরে জিনিসগুলি ধাক্কা দেওয়ার এবং পপিংয়ের জন্য অনেক বেশি দরকারী, তবুও সূচকযুক্ত (তবে টুকরো টুকরো করে নয়, আকর্ষণীয়ভাবে) হচ্ছে সম্ভব তবে তালিকার চেয়ে ধীর।


4
মনে রাখবেন যে আপনার যদি কেবল এক প্রান্তে (স্ট্যাক) সংযোজন এবং পপ করতে হয় তবে তালিকাগুলি আরও ভালভাবে সম্পাদন করতে হবে .append()এবং .pop()ও (1) রূপান্তরিত হয়েছে (পুনর্নির্মাণ এবং অনুলিপিটি ঘটে তবে খুব কমই এবং কেবলমাত্র সর্বাধিক আকারে পৌঁছানো পর্যন্ত স্ট্যাকটি হবে কখনও আছে)।

@ ডেলানন: তবে আপনি যদি একটি সারি চান, তবে dequeঅবশ্যই এর মতো কিছু হ'ল সঠিক উপায়।
জ্যাব

@ ডেলান: আপনারা কীভাবে বুঝবেন? .append () এবং .pop () amortized হে (1) তালিকা রয়েছে, কিন্তু তারা deques এবং কপি উপর প্রকৃত হে (1) হয় না কখনোই প্রয়োজনীয়।
এলি

4
@ এলি: তালিকাগুলি থ্রেড-সুরক্ষা নিয়ে কাজ করে না (ভাল, এটি তাদের অভ্যন্তরীণ অংশে আবদ্ধ হয় না) এবং অনেক স্মার্ট ব্যক্তি দীর্ঘকাল ধরে এটি পরিচালনা করেছেন।

4
@ ডেলানন: আসলে সিপিথনে dequeএস থ্রেড সুরক্ষাটি সত্যিই পরিচালনা করেন না; জিআইএল তাদের অপারেশনগুলিকে পারমাণবিক করে তোলার মাধ্যমে কেবল উপকৃত হয় (এবং বাস্তবে appendএবং popএর শেষের দিক থেকে listএকই সুরক্ষা পাওয়া যায়)। বাস্তবে, যদি আপনি শুধু একটি স্ট্যাক ব্যবহার করছেন, উভয় listএবং dequeCPython কার্যকরীভাবে অভিন্ন কর্মক্ষমতা আছে; ব্লক বরাদ্দগুলি আরও ঘন ঘন হয় deque(তবে সরল সংযুক্ত তালিকার সাথে ঘন ঘন নয়; আপনি প্রতিবার সিপিথন বাস্তবায়নের ক্ষেত্রে 64৪ সদস্যের সীমানা অতিক্রম করার সময় কেবল বরাদ্দ / নিবন্ধ শেষ করবেন), তবে বিশাল অবিচ্ছিন্ন অনুলিপিগুলির অভাব ক্ষতিপূরণ দেয়।
শ্যাডোএ্যাঞ্জার

51

চেক আউট collections.deque। ডক্স থেকে:

ডিউকগুলি থ্রেড-সেফ সমর্থন করে, মেমরি এফিসিটি দক্ষ সংযুক্ত করে এবং উভয় দিকের প্রায় একই হে (1) কর্মক্ষমতা সহ ডেকের উভয় দিক থেকে পপ করে।

তালিকার অবজেক্টগুলি অনুরূপ অপারেশনগুলিকে সমর্থন করে তবে তারা দ্রুত নির্ধারিত দৈর্ঘ্যের ক্রিয়াকলাপগুলির জন্য অনুকূলিত হয় এবং পপ (0) এবং সন্নিবেশ (0, v) ক্রিয়াকলাপগুলির জন্য ও (এন) মেমরি চলন ব্যয়কে অন্তর্ভুক্ত করে যা অন্তর্নিহিত তথ্য উপস্থাপনের আকার এবং অবস্থান উভয়ই পরিবর্তন করে ।

ঠিক যেমনটি বলা হয়েছে, পপ (0) বা সন্নিবেশ (0, ভি) ব্যবহার করে তালিকার অবজেক্টগুলির সাথে বড় জরিমানা আদায় করতে হবে। আপনি একটিতে স্লাইস / সূচক ক্রিয়াকলাপগুলি ব্যবহার করতে পারবেন না deque, তবে আপনি popleft/ ব্যবহার করতে পারেন appendleftযা অপারেশনগুলির dequeজন্য অনুকূলিত। এটি প্রদর্শনের জন্য এখানে একটি সাধারণ মানদণ্ড দেওয়া হল:

import time
from collections import deque

num = 100000

def append(c):
    for i in range(num):
        c.append(i)

def appendleft(c):
    if isinstance(c, deque):
        for i in range(num):
            c.appendleft(i)
    else:
        for i in range(num):
            c.insert(0, i)
def pop(c):
    for i in range(num):
        c.pop()

def popleft(c):
    if isinstance(c, deque):
        for i in range(num):
            c.popleft()
    else:
        for i in range(num):
            c.pop(0)

for container in [deque, list]:
    for operation in [append, appendleft, pop, popleft]:
        c = container(range(num))
        start = time.time()
        operation(c)
        elapsed = time.time() - start
        print "Completed %s/%s in %.2f seconds: %.1f ops/sec" % (container.__name__, operation.__name__, elapsed, num / elapsed)

আমার মেশিনে ফলাফল:

Completed deque/append in 0.02 seconds: 5582877.2 ops/sec
Completed deque/appendleft in 0.02 seconds: 6406549.7 ops/sec
Completed deque/pop in 0.01 seconds: 7146417.7 ops/sec
Completed deque/popleft in 0.01 seconds: 7271174.0 ops/sec
Completed list/append in 0.01 seconds: 6761407.6 ops/sec
Completed list/appendleft in 16.55 seconds: 6042.7 ops/sec
Completed list/pop in 0.02 seconds: 4394057.9 ops/sec
Completed list/popleft in 3.23 seconds: 30983.3 ops/sec

4
হু, ঠিক লক্ষ্য করেছেন যে আপনি ইনডেক্সিং করতে সত্ত্বেও আপনি ডেকের সাথে স্লাইসিং করতে পারবেন না। মজাদার.
জ্যাব

4
সময়গুলির জন্য +1 - আকর্ষণীয় যে listপরিশিষ্টগুলি dequeসংযোজনের তুলনায় কিছুটা দ্রুত ।
প্রেরক

4
@ জিজিএ: এটি বেশ অদ্ভুত, বিবেচনা করে যে কোনও নির্দিষ্ট আইটেমের সূচীটি অনুসন্ধানের জন্য সাধারণত সংগ্রহের আইটেমগুলির উপরে পুনরাবৃত্তি প্রয়োজন হয় এবং আপনি dequeযেমন চান তেমন একটিতেও সূচক করতে পারেন list
জ্যাব

4
@ সেন্ডারেল: অবশ্যই, গুলিগুলি list popএর চেয়ে ধীরে ধীরে ছিল deque( listএটি সঙ্কুচিত হওয়ায় মাঝেমধ্যে পুনরায় আকার পরিবর্তন করতে উচ্চতর ব্যয়ের কারণে , যেখানে dequeকেবলমাত্র বিনামূল্যে তালিকা বা ছোট অবজেক্ট পুলে ব্লকগুলি মুক্ত করা হয়), সুতরাং যখন কোনও ডেটা কাঠামো বেছে নেওয়ার সময় একটি স্ট্যাক (ওরফে LIFO সারি), খালি-থেকে-পূর্ণ-থেকে-খালি পারফরম্যান্সের জন্য কিছুটা ভাল দেখায় deque(গড়, K৩6565 কে অপস / সেকেন্ডের জন্য append/ pop, ভার্সেস listএর 5578 কে অপস / সেকেন্ড)। আমি সন্দেহ dequeকরি আসল বিশ্বে কিছুটা ভাল করতে পারব, কারণ dequeপ্রথমবারের মতো ফ্রিলিস্টটি সঙ্কুচিত হওয়ার পরে বাড়ার চেয়ে ব্যয়বহুল।
শ্যাডোএ্যাঞ্জার

4
আমার ফ্রিলিস্টের রেফারেন্সটি স্পষ্ট করার জন্য: সিপিথনগুলি 16 টি ব্লক (মডিউল-প্রশস্ত, প্রতি নয় ) এর পরিবর্তে এগুলি পুনরায় ব্যবহারের জন্য উপলভ্য ব্লকের সস্তা অ্যারে dequeরাখবে না । সুতরাং প্রথমবারের জন্য যখন বাড়ার জন্য এটি সর্বদা নতুন ব্লকগুলি টানতে হবে ( আরও ব্যয়বহুল করে তোলা), তবে যদি এটি ক্রমাগত কিছুটা বিস্তৃত হয়, তবে কিছুটা সঙ্কুচিত হয় এবং পিছনে পিছনে থাকে তবে এটি সাধারণত জড়িত না / এ যতক্ষণ দৈর্ঘ্য মোটামুটি 1024 উপাদানগুলির মধ্যে থাকে (নিখরচায় 16 ব্লক, প্রতি ব্লকে 64 স্লট)। freedequedequemallocappendmallocfree
শ্যাডোর্যাঞ্জার

17

আমার সন্দেহ হয় যে dequeঅবজেক্টগুলির জন্য ডকুমেন্টেশন এন্ট্রি আপনাকে জানার প্রয়োজনগুলির বেশিরভাগ ক্ষেত্রেই বানান। উল্লেখযোগ্য উদ্ধৃতি:

ডিউকগুলি থ্রেড-সেফ সমর্থন করে, মেমরি এফিসিটি দক্ষ সংযুক্ত করে এবং উভয় দিকের প্রায় একই হে (1) কর্মক্ষমতা সহ ডেকের উভয় দিক থেকে পপ করে।

তবে ...

সূচক অ্যাক্সেস উভয় প্রান্তে ও (1) হয় তবে মাঝখানে ও (এন) এর দিকে ধীর হয়। দ্রুত এলোমেলো অ্যাক্সেসের জন্য, পরিবর্তে তালিকাগুলি ব্যবহার করুন।

বাস্তবায়নটি একটি লিঙ্কযুক্ত তালিকা বা অন্য কিছু কিনা তা জানাতে আমাকে উত্সটি একবার দেখে নিতে হবে, তবে এটি আমার কাছে মনে হয় deque দ্বিগুণ-লিঙ্কযুক্ত তালিকার প্রায় একই বৈশিষ্ট্য রয়েছে।


11

অন্যান্য সমস্ত সহায়ক উত্তরের পাশাপাশি পাইথন তালিকাগুলি, ডেকস, সেট এবং অভিধানের বিভিন্ন অপারেশনের সময়ের জটিলতার (বিগ-ওহ) তুলনা করার জন্য এখানে আরও কিছু তথ্য দেওয়া হয়েছে । এটি কোনও নির্দিষ্ট সমস্যার জন্য সঠিক ডেটা কাঠামো নির্বাচন করতে সহায়তা করবে।


-3

পাইথন কীভাবে এটি প্রয়োগ করেছে তা আমি ঠিক নিশ্চিত নই, আমি এখানে কেবল অ্যারে ব্যবহার করে কুইজের একটি প্রয়োগ লিখেছি। পাইথনের কিউসের মতোই এর জটিলতা রয়েছে।

class ArrayQueue:
""" Implements a queue data structure """

def __init__(self, capacity):
    """ Initialize the queue """

    self.data = [None] * capacity
    self.size = 0
    self.front = 0

def __len__(self):
    """ return the length of the queue """

    return self.size

def isEmpty(self):
    """ return True if the queue is Empty """

    return self.data == 0

def printQueue(self):
    """ Prints the queue """

    print self.data 

def first(self):
    """ Return the first element of the queue """

    if self.isEmpty():
        raise Empty("Queue is empty")
    else:
        return self.data[0]

def enqueue(self, e):
    """ Enqueues the element e in the queue """

    if self.size == len(self.data):
        self.resize(2 * len(self.data))
    avail = (self.front + self.size) % len(self.data) 
    self.data[avail] = e
    self.size += 1

def resize(self, num):
    """ Resize the queue """

    old = self.data
    self.data = [None] * num
    walk = self.front
    for k in range(self.size):
        self.data[k] = old[walk]
        walk = (1+walk)%len(old)
    self.front = 0

def dequeue(self):
    """ Removes and returns an element from the queue """

    if self.isEmpty():
        raise Empty("Queue is empty")
    answer = self.data[self.front]
    self.data[self.front] = None 
    self.front = (self.front + 1) % len(self.data)
    self.size -= 1
    return answer

class Empty(Exception):
""" Implements a new exception to be used when stacks are empty """

pass

এবং এখানে আপনি কিছু কোড দিয়ে এটি পরীক্ষা করতে পারেন:

def main():
""" Tests the queue """ 

Q = ArrayQueue(5)
for i in range(10):
    Q.enqueue(i)
Q.printQueue()    
for i in range(10):
    Q.dequeue()
Q.printQueue()    


if __name__ == '__main__':
    main()

এটি সি বাস্তবায়নের মতো দ্রুত কাজ করবে না, তবে এটি একই যুক্তি ব্যবহার করে।


4
না.আরিনভেন্ট.টহ.হুইল!
অভিজিৎ সরকার

প্রশ্ন ছিল কিভাবে পাইথন এর deque বাস্তবায়িত হয়। এটি বিকল্প বাস্তবায়নের জন্য বলছিল না।
জিনো মেম্পিন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.