การเรียงลำดับโดยใช้สแต็คแบบอ่านอย่างเดียว


14

พิจารณาการตั้งค่าต่อไปนี้:

  • เราจะได้สแต็คsซึ่งมีรายการn
  • เราสามารถใช้จำนวนสแต็คพิเศษคงที่O(1)
  • เราสามารถใช้การดำเนินการต่อไปนี้กับสแต็คเหล่านี้:
    1. ตรวจสอบว่าสแต็กว่างเปล่าหรือไม่
    2. เปรียบเทียบไอเท็มยอดนิยมของทั้งสองกอง
    3. ลบรายการด้านบนในสแต็ก
    4. พิมพ์รายการยอดนิยมในสแต็ค
    5. คัดลอกรายการบนสุดของสแต็กไปยังสแต็กอื่น
    6. คัดลอกเนื้อหาของกองหนึ่งไปยังกองอื่น

โปรดทราบว่าสิ่งเหล่านี้เป็นเพียงการดำเนินการที่ได้รับอนุญาต เราไม่สามารถแลกเปลี่ยนไอเท็มได้และเราไม่ได้รับอนุญาตให้ดันไอเท็มใด ๆ ลงบนสแต็คใด ๆ ยกเว้นการคัดลอกไอเท็มด้านบนลงในสแต็ก (หลังจากที่เนื้อหาก่อนหน้าของสแต็คเป้าหมายถูกทิ้งไปแล้ว .

นี่เป็นอัลกอริทึมในการจัดเรียงสแต็คด้วยการเปรียบเทียบ :O(n2)

last := empty
for i from 1 to n
  min := empty
  w := s
  while w is not empty
    if w.top > last and w.top < min
      min := w.top
    delete w.top
  print min
  last := min

เราทำได้ดีกว่านี้ไหม

มีโปรแกรมที่พิมพ์รายการที่เรียงลำดับของไอเท็มในสแต็กโดยใช้การเปรียบเทียบO(nlogn)หรือไม่?


2
ดูเหมือนว่ารีจิสเตอร์จะทำงานเหมือนกองข้าว? ดูเหมือนว่าคุณกำลังพูดถึงการดำเนินการพุชและป๊อป นั่นคือคำถามของคุณ? คุณจะเรียงลำดับสแต็กโดยใช้การดำเนินการสแต็กและสแต็กจำนวนมากอย่างไร
AturSams

2
ด้วยลงทะเบียนคุณสามารถ: เพียงแค่ใส่หมายเลขทุกหนึ่งในการลงทะเบียน ( O ( n ) ) แล้วใช้ขั้นตอนวิธีการเรียงลำดับตามปกติ ( O ( n LG n ) ) nO(n)O(nlgn)
Kaveh

1
คุณต้องการใช้การลงทะเบียนหรือไม่ มิฉะนั้นปัญหาจะเป็นเรื่องเล็กน้อยตามที่ Kaveh ให้ความเห็นไว้ O(1)
Yuval Filmus

1
ยินดี. ฉันคิดว่าเราได้รับสแต็คจำนวนมากไม่ใช่แค่อันเดียวฉันจะแก้ไข
Kaveh

2
@akappa คุณแน่ใจหรือไม่ว่าสามารถใช้ในการดูนี้ เราไม่สามารถทำให้ขนาดที่ใหญ่กว่า 1 หายไปโดยพลการคุณไม่จำเป็นต้องเก็บบล็อกที่เรียงแล้วใช่ไหม
Kaveh

คำตอบ:


1

ฉันคิดว่าตอนนี้ฉันสามารถแสดงให้เห็นถึงขอบเขตล่างที่ไม่สำคัญ แนวคิดคือการนำโปรแกรมดังกล่าวไปใช้กับโปรแกรมเปรียบเทียบการแยกสาขา สมมติฐาน `แบบอ่านอย่างเดียว 'หมายความว่าครอบครัวของโปรแกรมการแตกสาขาของเราใช้เพียงเล็กน้อยคือพื้นที่ จากนั้นเราใช้ขอบเขตล่างS T = Ω ( n 2 ) ที่พิสูจน์โดย Borodin และคณะ ใน "การแลกเปลี่ยนพื้นที่เวลาสำหรับการเรียงลำดับบนเครื่องที่ไม่ลืมเลือน" นี้จะช่วยให้เราn 2 /บันทึกnผูกพันลดลงเป็นครั้งที่O(logn)ST=Ω(n2)n2/logn

รายละเอียดเพิ่มเติมเล็กน้อย: เราสามารถแจกจ่ายด้วยการปฏิบัติการ 5 ด้านบน การพูดอย่างหลวม ๆ ถ้าเราสามารถเปรียบเทียบหัวของสองรายการและพิมพ์ส่วนหัวของรายการแล้วก็ไม่จำเป็นที่เราจะต้องแยกส่วนหัวของรายการในการลงทะเบียนที่เฉพาะเจาะจง ด้วยเหตุนี้เราจะเห็นว่าการลงทะเบียนทุกครั้งในเครื่องจะเก็บซับสตริงสุดท้ายของอินพุตเท่านั้น

สมมติว่าโปรแกรมของเรามีการลงทะเบียนบรรทัดของรหัสและkจิX 1 , ... , X kkX1,,Xk

แก้ไขnเราสร้างโปรแกรมเปรียบเทียบการแตกสาขาสำหรับสตริงที่มีความยาวnดังนี้ สร้างโหนดสำหรับแต่ละ tuple ( ฉัน, d 1 , ... , d k )ที่1 ฉัน และ0 d 1 , ... , d k n แนวคิดคือการคำนวณในเครื่องลงทะเบียนสอดคล้องกับเส้นทางในโปรแกรมการแยกสาขาและเราอยู่ที่โหนด( i , d 1 , , dnn(i,d1,,dk)1i0d1,,dknถ้าเราจะอยู่ที่เส้นฉันในเครื่องลงทะเบียนและความยาวของสตริงที่เก็บไว้ใน X ฉันคือ dฉัน ตอนนี้เราต้องกำหนดขอบกำกับของโปรแกรมการแยกสาขา(i,d1,,dk)iXidi

หากบรรทัดเป็นของแบบฟอร์มi

ถ้ากลับไปที่iอีก1กลับไปที่i 2Xu<Xvi1i2

แล้วสำหรับทุกโหนด( ฉัน, d 1 , ... , d k )จะมีป้ายโดยการเปรียบเทียบd ยู -th และd วีองค์ประกอบ -th ของการป้อนข้อมูลและการมี "ความจริง" ขอบไปที่( i 1 , d 1 , , d k )และขอบ "false" ถึง( i 2 , d 1 , , d kd1,,dk(i,d1,,dk)dudv(i1,d1,,dk) .(i2,d1,,dk)

หากบรรทัดเป็นของแบบฟอร์มi

, goto line i X1tail(X2)i

แล้วมีลูกศรจากโหนดใด ๆจะ( ฉัน' , d 2 - 1 , ... , d k )(i,d1,,dk)(i,d21,,dk)

หากบรรทัดเป็นของแบบฟอร์มi

, goto line i print(head(Xu))i

จากนั้นจะมีลูกศรจากโหนดใด ๆถึง( i , d 1 , , d k )ซึ่งมีข้อความกำกับโดยโหนดd u- th ของอินพุต(i,d1,,dk)(i,d1,,dk)du

หวังว่าตัวอย่างเหล่านี้ทำให้ชัดเจนว่าฉันตั้งใจจะสร้างโปรแกรมการแยกสาขาของฉัน เมื่อทั้งหมดได้ถูกพูดและทำโปรแกรมแตกแขนงนี้มีที่มากที่สุดโหนดจึงมีพื้นที่O ( บันทึกn )nkO(logn)


0

คุณสามารถนับองค์ประกอบหรือไม่ จากนั้นฉันคิดว่ามีการดำเนินการควบรวมกิจการที่ค่อนข้างง่าย หากคุณสามารถใส่สัญลักษณ์เพิ่มเติมลงในสแต็กคุณสามารถแก้ได้ด้วย 3 สแต็คดังนี้:

หากเรามีองค์ประกอบเดียวรายการจะถูกเรียงลำดับแล้ว ทีนี้สมมติว่าเราได้เรียงลำดับครึ่งบนของสแต็กแล้ว เราสามารถคัดลอกครึ่งบน (เรียงกลับกัน) ไปยังสแต็กที่สองและวางสัญลักษณ์แยกไว้ด้านบน ตอนนี้เรามี 3 กองอีกครั้ง (เนื่องจากเราสามารถมองข้ามสัญลักษณ์เรียงแล้วด้านล่างสัญลักษณ์แยก) และสามารถเรียงครึ่งล่าง ในที่สุดเราสามารถคัดลอกครึ่งล่างที่เรียงลำดับไปยังกองซ้อนที่สามในลำดับย้อนกลับและผสานครึ่งทั้งสองกลับไปที่กองซ้อนต้นฉบับ

การดำเนินการทั้งหมดต้องใช้เวลาเชิงเส้นดังนั้นเราจึงเรียงลำดับรายการในO(nlogn)

(โปรดทราบว่าเราต้องการสแต็คขนาดเนื่องจากสัญลักษณ์การแยก แต่สามารถแก้ไขได้อย่างง่ายดายโดยใช้สแต็กอื่น)nlogn


เนื่องจากคุณไม่สามารถใส่องค์ประกอบใหม่ลงในสแต็กคุณอาจพบปัญหาที่จุดแยก เพื่อแก้ปัญหานี้คุณสามารถทำสิ่งต่อไปนี้พร้อมกับสแต็คเพิ่มเติม:

คัดลอกบนองค์ประกอบกองเพิ่มเติมแล้วดำเนินการต่อกับองค์ประกอบที่เหลือเป็นมาก่อน ตอนนี้คุณรู้จำนวนขององค์ประกอบที่คุณต้องพิจารณาในแต่ละขั้นตอนแล้วดังนั้นไม่จำเป็นต้องมีสัญลักษณ์การแยกn2logn

สุดท้ายทำซ้ำขั้นตอนที่มีองค์ประกอบเพิ่มเติมที่มากที่สุดครั้งและผสานพวกเขาไปยังกองต้นฉบับในเส้นเวลา การเรียงลำดับค่าสแต็กสำหรับค่าคงที่cที่มากที่สุดc n log n + c nlognccnlogn+cn2logn2+cn4logn4+ ...=O(nlogn)O(nlogn)


ฉันไม่แน่ใจว่าฉันเข้าใจ ยกตัวอย่างเช่นเราจะคัดลอกครึ่งบนของสแต็กในลำดับย้อนกลับไปยังสแต็กอื่นได้อย่างไรเมื่อเราไม่สามารถผลักองค์ประกอบใด ๆ ลงในสแต็กใด ๆ
Siddharth

เราไม่สามารถผลักองค์ประกอบใหม่ใด ๆ ไปยังสแต็ก แต่ตาม 5 เราสามารถผลักองค์ประกอบด้านบนของหนึ่งกองไปยังอีก ดังนั้นการคัดลอกสแต็กในลำดับกลับกันต้องใช้เวลาเชิงเส้นมากที่สุด ดังนั้นฉันคิดว่านั่นไม่ใช่สิ่งที่คุณขอ?
cero

คุณไม่สามารถผลักดันสิ่งอื่นใดนอกเหนือจากรายการอื่น ๆ ตามที่อธิบายไว้ในคำถาม
Kaveh
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.