درخت جستجوی دودویی

یک درخت جستجوی دودویی با اندازه ۹، عمق ۳، ریشه ۸ و برگ‌های ۱، ۴، ۷ و ۱۳.
در علوم رایانه، درخت جستجوی دودویی که گاهی اوقات درخت دودویی مرتب هم نامیده می‌شود، یک ساختار داده است و نوعی درخت دودویی است.
تعریف
درخت جستجوی دودویی، نوعی درخت دودویی است که ممکن است تهی باشد، اگر تهی نباشد، دارای خصوصیات زیر است:
از تعدادی گره تشکیل شده که هر گره دارای یک کلید است. کلیدها منحصربه‌فرد هستند و در درخت کلید تکراری وجود ندارد.
تمام کلیدهایی که در زیردرخت سمت چپ واقع شده‌اند، کوچکتر از کلید گره ریشه هستند.
تمام کلیدهایی که در زیردرخت سمت راست واقع شده‌اند، بزرگتر از کلید گره ریشه هستند.
زیردرخت سمت راست و زیردرخت سمت چپ خود درختان جستجوی دودویی هستند.
این ویژگی تضمین می‌کند که پیمایش میان‌ترتیب یک درخت جستجوی دودویی، کلیدها را به ترتیب صعودی نمایش می‌دهد.
عملیات اصلی بر روی درخت جستجوی دودویی
معمولا عملیات زیر بر روی یک درخت جستجوی دودویی تعریف می‌شود:
ایجاد یک درخت جستجوی خالی
آزمایش خالی بودن درخت
درج کردن یک کلید جدید در درخت، بدون برهم خوردن خاصیت درخت
جستجو کردن و یافتن یک کلید خاص در درخت
حذف کردن یک کلید از درخت، با حفظ خاصیت درخت
پیمایش درخت جستجوی دودویی، به طوری تمام گره‌ها دقیقا یک بار مورد دسترسی قرار گیرند.
جستجو
برای پیدا کردن گرهی با یک کلید خاص مانند key در درخت، ابتدا باید از ریشه درخت شروع کنیم. اگر ریشه تهی باشد، درخت فاقد هر عنصری بوده و جستجو ناموفق خواهد بود. در غیر این صورت، key را با مقدار گره ریشه مقایسه می‌کنیم، اگر برابر بودند، جستجو موفق است و گره ریشه همان گره مورد نظر است. در غیر این صورت، دو حالت پیش خواهد آمد:
key از گره ریشه کوچکتر است. در این حالت، هیچ عنصری در زیردرخت سمت راست وجود ندارد که مقدار کلید آن برابر با key باشد؛ بنابراین جستجو باید در زیردرخت سمت چپ ادامه یابد.
key بزرگتر از گره ریشه است. در این حالت، هیچ عنصری در زیردرخت سمت چپ وجود ندارد که مقدار کلید آن برابر با key باشد؛ بنابراین جستجو باید در زیردرخت سمت راست ادامه یابد.
سپس بسته به حالت یک و دو، زیردرخت سمت چپ یا زیردرخت سمت راست را به روش بازگشتی و با استفاده از الگوریتم بالا جستجو می‌کنیم. عمل جستجو در درخت جستجوی دودویی، از مرتبه O(h) است که در آن h ارتفاع درخت است. چرا که حداکثر باید به میزان عمق درخت، به طرف پایین حرکت کنیم.
node_t search(node_t *root, T value)
if(NULL != root)
if(root->key == value)
return root;
else if(value key)
search(root->left, value)
else
search(root->right, value)
return NULL;
درج عنصر جدید
برای درج کردن یک گره جدید در درخت جستجوی دودویی، باید گره را طوری درج کرد که خاصیت درخت برهم نخورد و درخت همچنان یک درخت جستجوی دودویی باقی بماند. برای حفظ خاصیت اول (منحصربه‌فرد بودن کلیدها)، باید ابتدا درخت را جستجو کنیم تا مطمئن شویم که عنصر قبلا در درخت درج نشده است. پس از اینکه مطمئن شدیم کلید مورد نظر از قبل در درخت وجود ندارد، می‌توانیم کلید را در درخت درج کنیم. اگر درخت تهی بود، کافیست گره جدید را به عنوان گره ریشه درج کنیم تا عمل درج خاتمه یاد. اگر درخت خالی نبود، کلید جدید را ریشه مقایسه می‌کنیم، که دو حالت جستجو پیش می‌آید:
کلید جدید از ریشه کوچکتر است. در این حالت گره باید در زیردرخت سمت چپ درج شود. مراحل بالا را به روش بازگشتی ادامه می‌دهیم تا مکان مورد نظر در درخت پیدا شود. سپس گره را درج می‌کنیم.
کلید جدید از ریشه بزرگتر است. در این حالت گره باید در زیردرخت سمت راست درج شود. مراحل بالا را به روش بازگشتی ادامه می‌دهیم تا مکان مورد نظر در درخت پیدا شود. سپس گره را درج می‌کنیم.
عمل درج در درخت جستجوی دودویی، از مرتبه O(h) است.
typedef int T
void insert(node_t **tree, T data)
node_t *temp;
if(!(*tree))
temp = malloc(sizeof(node_t));
temp->left = temp->right = NULL;
temp->key = data;
*tree = temp;
return;
if(data key)
insert(-(*tree)->left, data);
if(data> (*tree)->key)
insert(-(*tree)->right, data);
حذف یک گره
فرض کنید می‌خواهیم گره i را از درخت جستجوی دودویی حذف کنیم. به طوری که P(i) نشان‌دهنده والد گره i و C(i) نشان‌دهنده فرزند گره i است (چپ یا راست). در مورد حذف یک گره از درخت دودویی، سه حالت مختلف پیش می‌آید:
i یک گره برگ است.
i یک فرزند دارد.
i دو فرزند دارد.
در حالت اول، کافیست اشاره‌گر مناسبی (چپ یا راست) از P(i) را برابر تهی قرار دهیم، عمل حذف خاتمه می‌یابد. در حالت دوم که i یک فرزند دارد، ابتدا گره i را حذف می‌کنیم، سپس فرزند i یا همان C(i) را جانشین گره i می‌کنیم.
در حالتی که i دو فرزند دارد، باید بزرگترین عنصر در زیردرخت چپ یا کوچکترین عنصر در زیردرخت راست را پیدا کرده و سپس آن را با گره i جایگزین و تعویض می‌کنیم. سپس ما این فرایند را با حذف کردن این عنصر جایگزین از زیردرختی که از آن گرفته شده است، دنبال می‌کنیم. به عبارتی دیگر، اگر بخواهیم گره N را از درخت حذف کنیم (که این گره دو فرزند دارد)، به جای اینکه خود گره N را پاک کنیم، یا گره بعد از N در پیمایش میانوندی یا گره قبلی N در پیمایش میانوندی را انتخاب می‌کنیم و آن گره را R می‌نامیم. سپس مقادیر N و R را تعویض کرده و سپس R را از درخت حذف می‌کنیم.
پیمایش درخت
پیمایش درخت بدین معنی است که به همه عناصر به ترتیب خاصی دسترسی داشته باشیم، بدون اینکه گرهی جا بیفتد یا اینکه گرهی دوبار در دسترس قرار گیرد. درخت جستجوی دودویی یک درخت دودویی است که می‌توان آن را به روش‌های معمول پیمایش کرد. اما از آنجا که نحوه قرار گرفتن عناصر در یک درخت جستجوی دودویی، تضمین می‌کند در هنگام پیمایش درخت به صورت میانوندی، عناصر به ترتیب صعودی در دسترس قرار گیرند، ما این نوع پیمایش را در ادامه بررسی می‌کنیم. درخت جستجوی دودویی به روش پیش‌ترتیب و پس‌ترتیب هم می‌توان پیمایش کرد، اما این نوع پیمایش‌ها در یک درخت جستجوی دودویی بیهوده هستند. پیمایش میانوندی بدین شکل تعریف می‌شود:
اگر زیردرخت سمت چپ وجود دارد، آن را به روش میانوندی پیمایش کنید.
ریشه درخت را ملاقات کنید.
اگر زیردرخت سمت راست وجود دارد، آن را به روش میانوندی پیمایش کنید.
الگوریتم بالا بازگشتی است.
void inorder(node_t *root)
if(!root)
if(root->left)
inorder(root->left)
process(root->key);
if(root->right)
inorder(root->right);
انواع
درخت جستجوی دودویی گونه‌های مختلفی دارد. درخت ای‌وی‌ال و درخت سرخ-سیاه از جمله درخت جستجوی دودویی خود-متوازن هستند. درخت اسپلی نوعی درخت دودویی است که عناصری که مکررا مورد استفاده قرار می‌گیرند را به صورت خودکار به ریشه درخت نزدیک می‌کند تا دسترسی به آنها راحت‌تر شود. در یک تریپ، (tree heap) هر گره یک اولویت دارد که این اولویت به شکل تصادفی به گره اختصاص می‌یابد و گره والد اولویت بیشتری نسبت به فرزندش دارد. درختان تانگو نوعی درخت جستجوی دودویی هستند که برای جستجوهای بسیار سریع مورد استفاده قرار می‌گیرند.
الگوریتم جستجوی دودویی
جستجوی درختی
درخت جستجوی دودویی خود-متوازن
درخت ای‌وی‌ال
درخت سرخ-سیاه
داده ساختار تیریپ
درخت جستجوی دودویی بهینه