ต้นไม้สามารถเคลื่อนที่ได้โดยไม่ต้องทำการวนซ้ำกองซ้อนหรือคิวและมีพอยน์เตอร์เพียงไม่กี่ตัว?


15

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

ดังนั้นมันเป็นไปได้หรือเป็นไปไม่ได้? ทำไมหรือทำไมไม่?

แก้ไข: เพื่อเพิ่มความกระจ่างบางอย่างฉันใช้สิ่งนี้บนต้นไม้ไบนารีซึ่งมีสามองค์ประกอบ - ข้อมูลที่จัดเก็บที่แต่ละโหนดและตัวชี้ไปยังลูกสองคน โซลูชันของฉันสามารถขยายไปยังต้นไม้ n-ary ด้วยการเปลี่ยนแปลงเพียงเล็กน้อยเท่านั้น

ครูโครงสร้างข้อมูลของฉันไม่ได้ จำกัด ข้อ จำกัด ใด ๆ กับการกลายพันธุ์ต้นไม้และแน่นอนฉันค้นพบในภายหลังว่าวิธีแก้ปัญหาของเขาคือใช้พอยน์เตอร์ชี้ไปที่ต้นไม้ในทางของเขา อาจารย์คณิตศาสตร์ที่ไม่ต่อเนื่องของฉันกล่าวว่าการกลายพันธุ์ของต้นไม้หมายความว่ามันไม่ได้เป็นต้นไม้ตามคำนิยามทางคณิตศาสตร์ของต้นไม้อีกต่อไปคำจำกัดความของเขาก็จะห้ามพอยน์เตอร์ชี้ไปยังผู้ปกครอง - ซึ่งจะตรงกับกรณีที่


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

2
ฉันเดา contraint อาจารย์จริงๆอยากจะแสดงเป็น "กับพื้นที่เพิ่มเติม" แต่อะไรคือทางออกของคุณล่ะ? O(1)
กราฟิลส์

คำตอบ:


17

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

ต้นไม้ไบนารีแบบเธรดเป็นการแสดงแบบดัดแปลงของต้นไม้ไบนารีที่มีตัวชี้ nil บางตัวถูกใช้เพื่อเชื่อมโยงไปยังโหนดตัวตายตัวแทนในต้นไม้ ข้อมูลพิเศษนี้สามารถใช้ในการสำรวจต้นไม้โดยไม่ต้องสแต็ค อย่างไรก็ตามจำเป็นต้องเพิ่มบิตต่อโหนดเพื่อแยกความแตกต่างของเธรดจากตัวชี้เด็ก วิกิพีเดีย: Tree_traversal

เท่าที่ผมรู้ว่าต้นไม้ไบนารีดำเนินการโดยใช้ตัวชี้ในแบบปกติ (ซ้ายและตัวชี้ขวาต่อโหนด) สามารถใช้วิธีการสำรวจของหัวข้อในวิธีการที่นำมาประกอบกับมอร์ริส พอยน์เตอร์ NIL จะถูกนำมาใช้ใหม่ชั่วคราวเพื่อเธรดพา ธ กลับไปที่รูท ส่วนที่ฉลาดคือในระหว่างการสำรวจเส้นทางหนึ่งสามารถแยกความแตกต่างของขอบเดิมจากการเชื่อมโยงเธรดชั่วคราวโดยใช้วิธีที่พวกเขาสร้างวงจรในต้นไม้)

ส่วนที่ดี: ไม่มีโครงสร้างข้อมูลเพิ่มเติม ส่วนที่ไม่ดี: การโกงเล็กน้อยสแต็คอยู่ในต้นไม้อย่างฉลาด ฉลาดมาก.

หลักฐานของสแต็กที่ซ่อนอยู่จะแสดงใน P. Mateti และ R. Manghirmalani: อัลกอริทึมการสำรวจเส้นทางต้นไม้ของมอร์ริสพิจารณาใหม่ DOI: 10.1016 / 0167-6423 (88) 90063-9

JM Morris: สำรวจต้นไม้ไบนารีอย่างง่ายดายและประหยัด IPL 9 (1979) 197-200 DOI: 10.1016 / 0020-0190 (79) 90068-1

จากนั้นก็มีการสแกนLindstrom วิธีนี้ "หมุน" ตัวชี้สามตัวที่เกี่ยวข้องในแต่ละโหนด (พาเรนต์และลูกสองลูก) หากคุณต้องการดำเนินการอัลกอริธึม pre-order หรือ post-order ที่เหมาะสมคุณต้องการบิตพิเศษต่อโหนด หากคุณเพียงต้องการเยี่ยมชมโหนดทั้งหมด (สามครั้ง แต่คุณไม่เคยรู้ว่าคุณเยี่ยมชมที่ใดที่ดำเนินการ) แล้วมันสามารถทำได้โดยไม่ต้องบิต

G. Lindstrom: สแกนโครงสร้างรายการโดยไม่มีสแต็กหรือแท็กบิต IPL 2 (1973) 47-51 DOI: 10.1016 / 0020-0190 (73) 90012-4

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

JM Robson: อัลกอริทึมที่ได้รับการปรับปรุงสำหรับการสำรวจต้นไม้แบบไบนารีโดยไม่มีสแต็กเสริม IPL 1 (1973) 149-152 10,1016 / 0020-0190 (73) 90018-5

IPL = จดหมายการประมวลผลข้อมูล


ฉันชอบวิธีนี้เหมือนกัน แต่ก็ไม่มีอะไรที่ฉันจะคิดในช่วงปีแรกของการเรียนวิทยาศาสตร์คอมพิวเตอร์ ใช่อาจโกงตามกฎของศาสตราจารย์
NL - ขอโทษที่โมนิก้า

2
คุณสามารถให้ลิงค์ / การอ้างอิงสำหรับกลยุทธ์ได้หรือไม่?
กราฟิลส์

1
ส่วนที่แย่จริง ๆ ของวิธีนี้คือคุณไม่สามารถข้ามเส้นทางได้มากกว่าหนึ่งครั้งในแต่ละครั้ง
Gilles 'หยุดความชั่วร้าย'

6

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


ซึ่งคล้ายกับวิธีแก้ปัญหาที่โครงสร้างข้อมูลอาจารย์ที่เสนอปัญหาใช้ในการแก้ปัญหา ศาสตราจารย์คณิตศาสตร์ไม่ต่อเนื่องคัดค้านว่า "นี่กลายเป็นกราฟมากกว่าต้นไม้" ถ้ามีพอยน์เตอร์กลับไปที่พ่อแม่
NL - ขอโทษที่โมนิก้า

@NathanLiddle: ขึ้นอยู่กับคำจำกัดความของต้นไม้ที่ใช้ (ซึ่งคุณไม่ได้ให้) ใน "โลกแห่งความเป็นจริง" การเป็นตัวแทนต้นไม้ของ Yuval นั้นสมเหตุสมผลแม้ว่าทฤษฎีกราฟจะบอกว่าสิ่งที่เขากำหนดไม่ใช่ต้นไม้แน่นอน
กราฟิลส์

@ ราฟาเอลใช่และเป็นไปตามข้อกำหนดเดิมของอาจารย์ดังนั้นมันจึงเป็นคำตอบที่ยอมรับได้สำหรับฉัน
NL - ขอโทษที่โมนิก้า

0

วิธีการแก้ปัญหาของฉันคือการสำรวจเส้นทางแรกโดยใช้ลูปซ้อนเพื่อบังคับให้ต้นไม้ สิ่งนี้ไม่ได้มีประสิทธิภาพไม่ว่าด้วยวิธีใดและโครงสร้างข้อมูลแบบเรียกซ้ำเช่นต้นไม้กำลังร้องขอการสำรวจเส้นทางแบบวนซ้ำ แต่คำถามไม่ได้ว่าต้นไม้สามารถสำรวจได้อย่างมีประสิทธิภาพหรือไม่

Pseudocode:
root = pointer root 
depth = integer 0
finished = bool false
//If we n-ary tree also track how many children have been found 
//on the node with the most children for the purposes of this psuedocode 
//we'll assume a binary tree and insert a magic number of 2 so that we 
//can use bitwise operators instead of integer division 
while(!finished)
    ++depth
    treePosition = pointer root
    finished = true;
    for i := 0..2**depth
        for j := 0..depth
            if (i & j) //bitwise operator explained below
                // if right child doesn't exist break the loop
                treePosition = treePosition.rightChild
            else
                // if left child doesn't exist break the loop
                treePosition = treePosition.leftChild
        if j has any children
            finished = false
            do anything else you want when visiting the node

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

2**1       0               1
2**2   00      01      10      11
2**3 000 001 010 011 100 101 110 111

สำหรับ n-ary คุณจะต้องใช้ i% (maxChildren ** j) / j เพื่อกำหนดพา ธ ที่จะใช้ระหว่าง 0 ถึง maxChildren

ในแต่ละโหนดใน n-ary คุณจะต้องตรวจสอบเพื่อดูว่าจำนวนลูกมากกว่า maxChildren และอัปเดตอย่างเหมาะสม


หากคุณต้องการใช้มากกว่าไบนารีคุณจะต้องแทนที่หมายเลขมายากล 2 ด้วยตัวแปรที่จะเพิ่มขึ้นเพื่อให้ตรงกับเด็กสูงสุดที่เห็นและแทนที่จะเป็นผู้ประกอบการระดับบิตที่คุณจะต้องหารด้วยตัวแปรเดียวกันยกขึ้นเป็น พลังแห่งความลึกของต้นไม้ที่คุณอาศัยอยู่
NL - ขอโทษที่โมนิก้า

O(1)O(LGn)O(1)O(n)O(1). พื้นที่เพิ่มเติม ") ตัวอย่างเช่นคุณจะทำอย่างไรถ้าdepthเกินกว่าความกว้างของint?
DW

DW ศาสตราจารย์ที่วางปัญหาไม่ได้ จำกัด ปัญหานั้นและสิ่งที่รบกวนฉันมากเกี่ยวกับการสนทนาของฉันกับอาจารย์คณิตศาสตร์ไม่ต่อเนื่องคือเขาไม่เคยยอมรับว่ามันเป็นไปได้ที่จะสำรวจต้นไม้โดยไม่ต้องเรียกซ้ำกองซ้อน หรือคิวอะไรก็ตามที่มีค่าใช้จ่าย สิ่งเดียวที่โซลูชันของฉันแสดงให้เห็นว่าเป็นไปได้ที่จะทำทุกอย่างซ้ำ ๆ ที่สามารถทำได้ซ้ำ ๆ แม้ว่าคุณจะลบตัวเลือกสำหรับสแต็กคิว ฯลฯ
NL - ขอโทษโมนิก้า

มันเป็นสิ่งหนึ่งที่จะบอกว่ามันเป็น unsolvable โดยไม่ต้องมีพื้นที่เพิ่มเติม O (1) มันค่อนข้างอื่นที่จะประกาศปัญหาที่แก้ไม่ตกโดยไม่ต้องเรียกซ้ำกองซ้อนหรือคิว และจริง ๆ แล้วหลังจากเห็นรหัสของฉันอาจารย์คณิตศาสตร์ที่ไม่ต่อเนื่องยังคงไม่ยอมให้ประเด็นเพราะเขาพูดว่า "ฉัน" ในตอนแรกสำหรับการวนรอบคือการแทนที่ของคิว นั่นเป็นวิธีการที่หัวแข็ง?
NL - ขอโทษที่โมนิก้า

1
idepthdepthΘ(n)Θ(n)iO(1)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.