User Tools

Site Tools


Sidebar

1. บทนำ

2. การวิเคราะห์ Algorithm

3. List, Stack and Queue

4. Tree

5. Hashing

6. Priority Queues

7. การจัดเรียง (Sorting)

8. The Disjoint Set

9. Graph Algorithms

dsa:dsunion

8.4. Smart Union Algorithms

การ unions ดังที่กล่าวมาข้างบนไม่มีข้อกำหนดใดกำกับเพียงแต่ใช้ทรีตัวที่สองไปเป็นทรีย่อยของทรีตัวแรก การปรับปรุงอย่างง่ายให้การทำงานดีขึ้นคือกำหนดให้ทรีที่มีขนาดเล็กกว่าไปเป็นทรีย่อยของทรีที่มีขนาดใหญ่กว่าเสมอ และเรียกวิธีนี้ว่า union-by-size

การ union กันทั้งสามในตัวอย่างที่ผ่านมามีขนาดเท่ากันทั้งหมดจึงกล่าวได้ว่ามันเป็น union-by-size เช่นกัน และถ้าการดำเนินการต่อไปเป็นการทำ union (3,4) ก็จะได้ forest ดังรูปที่ 8.10 และในกรณีที่เราไม่คำนึงถึงขนาดของทรีเราก็จะได้ forest ที่มีขนาดลึกมากกว่าดังรูปที่ 8.11

ถ้าทำ unions โดยใช้ขนาดก็จะประกันได้ว่าความลึกของโนดใด ๆ จะไม่มากกว่า $log\ N$ ดังนี้ เริ่มต้นโนดอยู่ที่ความลึก 0 และขณะเมื่อความลึกเพิ่มขึ้นจากผลการทำ union โนดนั้นก็จะถูกจัดให้อยู่ในทรีที่อย่างน้อยมีขนาดเป็นสองเท่าของของเดิม ดังนั้นความลึกของมันจึงเพิ่มขึ้นได้มากที่สุดเป็น $log\ N$ เท่า นั่นคือ running time สำหรับการทำงาน find หนึ่ง ๆ จึงเป็น $O(log\ N)$, และถ้าทำต่อเนื่องกัน $M$ ครั้งจึงใช้เวลาเป็น $O(M\ log\ N)$ ทรีในรูปที่ 8.12 แสดงกรณีทรีเลวร้ายที่สุดที่เป็นไปได้หลังจากการทำ unions จำนวน 16 ครั้งและเกิดขึ้นได้กรณีที่เราทำการ unions ระหว่างทรีที่มีขนาดเท่ากันทั้งหมด (binomial tree เป็นตัวอย่างกรณีเลวร้ายที่สุด)

รูปที่ 8.10 ผลของ union-by-size


รูปที่ 8.11 ผลของการ union แบบเดิม

รูปที่ 8.12 Worst-case tree ที่มี N = 16

การใช้วิธีดังกล่าวนี้จะต้องบันทึกขนาดของแต่ละทรีในระหว่างทำงานด้วย เนื่องจากเราใช้อะเรย์ ดังนั้นเราจึงสามารถใส่ค่าติดลบ (negative) ให้แก่รากของทรีลงในรายการของอะเรย์ โดยเริ่มต้นจะให้มีค่าเป็น –1 ทั้งหมด เมื่อมีการทำ union ก็จะทำการตรวจสอบขนาด และขนาดใหม่ก็คือผลบวกของขนาดเดิม ดังนั้นโปรแกรมจึงไม่ได้ยุ่งยากแต่อย่างใด การทำงานต่อเนื่องกัน M ครั้ง โดยเฉลี่ยแล้วใช้เวลาเป็น $O(M)$ ถ้าใช้ union-by-size เนื่องจากการ unions ที่เป็นแบบสุ่มนั้นโดยทั่วไปแล้วเป็นการควบรวมเซตที่มีขนาดเล็กมาก (ปกติมีสมาชิกตัวเดียว) เข้ากับเซตที่มีขนาดใหญ่ตลอดการทำงานของอัลกอริทึม

อีกวิธีการหนึ่งที่ประกันได้เช่นกันว่าทรีทั้งหมดมีความลึกมากสุดเป็น $O(log\ N)$ คือ วิธี union-by-height วิธีการนี้จะทำการ unions ด้วยการใช้ทรีที่มีความลึกน้อยกว่าไปเป็นทรีย่อยของทรีที่มีความลึกมากกว่า ด้วยวิธีนี้จะทำให้ความสูงของทรีเพิ่มขึ้นได้ก็ต่อเมื่อทรีที่นำมาควบรวมกันนั้นมีความลึกเท่ากันเท่านั้น และจะทำให้มีความสูงของทรีเพิ่มขึ้นหนึ่งระดับ รูปข้างล่างนี้แสดงรูปทรีและโครงสร้างที่ใช้งานจริงของ union-by-size และ union-by-height และรูปที่ 8.13 เป็นโปรแกรม union-by-height

-1 -1 -1 4 -5 4 4 6
0 1 2 3 4 5 6 7

union-by-size

-1 -1 -1 4 -3 4 4 6
0 1 2 3 4 5 6 7

union-by-height

public void union ( int  root1, int  root2 )
{
    if ( s[root2] < s[root1] )  	/* root2 is deeper */
	    s[root1] = root2;     	/* make root2 new root */
    else
    {
	    if ( s[root1] == s[root2] )
	       s[root1]--; 		    /* update height if same */
 	    s[root2] = root1; 		/* make root1 new root */
    }
}

รูปที่ 8.13 ฟังก์ชัน union-by-height (rank)

dsa/dsunion.txt · Last modified: 2021/09/08 22:32 by wasu

Page Tools