شماره گذاری درخت فرکتال
در علوم کامپیوتر، درخت فرکتال یکی از انواع داده ساختارهای درخت است که میتواند اطلاعات را ذخیره و نگهداری کند و میتوان به اطلاعات آن دسترسی داشت یا همچنین اطلاعات مشخصی را در آن جستجو کرد. این داده ساختار شباهت زیادی به درخت دارد. این داده ساختار نیز شبیه درخت تعمیمی از درخت جست جوی دودویی است. در درخت جستجوی دودویی هر عضو دارای حداکثر دو بچه است (اصطلاحاً فرزند چپ و راست) ولی در درخت فرکتال هر عضو میتواند تعداد دلخواهی فرزند داشته باشد و معمولاً یک عدد به عنوان حداکثر تعداد فرزندان وجود دارد که هنگام ساختن فرکتال داده میشود. در این داده ساختار در هر عضو تعدادی کلید وجود دارد که در هنگام جستجو به کار میآید. همچنین در هر عضو از درخت فرکتال، حافظهای وجود دارد که میتواند اطلاعات رو ذخیره کند. این حافظه بسیار شبیه به حافظه نهان است. درخت فرکتال کاربرد زیادی در دستگاههای ورودی خروجی دارد و در ادامه خواهیم دید که که این ساختار برای حافظههای خارجی بسیار مناسب است.
محتویات اعضا
همانطور که بیان شد هر عضو دارای یک لیست از کلیدها است. کلیدها مسئولیت جداسازی اطلاعات را هنگام اضافهشدن آنها به فرکتال دارند که در نتیجه تعداد کلیدها یکی کمتر از تعداد فرزندان است. برای مثال فرض کنید یک عضو دارای کلید های
حال در اینجا با استفاده از زبان برنامهنویسی پایتون یک کلاس برای اعضا مینویسیم.
class Node:
def __init__(self, max_child, max_cache, key):
self.max_cache = max_cache
self.cache = []
self.max_child = max_child
self.child = []
self.key = key
def isfull(self):
if len(self.cache) == self.max_cache:
return True
else:
return False
درج عضو جدید
برای اضافه کردن یک عضو جدید به صورت بازگشتی عمل میکنیم. فرض میکنیم یک مقدار و یک عضو فرکتال به ما داده شدهاست. اگر حافظه نهان آن عضو دارای ظرفیت خالی بود آن مقدار (شی) را به آن اضافه میکنیم. در غیر این صورت زیر درختی که این مقدار باید در آن اضافه شود را پیدا میکنیم و تابع درج را به صورت بازگشتی برای آن مقدار (شی) فراخوانی میکنیم. در حالتی که ریز درختی که باید مقدار به آن اضافه شود تهی بود، یک برگ جدید ساخته و آن را فرزند عضو فعلی قرار داده و تابع را برای عضو جدید ساخته شده دوباره فراخوانی میکنیم. بقیه توابع مانند جستجو، حذف و … شبیه داده ساختار درخت است با این تفاوت که هر عضو خود دارای یک لیست از مقادیر است به جای یک مقدار.
def insert(node, value):
if node.isfull == False:
node.cache += [value]
else:
for i in range(len(node.key)):
if value <= node.key[i]:
if node.child[i] != None:
return insert(node.child[i], value)
else:
new = Node (node.max_child, node.max_cache, node.key)
new.cache += [value]
node.child[i] = new
return insert(new, value)
return 0
تحلیل زمانی درخت فرکتال
در اینجا فرض میکنیم درخت فرکتال متوازن است. فرض کنید یک راس در فرکتال حداکثر
زمان جستجو در یک فرکتال همانند درخت است. در هر مرحله باید لیست مقادیر راسی که در آن هستیم را چک کنیم که این
اما مدت زمان جسجو در درخت
هزینه حذف کردن هم که برابر با هزینه جستجو است. (در واقع اگر بدانیم مقداری که میخواهیم حذف کنیم در کدام راس است هزینه حذف
مقایسه فرکتال با درخت
در بالا هزینههای زمانی فرکتال و درخت رو با هم مقایسه کردیم. اما این دو از نظر مقدار حافظه بسیار متفاوت هستند. در درخت هر عضو B بچه دارد و در نتیجه هر راس حافظهای از مرتبه B دارد. اما در فرکتال هر عضو دارای
یکی دیگر از مزیتهای فرکتال زمانی است که از این الگوریتم در حافظه دیسکها استفاده شود. فرض کنید اطلاعات را در دو دیسک ذخیره کردهاید که یکی با الگوریتم درخت و دیگری با فرکتال کار میکند. در این صورت میدانیم هزینه دسترسی و خواندن اطلاعات از دیسک بسیار زیاد است و میخواهیم تا جای ممکن دسترسی به دیسک را کاهش دهیم. در این صورت در دیسکی که با الگوریتم درخت کار میکند برای خواندن یک مقدار باید ابتدا ان را جستجو کرد و سپس آن را از دیسک خواند و به حافظه نهان آورد. حال برای مقدار بعدی دوباره باید همین کار را انجام داد. اما اگر دیسک با الگوریتم فرکتال کار کند بعد از پیدا کردن مقدار میتوان کل حافظه نهان راس را به حافظه نهان آورد و طبق اصل محلی دسترسیها، تعداد دسترسیها به حافظه کمتر میشود و مخصوصاً زمانی که بخواهیم عمل نوشتن در حافظه انجام دهیم این اختلاف محسوس تر است.