threaded tree.pdf

‫درخت‌های‌دودوئی‌نخ‌‌کشی‌شده‌‬
‫‪Threaded Binary Trees‬‬
‫سرفصلها‪‌:‬‬
‫‌‬
‫• تعریف‌‬
‫• پیمایش‌‬
‫• گسترش‌مفهوم‌‬
‫• جستجو‌‬
‫• درج‌یک‌گره‌‬
‫• حذف‌یک‌گره‬
‫‪1‬‬
‫تعریف‬
‫‪ ‬در‌درخت‌دودوئی‌در‌یک‌برگ‌اشاره‌گر‌ها‌به‌فرزند‌چپ‌و‌فرزند‌راست‌‪‌،‬تهی‌است‪‌.‬‬
‫‪ ‬به ‌علت ‌استفاده ‌نکردن ‌از ‌‌اشاره‌گرهای ‌فرزند ‌در ‌برگ ‌ها ‌مقداری ‌از ‌حافظه ‌تخصیص‌‬
‫داده‌شده‌عمال‌بدون‌استفاده‌می‌ماند‪‌‌.‬‬
‫‌‬
‫‪ ‬می‌توان‌از‌این‌اشاره‌گرها‌برای‌بهینه‌کردن‌پیمایش‌میان‌ترتیب‌استفاده‌کرد‪‌.‬‬
‫‌‌‌‌تا ‌بجای ‌استفاده ‌از ‌الگوریتم ‌بازگشتی ‌پیمایش ‌میان ‌ترتیب ‌از ‌یک ‌الگوریتم ‌غیر‌‬
‫بازگشتی‌)‪‌(iterative‬استفاده‌کنیم‌که‌وقت‌کمتری‌میگیرد‪‌.‬‬
‫‌‬
‫‌‬
‫‌‬
‫‪2‬‬
‫‌‬
‫تعریف‬
‫‌‬
‫‪ ‬در‌یک‌درخت‌دودوئی‪‌‌،‬در‌یک‌برگ‌‌‪‌،‬اشاره‌گرها‌مقدار‌تهی‌دارند‪‌.‬‬
‫‌‬
‫‪ ‬میتوان ‌محتویات ‌ ‌اشارگر ‌های ‌چپ ‌و ‌راست ‌تهی ‌را ‌طوری ‌عوض ‌کرد ‌که ‌به ‌گره‌‌‬
‫بعدی‌و‌‌قبلی‌در‌پیمایش‌میان‌ترتیب‌درخت‌دودوئی‌اشاره‌‌کنند‌‪‌‌.‬‬
‫‌‬
‫‪ ‬به‌این‌ترتیب‌وقتی‌به‌یک‌گره‌برگ‌می‌رسیم‪‌‌،‬برای‌پیدا‌کردن‌گره‌بعدی‌نیازی‌به‌‬
‫فراخوانی‌بازگشتی‌نیست‌‪‌،‬چون‌آدرس‌گره‌بعدی‌را‌در‌فیلد‌اشاره‌گر‌گره‌‌برگ‌در‌‬
‫اختیار‌داریم‪‌.‬‬
‫‌‬
‫‪ ‬به‌این‌اشاره‌گر‌ها‌نخ‌‌)‪‌(Thread‬می‌گوییم‪‌.‬‬
‫‌‬
‫‪3‬‬
‫‌‬
‫تعریف‬
‫‪ ‬بنا ‌براین ‌در ‌این ‌روش ‌باید ‌مشخص ‌شود ‌که ‌یک ‌اشاره ‌گر ‌از ‌نوع ‌اشاره ‌گر ‌به‌‬
‫فرزندان‌است‌(‌گره‌هائی‌که‌در‌سطوح‌پائین‌تر‌قرار‌دارند)‌و‌یا‌اشاره‌گری‌از‌‬
‫نوع ‌نخ ‌است ‌که ‌به ‌گره ‌ها ‌ی ‌‪‌ ancestor‬که ‌در ‌سطوح ‌باال ‌تر ‌قرار ‌دارند‌‬
‫اشاره‌میکند‪‌.‬‬
‫‪ ‬برای‌تعیین‌این‌مورد‌از‌دو‌متغییر‌‪‌Boolean‬استفاده‌میکنیم‪‌.‬‬
‫‌‌‌‌‬
‫;‪typedef struct NODE *PNODE‬‬
‫{‪NODE‬‬
‫‪int‬‬
‫;‪label‬‬
‫;‪PNODE leftChild, rightChild‬‬
‫‪bool‬‬
‫;‪LeftThread, RightThread‬‬
‫‪4‬‬
‫‪struct‬‬
‫}‬
‫تعریف‬
‫‪ ‬مثال‌‪‌:‬‬
‫‌‌‌‌اشاره‌گر‌فرزند‌راست‌در‌گره‌های‌برگ‌که‌از‌نوع‌نخ‌است‌به‌گره‌بعدی‌در‌‬
‫ترتیب‌پیمایش‌میان‌ترتیب‌اشاره‌میکند‪‌.‬‬
‫‪6‬‬
‫‪8‬‬
‫‪11‬‬
‫‪13‬‬
‫‪3‬‬
‫‪5‬‬
‫‪7‬‬
‫‪1‬‬
‫اشاره‌گر‬
‫‌از‌نوع‌نخ‬
‫‪9‬‬
‫‪5‬‬
‫پیمایش‌میان‌ترتیب‌در‌درخت‌دودوئی‌نخ‌کشی‌شده‬
‫‪ ‬آغاز ‌پیمایش ‌از ‌سمت ‌چپ‌ترین ‌گره ‌خواهد ‌بود‪‌ .‬مقدار ‌آن ‌را ‌چاپ ‌می‌کنیم ‌و ‌به‌‬
‫سراغ‌نخ‌(اشاره‌گر)‌سمت‌راست‌آن‌می‌رویم‪‌.‬‬
‫‌‬
‫‪ ‬زمانی‌که‌با‌استفاده‌از‌یک‌نخ‌به‌یک‌گره‌می‌رسیم‌مقدار‌آن‌گره‌را‌چاپ‌کرده‌و‌به‬
‫سراغ‌زیر‌درخت‌راست‌آن‌می‌رویم‪‌.‬‬
‫‌‬
‫‪ ‬در‌هنگامی‌که‌وارد‌یک‌زیر‌درخت‌جدید‌می‌شویم‌‌‪‌،‬‬
‫‌‌‌‌ابتدا‌سراغ‌سمت‌چپ‌ترین‌گره‌رفته‌و‌مقدار‌آن‌را‌چاپ‌می‌کنیم‌و‌‬
‫‌‌‌‌به‌همین‌ترتیب‌به‌کار‌خود‌ادامه‌می‌دهیم‪‌.‬‬
‫‪6‬‬
‫پیمایش‌میان‌ترتیب‌درخت‬
‫‪6‬‬
‫خروجی‌‬
‫‪‌1‬‬
‫‪8‬‬
‫‪11‬‬
‫‪13‬‬
‫‪3‬‬
‫‪7‬‬
‫‪9‬‬
‫‪5‬‬
‫‪1‬‬
‫شروع‌از‌چپ‌ترین‌گره‌و‌چاپ‌آن‌‬
‫‪7‬‬
‫پیمایش‌درخت‬
‫‪6‬‬
‫خروجی‌‬
‫‪‌1‬‬
‫‪‌3‬‬
‫‪8‬‬
‫‪11‬‬
‫‪13‬‬
‫‪3‬‬
‫‪7‬‬
‫‪9‬‬
‫‪5‬‬
‫‪1‬‬
‫گذر‌از‌نخ‌سمت‌راست‌و‌چاپ‌مقدار‌جدید‌‬
‫‪8‬‬
‫پیمایش‌درخت‬
‫‪6‬‬
‫خروجی‌‬
‫‪‌1‬‬
‫‪‌3‬‬
‫‪‌5‬‬
‫‪8‬‬
‫‪11‬‬
‫‪13‬‬
‫‪3‬‬
‫‪7‬‬
‫‪9‬‬
‫‪5‬‬
‫‪1‬‬
‫رفتن‌به‌سمت‌زیر‌درخت‌راست‪‌،‬پیدا‌کردن‌‬
‫چپ‌ترین‌گره‌و‌چاپ‌کردن‌آن‌‬
‫‪9‬‬
‫پیمایش‌درخت‬
‫‪6‬‬
‫خروجی‌‬
‫‪‌1‬‬
‫‪‌3‬‬
‫‪‌5‬‬
‫‪‌6‬‬
‫‪8‬‬
‫‪11‬‬
‫‪13‬‬
‫‪3‬‬
‫‪7‬‬
‫‪9‬‬
‫‪5‬‬
‫‪1‬‬
‫گذر‌از‌نخ‌سمت‌راست‌و‌چاپ‌مقدار‌جدید‌‬
‫‪10‬‬
‫پیمایش‌درخت‬
‫خروجی‌‬
‫‪‌1‬‬
‫‪‌3‬‬
‫‪‌5‬‬
‫‪‌6‬‬
‫‪‌7‬‬
‫‪6‬‬
‫‪8‬‬
‫‪11‬‬
‫‪13‬‬
‫‪3‬‬
‫‪7‬‬
‫‪9‬‬
‫‪5‬‬
‫‪1‬‬
‫رفتن ‌به ‌سمت ‌زیر ‌درخت ‌راست‪‌ ،‬پیدا ‌کردن‌‬
‫چپ‌ترین‌گره‌و‌چاپ‌کردن‌آن‌‬
‫‪11‬‬
‫پیمایش‌درخت‬
‫خروجی‌‬
‫‪‌1‬‬
‫‪‌3‬‬
‫‪‌5‬‬
‫‪‌6‬‬
‫‪‌7‬‬
‫‪‌8‬‬
‫‪6‬‬
‫‪8‬‬
‫‪11‬‬
‫‪13‬‬
‫‪3‬‬
‫‪7‬‬
‫‪9‬‬
‫‪5‬‬
‫‪1‬‬
‫گذر‌از‌نخ‌سمت‌راست‌و‌چاپ‌مقدار‌جدید‌‬
‫‪12‬‬
‫پیمایش‌درخت‬
‫خروجی‌‬
‫‪‌1‬‬
‫‪‌3‬‬
‫‪‌5‬‬
‫‪‌6‬‬
‫‪‌7‬‬
‫‪‌8‬‬
‫‪‌9‬‬
‫‪6‬‬
‫‪8‬‬
‫‪11‬‬
‫‪13‬‬
‫‪3‬‬
‫‪7‬‬
‫‪9‬‬
‫‪5‬‬
‫‪1‬‬
‫رفتن ‌به ‌سمت ‌زیر ‌درخت ‌راست‪‌ ،‬پیدا ‌کردن‌‬
‫چپ‌ترین‌گره‌و‌چاپ‌کردن‌آن‌‬
‫‪13‬‬
‫پیمایش‌درخت‬
‫خروجی‌‬
‫‪‌1‬‬
‫‪‌3‬‬
‫‪‌5‬‬
‫‪‌6‬‬
‫‪‌7‬‬
‫‪‌8‬‬
‫‪‌9‬‬
‫‪‌11‬‬
‫‪6‬‬
‫‪8‬‬
‫‪11‬‬
‫‪13‬‬
‫‪3‬‬
‫‪7‬‬
‫‪9‬‬
‫‪5‬‬
‫‪1‬‬
‫گذر‌از‌نخ‌سمت‌راست‌و‌چاپ‌مقدار‌جدید‌‬
‫‪14‬‬
‫پیمایش‌درخت‬
‫خروجی‌‬
‫‪‌1‬‬
‫‪‌3‬‬
‫‪‌5‬‬
‫‪‌6‬‬
‫‪‌7‬‬
‫‪‌8‬‬
‫‪‌9‬‬
‫‪‌11‬‬
‫‪‌13‬‬
‫‪6‬‬
‫‪8‬‬
‫‪11‬‬
‫‪13‬‬
‫‪3‬‬
‫‪7‬‬
‫‪9‬‬
‫‪5‬‬
‫‪1‬‬
‫رفتن ‌به ‌سمت ‌زیر ‌درخت ‌راست‪‌ ،‬پیدا ‌کردن‌‬
‫چپ‌ترین‌گره‌و‌چاپ‌کردن‌آن‌‬
‫‪15‬‬
‫پیمایش‌درخت‬
‌:‌‫ کد‌الگوریتم‌غیر‌باز‌گشتی‌برای‌پیمایش‌میان‌ترتیب‬
Thread-Inorder (T: Tree)
{
var P: position;
p = NEXT(T); // The next node in inorder traveral
while p ≠ Root do
{
write (p^.data);
p = NEXT(p);
}
}
16
‫پیمایش‌درخت‬
‫‪ ‬الگوریتم‌غیر‌باز‌گشتی‌برای‌پیدا‌کردن‌عنصر‌بعدی‌‌در‌پیمایش‌میان‌ترتیب‌‪:‬‬
‫‪Given a node Node, this algorithm returns its next node P in in-order traversal‬‬
‫‪NEXT (Node: Position):Position‬‬
‫{‬
‫;‪var P: position‬‬
‫‪p = Node^.RC; // P is the right child of Node‬‬
‫‪if Node^.RightIsThread == FALSE then‬‬
‫‪while p^.LeftIsThread == FALSE do‬‬
‫‪p = p^.LC‬‬
‫‪// P becomes its left child‬‬
‫‪// p is the next node in in-order traversal‬‬
‫;‪return p‬‬
‫}‬
‫‪ -1‬اگر‌اشاره‌گر‌سمت‌راست‌نخ‌باشد‌‪‌،‬گره‌بعدی‌در‌پیمایش‌میان‌ترتیب‌گرهی‌است‌که‌‪‌RC‬به‌آن‌اشاره‌میکند‌که‌در‌برنامه‌فوق‌با‌‪‌P‬‬
‫نشان‌داده‌شده‌است‌که‌‪‌Return p‬آنرا‌برمیگرداند‪‌.‬‬
‫‪ ‌-2‬اگر‌اشاره‌گر‌سمت‌راست‌نخ‌نباشد‌و‌به‌فرزند‌اشاره‌کند‌‪‌،‬الگوریتم‌برای‌پیدا‌کردن‌گره‌بعدی‌به‌سراغ‌گره‌سمت‌راست‌رفته‌و‌سپس‌تا‌‬
‫زمانیکه‌گره‌سمت‌چپ‌نخ‌نباشد‌‪‌،‬به‌سمت‌چپ‌میرود‪ ‌.‬چپ‌ترین‌فرزند‌زیر‌درخت‌راست‌گره‌بعدی‌در‌پیمایش‌میان‌ترتیب‌است‪.‬‬
‫‪17‬‬
‫گسترش‌مفهوم‬
‫‪ ‬در‌مدل‌فوق‌همچنان‌نیمی‌از‌اشاره‌گرها‌ی‌گره‌های‌برگ‌بدون‌استفاده‌‬
‫باقی‌می‌مانند‪‌.‬‬
‫‌‬
‫‪ ‬می‌توان‌از‌این‌اشاره‌گرهای‌استفاده‌نشده‌(اشاره‌گر‌فرزند‌چپ)‌برای‌اشاره‌‬
‫کردن‌به‌گره‌قبلی‌در‌پیمایش‌میان‌ترتیب‌استفاده‌کرد‪‌.‬‬
‫‌‬
‫‪‌ ‬با‌این‌کار‌می‌توان‌عمل‌پیمایش‌را‌به‌صورت‌برعکس‌(ترتیب‌از‌راست‌به‌‬
‫چپ‌میان‌ترتیب)‌‌انجام‌داد‌و‌یا‌حتی‌از‌آن‌برای‌پیمایش‌پس‌ترتیب‌‬
‫استفاده‌کرد‪.‬‬
‫‪18‬‬
‫گسترش‌مفهوم‬
‫‪ ‬مثال‪‌:‬توجه‌کنید‌که‌برخی‌از‌برگ‌ها‌با‌دو‌اشاره‌گر‌از‌نوع‌نخ‌به‌گره‌های‌پدران‌‪‌Ancestors‬‬
‫خود‌اشاره‌میکنند‪‌.‬‬
‫‪19‬‬
‫گسترش‌مفهوم‬
‫‪ ‬مثال‪‌:‬یک‌دودوئی‌درخت‌نخ‌کشی‌شده‌کامل‌و‌پیمایش‌میان‌ترتیب‌آن‌‬
‫‪‌H D B E A I K F J C G‬‬
‫‪20‬‬
‫جستجو‌در‌درخت‌دودوئی‌نخ‌کشی‌شده‌‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫جستجو ‌در ‌درخت‌های ‌نخ‌کشی ‌شده ‌بسیار ‌شبیه ‌روش ‌جستجو ‌در‌‬
‫درخت‌های‌جستجوی‌دودویی‌می‌باشد‪‌‌،‬‬
‫با‌این‌تفاوت‌که‌در‌اینجا‌باید‌به‌تفاوت‌بین‌اشاره‌گر‌از‌نوع‌نخ‌‌و‌اشاره‌گر‌به‌‬
‫فرزندان‌توجه‌ویژه‌ای‌داشته‌باشیم‪‌.‬‬
‫‌‬
‫‌در‌جستجو‪‌،‬زمانی‌که‌به‌گرهی‌که‌دارای‌اشاره‌گری‌از‌نوع‌نخ‌است‌‌برسیم‌‬
‫یعنی‌جستجو‌خاتمه‌یافته‌است‌و‌مقدار‌مورد‌نظر‌پیدا‌نشده‌است‪‌‌.‬‬
‫به ‌جز ‌این ‌مورد ‌تفاوتی ‌دیگر ‌میان ‌جستجوی ‌این ‌دو ‌گونه ‌درخت ‌وجود‌‬
‫ندارد‪.‬‬
‫‪21‬‬
‌‫جستجو در‌درخت‌دودوئی‌نخ‌کشی‌شده‬
‌‌‫ کد‌جستجو‌در‌درخت جستجوی‌دودوئی‌نخ‌کشی‌شده‬
‌‫‌باشد‬k‌‫‌‌‌ گرهی‌را‌پیدا‌کنیم‌که‌دارای‌لیبل‌مساوی‬
‌:‫‌اشاره‌گری‌به‌ریشه‌درخت‌است‬root‌‌‌‌
‌
NODE* search(PNODE root, int k) {
if(root->label == k) return root;
if( k < root->label) {//move toward left sub-tree
// root of sub-tree must be a real child,
// not being pointed by a thread
if(!root->LeftThread && root->leftChild != null)
return search(root->leftChild, k);
else return null;
}
if( k > root->label) {// move toward right sub-tree
// root of sub-tree must be a real child,
// not being pointed by a thread
if(!root->RightThread && root->rightChild != null)
return search(root->leftChild, k);
else return null;
}
}
22
‫جستجو در‌درخت‌دودوئی‌نخ‌کشی‌شده‌‬
‫‪ ‬درخت‌های‌نخ‌کشی‌شده‌برای‌درخت‌های‌دودوی‌بطور‌عام‌‬
‫تعریف‌شده‌اند‪‌.‬‬
‫‌‬
‫‪ ‬بنابراین‌میتوانیم‌درخت‌جستجوی‌دودوئی‌نخ‌کشی‌شده‌را‌نیز‌‬
‫تعریف‌کنیم‌و‌عملیات‌‬
‫‌‌‌جستجو‌‪‌‌،‬درج‌و‌‌حذف‌‬
‫‌‌را‌برای‌آن‌تعریف‌نمائیم‪.‬‬
‫‪23‬‬
‫درج‌گره‌جدید دریک‌‬
‫‌درخت‌جستجوی‌دودوئی‌نخ‌کشی‌شده‌‬
‫‪ ‬درج‌گره‌جدید‌در‌درخت‌های‌جستجوی‌دودوئی‌نخ‌کشی‌شده‌تفاوت‌چندانی‌‬
‫با‌درخت‌های‌جستجوی‌دودویی‌ندارد‪‌.‬‬
‫‌‌‌اما‌باید‌برای‌گره‌جدید‌نخ‌های‌آن‌را‌به‌گره‌بعد‌و‌قبل‌از‌آن‌متصل‌کرد‪‌.‬‬
‫‌‬
‫‪ ‬فرض ‌کنید ‌گره ‌جدید ‌‪‌ n‬که ‌به ‌درخت ‌اضافه ‌میشود ‌‪‌ ،‬فرزند ‌راست ‌پدرش‌‬
‫)‪‌‌(p‬باشد‪‌.‬‬
‫‌‌‌در‌این‌حالت‌گره‌قبلی‌‪‌n‬همان‌‪‌p‬می‌باشد‌(چرا؟)‌‪‌:‬خاصیت‌درخت‌جستجوی‌دودوئی‪‌.‬‬
‫‌‌‌و‌گره‌ی‌بعدی‌‪‌،‌‌n‬گره‌ی‌بعدی‌‪‌p‬قبل‌از‌اینکه‌‪‌n‬به‌درخت‌اضافه‌شود‪‌،‬است‪‌‌.‬‬
‫‌‬
‫‪‌ ‬حالت‌فرزند‌چپ‌بودن‌دقیقا‌قرینه‌حالتی‌است‌که‌در‌باال‌ذکر‌شد‪.‬‬
‫‪24‬‬
‫درج‌گره‌جدید در‌درخت‌جستجوی‌دودوئی‌نخ‌کشی‌شده‌‬
‫‪ ‬مثال‌‪‌:‬اضافه‌کردن‌گره‌‪5‬‬
‫‪Node n before insertion‬‬
‫‪6‬‬
‫‪6‬‬
‫‪8‬‬
‫‪8‬‬
‫‪3‬‬
‫‪7‬‬
‫‪5‬‬
‫‪1‬‬
‫‪3‬‬
‫‪7‬‬
‫‪Node 5‬‬
‫‪inserted‬‬
‫‪25‬‬
‫‪5‬‬
‫‪1‬‬
‫درج‌گره‌جدید در‌درخت‬
‌‫‌جستجوی‌دودوئی‌نخ‌کشی‌شده‬
‌ ‫ ‌به‌درخت‬n‌‫ کد‌تابع‌برای‌درج‌گره‌جدید‬
‌:‌)5‌‫‌‌‌‌(اضافه‌کردن‌گره‬
void insert(PNODE root, PNODE n) {
PNODE p;
// find p, the parent of n, using BST-insert
// parent of node 5 is node 3 in previous example
PNODE templ , tempr;
templ = p->leftChild; //left-child pointer of 3 before 5 is inserted
tempr = p->rightChild; //right-child pointer of 3 before 5 is inserted
// shown as a thread pointing to node 6
if(n->label < p->label) { //determine the left or right child
p->leftChild = n; p->LeftThread = false;
n->leftChild = templ; n->rightChild = p;
} else {
p->rightChild = n; p->RightThread = false;
n->leftChild = p; n->rightChild = tempr;
}
n->LeftThread = n->RightThread = true;
}
26
‫حذف‌یک‌گره‌در‌درخت‌جسسجوی‌دودوئی‬
‫‪ ‬در ‌حذف ‌گره ‌در ‌درخت‌های ‌جستجوی ‌دودوئی ‌نخ‌کشی ‌شده ‌‪‌ ‌ ،‬عالوه ‌بر‌‬
‫حفظ ‌ویژگی ‌درخت ‌جستجوی ‌دودویی ‌‌‪‌ ،‬باید ‌تعدادی ‌لینک ‌را ‌نیز ‌به ‌روز‌‬
‫رسانی‌کنیم‪‌‌.‬‬
‫‌‌‌گاهی‌این‌کار‌ممکن‌است‌آسان‌نباشد‪‌.‬‬
‫‌‬
‫‪ ‬در‌زمان‌حذف‌یک‌گره‌‪‌p‬باید‌‪‌2‬پارامتر‌زیر‌را‌بدانیم‌‪‌‌:‬‬
‫• پدر‌گره‌‪q:‌p‬‬
‫• ‪‌P‬فرزند‌راست‌پدرش‌‪‌q‬بود‌یا‌فرزند‌چپ‌آن‌‬
‫‌‬
‫‪ ‬با‌توجه‌به‌دو‌پارامتر‌‌باال‌‪‌4‌‌،‬حالت‌زیر‌برای‌حذف‌گره‌قابل‌تصور‌است‪‌.‬‬
‫‌‬
‫‪27‬‬
‫حذف‌گره‪‌:‬‬
‫‌حالت‌اول‬
‫‪‌p ‬دارای‌یک‌نخ‌در‌سمت‌راست‌و‌یک‌فرزند‌در‌سمت‌چپ‌باشد‪‌.‬‬
‫‌‬
‫‪ ‬در‌این‌حالت‌‪‌2‬عمل‌زیر‌را‌باید‌انجام‌دهیم‪‌:‬‬
‫‪ .1‬اشاره‌گر‌چپ‌‪‌q‬به‌فرند‌چپ‌‪‌p‬اشاره‌کند‪‌q.leftchild = p.eftchild .‬‬
‫‪ .2‬اگر ‌گره ‌قبلی ‌‪‌ p‬در ‌پیمایش ‌میان‌ترتیب ‌گره ‌‪‌ t‬باشد ‌(نخ ‌سمت ‌راست ‌‪‌ t‬به ‌‪‌ p‬اشاره‌‬
‫می‌کند)‪‌،‬آنگاه‌نخ‌سمت‌راست‌‪‌t‬را‌با‌نخ‌سمت‌راست‌‪‌p‬جایگزین‌می‌کنیم‪‌.‬‬
‫‌‌‌‌‌‌‌‪t.rightChild = p.rightChild‬‬
‫‪28‬‬
‌:‫حذف‌گره‬
‫‌حالت‌اول‬
‌:‫ کد‌برای‌حالت‌اول‬
//<find p, parent q, and right/left relation, determine the
//case>
q->leftChild = p->leftChild;
PNODE t = p->leftChild;
while(!t->RightThread) {
t = t->rightChild;
}
t->rightChild = p->rightChild;
29
‫حذف‌گره‪‌:‬‬
‫‌حالت‌دوم‬
‫‪‌p ‬دارای‌نخ‌سمت‌راست‌و‌نخ‌سمت‌چپ‌باشد‌یا‌به‌عبارت‌بهتر‌یک‌برگ‌‬
‫باشد‪‌.‬‬
‫‌‬
‫‪ ‬در‌این‌حالت‌تنها‌یک‌کار‌الزم‌است‪‌:‬اگر‌‪‌p‬فرزند‌چپ‌(راست)‌‪‌q‬بود‪‌،‬آنگاه‌‬
‫اشاره‌گر‌سمت‌چپ‌(راست)‌‪‌،q‬تبدیل‌به‌نخ‌میشود‪‌.‬‬
‫‪‌ ‬این‌اشاره‌گر‌‌به‌گره‌ای‌اشاره‌می‌کند‌که‌قبال‌نخ‌سمت‌راست‌(چپ)‌‪‌p‬به‌‬
‫آن‌اشاره‌می‌کرده‌است‪.‬‬
‫‪30‬‬
‌‌:‫حذف‌گره‬
‫حالت‌دوم‬
‌:‫ کد‌برای‌حالت‌دوم‬
//<find p, parent q, and dir, determine the case>
if(dir == "left") {
q->LeftThread = true;
q->leftChild = p->leftChild;
}
if(dir == "right") {
q->RightThread = true;
q->rightChild = p->rightChild;
}
31
‫حذف‌گره‪‌‌:‬‬
‫حالت‌سوم‬
‫‪ ‬فرزند‌سمت‌راست‌‪‌p‬یعنی‌‪‌ r‬دارای‌نخ‌سمت‌چپ‌باشد‪‌.‬‬
‫‪ ‬فرض‌کنید‌که‌‪‌q‬پدر‌‪‌p‬باشد‪.‬‬
‫‪ ‬در‌اینجا‌کافی‌است‌که‌‪‌r‬را‌با‌‪‌p‬جایگزین‌کرده‌و‌اشاره‌های‌مربوط‌را‌به‌روز‌‬
‫کنیم‪‌:‬‬
‫• ‪‌‌ q‬که‌به‌ ‪‌p‬اشاره‌میکرده‌‪‌،‬حاال‌به‌‌‪‌r‬اشاره‌کند‪‌.‬‬
‫• اشاره‌گر‌سمت‌چپ‌‪‌r‬مساوی‌اشاره‌گر‌سمت‌چپ‌‪‌p‬شود‪‌.‬‬
‫• هر‌گره‌دیگری‌که‌به‌‪‌p‬اشاره‌می‌کرد‌‪‌،‬اکنون‌به‌‪‌r‬اشاره‌کند‪(‌.‬مانند‌نخ‌گره‌‪‌)l‬‬
‫‪32‬‬
‫حذف‌گره‪‌:‬‬
‫‌حالت‌چهارم‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫فرزند‌سمت‌راست‌‪(‌p‬یعنی‌گره‌‪‌)r‬دارای‌فرزند‌چپ‌باشد‪‌.‬‬
‫‌‬
‫در‌این‌حالت‌باید‌گره‌ی‌بعدی‌‪‌p‬در‌پیمایش‌میان‌ترتیب‪‌،‬یعنی‌‪‌s‬را‌پیدا‌کنیم‪‌.‬‬
‫‌همچنین‌باید‌پدر‌‪‌،‌s‬بنام‌‪‌k‬را‌هم‌پیدا‌کنیم‪‌‌.‬‬
‫سپس‌‪‌s‬را‌جایگزین‌‪‌p‬کرده‌و‌در‌موارد‌الزم‌اشاره‌گرها‌را‌به‌روز‌کنیم‪‌.‬‬
‫‌‬
‫این‌حالت‌خود‌به‌‪‌2‬زیر‌حالت‌دیگر‌شکسته‌می‌شود‪.‬‬
‫‪33‬‬
‫حذف‌گره‪‌:‬‬
‫‌حالت‌چهارم‌(‪)1‬‬
‫‪ ‬در ‌این ‌حالت ‌‪‌ s‬خود ‌دارای ‌فرزند ‌راست ‌است ‌با ‌نام ‌‪‌ ،d‬اینجا ‌نیازی ‌به ‌بروز ‌کردن‌‬
‫اشاره‌گر‌نخ‌چپ‌‪‌d‬نیست‌زیرا‌به‌صورت‌پیش‌فرض‌به‌‪‌s‬اشاره‌می‌کند‪‌.‬‬
‫‪ ‬کارهای‌الزم‪‌:‬‬
‫• به‌روز‌کردن‌اشاره‌گر‌پدر‌‪(‌‌p‬یعنی‌‪‌)q‬که‌حاال‌باید‌به‌‪‌s‬اشاره‌کند‪‌.‬‬
‫• به‌روز‌کردن‌اشاره‌گر‌پدر‌‪‌.)‌k‌(‌s‬‬
‫• به‌روز‌کردن‌اشاره‌گر‌‪‌.‌s‬‬
‫• به‌روز‌کردن‌نخ‌سمت‌راست‌گره‌قبلی‌‪(‌p‬در‌پیمایش‌میان‌ترتیب)‌‌‌‬
‫‌‌‌ در‌این‌مثال‌گره‌قبلی‌‪‌p‬گره‌‪‌u‬است‪‌‌.‬‬
‫‌ ‌بنابر‌این‌نخ‌راست‌‪‌u‬بجای‌اینکه‌به‌‪‌p‬اشاره‌کند‌به‌‪‌s‬اشاره‌خواهد‌کرد‪‌‌.‬‬
‫‪34‬‬
‌:‫حذف‌گره‬
)1(‌‫‌حالت‌چهارم‬
‌:‫‌نوع‌اول‬،‫ کد‌برای‌حالت‌چهارم‬
<find p, s, k, d, parent p: q, and dir, determin the case>
if(dir == "right") {q->rightChild = s;}
if(dir == "left") {q->leftChild = s;}
s->hasLeftThread = false;
s->leftChild = p->leftChild;
s->rightChild = p->rightChild;
k->leftChild = d;
PNODE t = p->leftChild;
while(!t->hasRightThread) {
t = t->rightChild;
}
t->rightChild = s;
35
‫حذف‌گره‪‌:‬‬
‫‌حالت‌چهارم‌(‪)2‬‬
‫‪ ‬در‌این‌حالت‌‪‌s‬دارای‌نخ‌سمت‌راست‌است‪‌،‬یا‌به‌عبارت‌بهتر‌‪‌s‬یک‌برگ‌است‪‌.‬‬
‫‪ ‬تفاوت ‌این ‌حالت ‌با ‌حالت ‌قبل ‌این ‌است ‌که ‌اشاره‌گر ‌سمت ‌چپ ‌‪‌ k‬به ‌نوع ‌نخ ‌تغییر‌‬
‫حالت‌می‌دهد‪‌.‬‬
‫‪ ‬کارهای‌الزم‪‌:‬‬
‫•‬
‫•‬
‫•‬
‫•‬
‫‌‬
‫به‌روز‌کردن‌اشاره‌گر‌پدر‌‪‌.‌p‬‬
‫به‌روز‌کردن‌اشاره‌گر‌پدر‌‪‌.)‌k‌(‌s‬‬
‫به‌روز‌کردن‌اشاره‌گر‌‪‌.‌s‬‬
‫به ‌روز ‌کردن ‌نخ ‌سمت ‌راست ‌گره ‌قبلی ‌‪(‌ p‬در ‌پیمایش ‌میان‌ترتیب) ‌‪‌ .‬یعنی ‌بروز ‌کردن‌‬
‫نخ‌سمت‌راست‌‪‌u‬‬
‫‪36‬‬
‌:‫حذف‌گره‬
)2(‌‫‌حالت‌چهارم‬
‌:‫‌نوع‌دوم‬،‫ کد‌برای‌حالت‌چهارم‬
<find p, s, k, d, parent p: q, and dir, determin the case>
if(dir == "right") {q->rightChild = s;}
if(dir == "left") {q->leftChild = s;}
s->LeftThread = s->RightThread = false;
s->leftChild = p->leftChild;
s->rightChild = p->rightChild;
k->LeftThread = true;
PNODE t = p->leftChild;
while(!t->RightThread) {
t = t->rightChild;
}
t->rightChild = s;
37
‫پایان‬
‫قسمت‌دوم‌درخت‌ها‬
‫درخت‌‪AVL‬‬
‫‪38‬‬