Transcript Document

‫ساختمان داده ها‬
‫متغیر ‪ :‬نامی است برای قسمتی از حافظه یا سلولی از حافظه ‪.‬‬
‫تعریف متغیرها در زبان ‪ c‬دو چیز را مشخص می کند ‪.‬‬
‫اول ‪ :‬این که متغیر به چه میزان حافظه نیاز دارد‬
‫دوم ‪ :‬رشته بیتی ذخیره شده در آن حافظه چگونه تفسیر میشود ‪.‬‬
‫معموال هر متغیر کاراکتری یک بایت‪،‬صحیح دو بایت‪ ،‬اعشاری چهاربایت و مضاعف ‪double‬‬
‫هشت بایت فضا را اشغال می کند که به آن سایز متغیر می گویند ‪.‬‬
‫برای تعریف اشاره گرها از فرمول روبرو استفاده می کنیم ‪:‬‬
‫; نام * نوع‬
‫مثال ‪:‬‬
‫; ‪Char * p‬‬
‫آرایه های یک بعدی‪:‬‬
‫آرایه ساده ترین ساختمان داده است که در زبان ‪ c‬از آن استفاده می شود‪ .‬آرایه انواع مختلفی دارد‬
‫ساده ترین نوع آرایه ‪ ،‬آرایه ی یک بعدی است ‪ .‬از دیدگاه تعریف آرایه مجموعه ای محدود از نوع‬
‫همگن است ‪.‬‬
‫برای تعریف آرایه از فرمول زیر استفاده می کنیم‪:‬‬
‫; [تعداد عناصر آرایه] نام آرایه نوع‬
‫مثال‪:‬‬
‫; ]‪Char x[10‬‬
‫آرایه ها ناحیه ی پیوسته را به خود اختصاص می دهند‪.‬‬
‫برای بدست آوردن تعداد خانه های آرایه ی یک بعدی از فرمول زیر کمک می گیریم‪:‬‬
‫‪ +1‬حد پایین ‪-‬حد باال‬
‫آرایه های دو بعدی‪:‬‬
‫یک آرایه ی دو بعدی از دیدگاه برنامه نویس شبیه به یک جدول است‪.‬میتوان آن را همانند آرایه ای‬
‫از آرایه ها تصور کرد ‪ ،‬اما بر خالف تصور برنامه نویس حافظه شکل جدولی ندارد ‪.‬‬
‫مثال‪:‬‬
‫; ]‪Char x[3][5‬‬
‫کامپیوتر می بایست دیدگاه منطقی را که حالت جدولی دارد به صورت دیدگاهی فیزیکی در آورد و‬
‫آرایه را در سلول های حافظه که به صورت دنباله ای از بایت ها هستند پیاده سازی کند ‪ .‬بدین‬
‫منظور به دو روش می تواند عمل کند روش سطری و روش ستونی‪.‬‬
‫در روش سطری عناصر آرایه سطر به سطر در حافظه قرار می گیرد ودر روش ستونی عناصر‬
‫آرایه ستون به ستون در حافظه ریخته می شود‪.‬‬
‫محاسبه ی آدرس ]‪ X[i,j‬به روش سطری‬
‫فرض کنید تعداد سطر های آرایه برابر با ‪row‬و تعداد ستونها برابر با ‪ col‬باشد ‪.‬‬
‫روش سطری‪:‬‬
‫‪X [i] [j]=base + (I *col+i)*size‬‬
‫روش ستونی‪:‬‬
‫‪X [i] [j]=base + (j *row+i)*size‬‬
: ‫آرایه های سه بعدی‬
‫ تعداد سطر ها‬: row
Base + (i*col +j)*size
Col :‫تعداد ستونها‬
H : ‫ارتفاع‬
Base + (k * row * col + I * col + j) * size
k = h X[k][i][j]
I = row
J = col
Base + ( l * h* row * col + k * row *col + I * col +j) * size
L = t X[l][h][i][j]
H=k
I = row
J = col
‫چند روش مختلف برای ذخیره سازی اعداد در آرایه های سه بعدی‬
Base +( k+row * col +I *col +j ) *size
Base +( k+row *col + j *row +i) *size
Base ( i * h * col + k * col +j ) *size
Base ( j * h * row +k * row + i) *size
‫نمایش چند جمله ای ها به کمک آرایه‪:‬‬
‫چند جمله ای زیر را در نظر بگیرید می توان آنرا به کمک آرایه ها پیاده سازی کرد روشهای مختلفی‬
‫برای این کار وجود دارد مثال می توان بزرگترین درجه ای که در چند جمله ای می تواند وجود‬
‫داشته باشد به عنوان ‪ Max‬درنظر گرفت دراین صورت می توان آرایه ای تعریف کرد که تعداد‬
‫سلول های ان برابر با ‪ Max+1‬باشد ‪.‬‬
‫‪4x^5+3x^2_6x+1‬‬
‫‪5x^2-7‬‬
‫]‪A[i‬اگر درجه چند جمله ای را بدانیم میتوان هر جمله را در آرایه پیاده سازی کرد در واقع ضریب‬
‫)‪ X^(n-i‬خواهد بود‪.‬‬
‫پس از ذخیره چند جمله ای ها در داخل آرایه ها می توان اعمالی مانند جمع چند جمله ای و ضرب‬
‫چند جمله ای را انجام داد ‪.‬‬
‫حاصل جمع دو عبارت باال‬
‫‪4x^5+8x^2-6x-6‬‬
‫روش قبل برای ذخیره سازی چند جمله ای ممکن است مناسب نباشد برای مثال چند جمله ای شما‬
‫ممکن است ‪ x^1000+1‬باشد ‪.‬‬
‫روش دیگری نیز برای ذخیره چند جمله ای ها وجود دارد دراین روش از یک آرایه با دو سطر و‬
‫‪k‬ستون استفاده می شود ‪.‬‬
‫نکته ‪ k :‬تعداد کل جمالت تشیکل دهنده ی همه چند جمله ای هاست‪.‬‬
‫ماتریس پراکنده یا اسپارس‪:‬‬
‫برای ذخیره ی یک ماتریس ‪M*N‬می توان از یک آرایه ی دو بعدی با ‪ m‬سطر و ‪n‬ستون‬
‫استفاده کرد گروهی از ماتریسها وجود دارد که به آن ماتریس خلوت یا اسپارس می گوییم‪ .‬در این‬
‫ماتریس ها اکثریت عناصر مقدار صفر دارند ‪.‬‬
‫از آنجاییکه ماتریس های اسپارس در عمل وجود دارندوبرخی موارد اندازه های آنها بسیار بزرگ‬
‫است می بایست روش بهینه تری را برای ذخیره آنها در کامپیوترارائه کنیم ‪ .‬یک روش آن است‬
‫که ازیک آرایه دو بعدی با سه ستون استفاده کنیم ‪ .‬ستون های اول و دوم این آرایه موقعیت‬
‫سطروستون مقداردر ماتریس اسپارس رانشان می دهند و ستون سوم مقدار ذخیره شده در آن‬
‫سطر و ستون رانشان میدهند ‪(.‬تعداد سطرهای آین آرایه به تعداد مقدار ذخیره شده در ماتریس‬
‫اصلی است )‬
:‫برای پیاده سازی ماتریس اسپارس میتوان از یک ساختمان کمک گرفت‬
Struct elements
{
Int row, col ,value ;
{;
void main()
{
Elements s[max];
S[0].row=0;
S[0].col=0;
S[0].value=7;
}
‫ترانهاده ماتریس (ماتریس معکوس)‬
‫برای بدست آوردن ترانهاده یک ماتریس باید جای سطرو ستون ها راعوض می کنیم در نتیجه‬
‫عنصری که روی مکان ]‪[i][j‬ازماتریس اولیه قرارداردبه مکان ]‪[j][i‬درماتریس ثانویه منتقل میشود‪.‬‬
‫در ماتریس اسپارس ساده ترین راه جهت تولید معکوس آن این است که ابتدا دنبال عناصر بگردیم که‬
‫در ستون صفر ماتریس قرار دارد آنها را به ترانهاده منتقل کرد به گونه ای که جای سطروستون‬
‫عوض شود سپس برای ستون یک و غیره این کار انجام شود‪.‬‬
‫ساختمان ‪:‬‬
‫برای پیاده سازی یک ساختمان از فرمول زیر کمک می گیریم ‪:‬‬
‫نام ساختمان ‪Struct‬‬
‫{‬
‫اجزای ساختمان‬
‫;}‬
‫مثال ‪:‬‬
‫‪Struct rect‬‬
‫{‬
‫; ‪Int x,y,s,p‬‬
‫;}‬
‫پشته ها یا ‪:Stack‬‬
‫پشته مجموعه ای مرتب از چند قلم داده است که عمل درج یا حذف اقالمی یا عناصری از مجموعه ای‬
‫آن فقط از با الی پشته امکان پذیر است (مثل خشاب اسلحه)‪.‬‬
‫(آخرین ورودی اولین خروجی ()‪LIFO (last in first out‬‬
‫در زبان‪ C‬نوع داده ای مثل پشته نداریم می بایست به وسیله ساختارهای موجود پشته را شبیه سازی‬
‫کنیم به عنوان مثال می توان از یک آرایه جهت نگهداری عناصر پشته استفاده کرد‪.‬پشته ای که در آن‬
‫هیچ عنصری وجود نداشته باشد پشته خالی نام دارد ‪.‬‬
‫بر اساس پشته ای که ارائه شد دو عمل روی پشته می توان انجام داد‪:‬‬
‫‪ -1‬درج عنصرجدیددرباالی پشته‪:‬به این کار ‪Push‬گفته میشود برای انجام این عمل به دوپارامترنیاز‬
‫داریم یکی نام پشته ای که می خواهیم در آن درج کنیم و دوم نام عنصری که قرار است در پشته درج‬
‫شود‪.‬‬
‫‪-2‬عمل حذف ازباالی پشته‪ :‬که به آن ‪ Pop‬می گوییم‪ ،‬برای انجام این عمل فقط الزم است نام پشته را‬
‫بدانیم‪.‬‬
‫از دیدگاه تئوری پشته یک فضای نامحدود است که می توان به هر تعداد عنصر در آن درج کنیم اما‬
‫در عمل به علت محدود بودن فضا چنین چیزی امکان پذر نیست‪.‬‬
‫همان طور که واضح است نمی توان از یک پشته خالی عمل حذف را انجام داد بنابراین برا ی حذف‬
‫باید از خالی نبودن پشته اطمینان حاصل شود‪.‬‬
‫در زبان ‪ C‬نوع پیش فرضی به نام پشته وجود ندارد بنابراین میبایست پشته رابا استفاده از ساختار‬
‫های موجود در این زبان شبیه سازی کنیم بنابراین پیاده سازی یک ساختارپشته ای و‪Push, pop‬‬
‫همگی به عهده برنامه نویس است‪.‬‬
‫پیاده سازی پشته در زبان ‪:C‬‬
‫برای اینکه بتوانیم پشته را به کمک آرایه پیاده سازی کنیم می بایست بدانیم که تا این لحظه چه تعداد‬
‫از سلول های آرایه بوسیله پشته پرشده است بدین منظور از متغیری استفاده می کنیم که‬
‫موقعیت‬
‫باالترین عنصر پشته را در آرایه به ما نشان می دهد به این متغیر ‪ Top‬می گویند ‪.‬‬
‫درج ‪ : Top ++‬ورود عنصر جدید‬
‫‪:‬خروج عنصر‬
‫حذف‪Top --‬‬
‫‪# Define max 100‬‬
‫‪Struct stack‬‬
‫{‬
‫; ]‪Char items [max‬‬
‫;‪Int top‬‬
‫;}‬
‫مقدار اولیه ‪ Top‬باید ‪ -1‬انتخاب شود تا بتوان از تمام آرایه ها استفاده کرد بنابراین اگر ‪(-1),top‬‬
‫باشد به این معناست که پشته خالیست‪.‬‬
‫پیاده سازی تابع ‪:Empty‬‬
‫این تابع در صورتی که پشته خالی باشد مقدار (‪ )1‬و در غیر این صورت (‪ )0‬را برگشت می زند پس‬
‫تابع ‪empty‬باید از نوع ‪ INT‬باشد‪.‬‬
Int empty (stack *p)
{
If (p->top==-1)
Return (1);
Else
Return (0);
}
‫آدرس یک متغیر از نوع پشته را دریافت می کند‬
:Push ‫پیاده سازی تابع‬
void Push (stack *p , char x)
{
If (p->top == max -1)
Printf )“stack is full”(;
Else
{
P->top++;
P->items [p->top]=x;
}
}
: Pop ‫پیاده سازی تابع‬
char Pop (stack *p)
{
Char x;
If (empty (p))
Printf)“stack is empty”(;
Else
{
x= p->items [p->top];
p->top- -;
return (x);
}
}
‫هر تالش برای حذف از پشته خالی منجر به وقوع رخدادی به نام پایریز)‪ (under flow‬می شود و‬
‫هر تالش برای درج در پشته پر موجب سرریز یا )‪)Overflow‬می شود ‪.‬‬
‫کاربرد پشته ها‪:‬‬
‫عبارتهای پیشوندی ‪Prefix‬‬
‫عبارتهای میانوندی ‪Infix‬‬
‫‪Postfix‬‬
‫عبارتهای پسوندی‬
‫برای بدست آوردن ‪Postfix‬ازیک عبارت ‪Infix‬باید تقدم عمگرها را در نظر داشت‪.‬ساده ترین راه‬
‫برای تبدیل ‪ infix‬به ‪postfix‬آنست که عبارت را براساس تقدم عمگرها پرانتزگذاری کنیم ‪.‬سپس از‬
‫پرانتزهای داخلی شروع کرده و موقعیت هر عملگر را به نزدیکترین پارانتز بسته ای که قبال‬
‫اشغال نشده جا به جا کنیم‪.‬‬
‫مثال‪:‬‬
‫)‪(((A / B)-((C * D)/E))+F‬‬
‫‪infixpostfix= ab / cd *e/-f+‬‬
‫برای تبدیل ‪Postfix‬به ‪Infix‬می توان از یک پشته خالی کمک گرفت بدین منظورازابتدای عبارت‬
‫‪ postfix‬شروع کرده با مشاهده هر عملوند آنرا به باالی پشته اضافه کنید و با دیدن هر عملگر دو‬
‫عنصر باالی پشته را برداشته عملگر راروی آن اعمال کرده حاصل را مجددا به پشته اضافه می کنیم‪.‬‬
‫مثال‪:‬‬
‫‪A + B/C‬‬
‫برای تبدیل ‪ Postfix‬به ‪ Infix‬شبه کد زیر آورده می شود ‪.‬‬
‫شبه کد ‪ :‬برنامه ای که جزییات در آن در نظر گرفته نمی شود ‪.‬‬
‫‪ABC /+‬‬
‫)‪((A * B) + C‬‬
‫‪AB * C +‬‬
‫‪(A + (B / C) :‬‬
‫تبدیل ‪ infix‬به ‪: prefix‬‬
‫(‪)infix  prefix‬‬
‫براي تبدیل ‪ infix‬به ‪ prefix‬نیز همانند تبدیل ‪ infix‬به ‪ postfix‬عمل مي كنیم فقط به جاي اینكه‬
‫از ابتداي عبارت شروع كنیم از انتهاي آن آغاز مي كنیم‪.‬‬
‫به مثال زیر توجه كنید‪:‬‬
‫))‪((A+ ((B / C) *E )) - (G * H‬‬
‫‪infix  prefix :- + A * / BCE * GH‬‬
‫تبدیل ‪ prefix‬به ‪: infix‬‬
‫)‪(prefix  infix‬‬
‫در این تبدیل نیز همانند تبدیل ‪ postfix‬به ‪ infix‬عمل میكنیم منتهي از آخر عبارت شروع مي كنیم تا‬
‫به ابتداي آن برسیم‪.‬به مثال زیر توجه كنید‪:‬‬
‫‪+ * ABC‬‬
‫‪prefix  infix: A * B+C‬‬
‫‪ s‬یک رشته خالی است‬
‫) به انتهای رشته ورودی نرسیده ای( ‪While‬‬
‫{‬
‫;نماد بعدی در رشته ورودی = ‪Symb‬‬
‫) ‪ symb‬یک عملوند است( ‪If‬‬
‫;) ‪Push (s , symb‬‬
‫‪Else‬‬
‫{‬
‫;)‪Op2 = pop (s‬‬
‫;)‪Op1 = pop (s‬‬
‫;)عبارت حاصل از ‪Push (s , op1 symb op2‬‬
‫}‬
‫}‬
‫شبه کد تبدیل‪ prefix‬به ‪:infix‬‬
‫‪ s‬یک رشته خالی است‬
‫) به ابتدای رشته ورودی نرسیده ای( ‪While‬‬
‫{‬
‫;نماد قبلی در رشته ورودی = ‪Symb‬‬
‫) ‪ symb‬یک عملوند است( ‪If‬‬
‫;) ‪Push (s , symb‬‬
‫‪Else‬‬
‫{‬
‫;)‪Op2 = pop (s‬‬
‫;)‪Op1 = pop (s‬‬
‫;)عبارت حاصل از ‪Push (s , op2 symb op1‬‬
‫}‬
‫}‬
‫شبه کدی برای تبدیل ‪ infix‬به ‪Postfix‬از ابتدای عبارت‪ infix‬شروع کرده و با دیدن هر عملوند‬
‫آنرا درخروجی چاپ می کنیم و با دیدن هر عملگر آنرا به پشته اضافه می کنیم به شرطی که تقدم‬
‫عملگر موجود در باال کمترازعملگر مشاهده شده باشد در غیر این صورت عملگر های موجود‬
‫درپشته را آنقدر ‪ Pop‬می کنیم و چاپ می کنیم ‪ .‬تا زمانی که به پشته خالی برخورد کنیم یا با‬
‫عملگرتقدم کمتری برخورد نماییم دراین لحظه عملگرمشاهده شده را به پشته می افزاییم و پس‬
‫از رسیدن به انتهای عبارت عملگرهای موجود در پشته را یکی یکی ‪Pop‬کرده و مشاهده می‬
‫کنیم ‪.‬‬
‫مثال دیگری از کاربرد پشته ها‪:‬‬
‫فرض کنید بخواهید یک عبارت شامل پرانتز گذاری ها را از نظر صحت بررسی کنید بدین منظور می‬
‫توان از ابتدای عبارت شروع کرد و با مشاهده هر پرانتز باز یک واحد اضافه و پرانتز بسته یک‬
‫واحد کم نمود ‪.‬‬
‫)‪(1(2A + (3B / C2)* E1)-F0‬‬
‫)‪(1A + B0) -1‬‬
‫شرایط زیراگر برقرار باشد عبارت معتبر است‪:‬‬
‫اوال ‪ :‬در خاتمه می بایست صفر به دست آید‪.‬‬
‫ثانیا ‪ :‬در طول مسیر هیچ گاه شماره منفی دیده نشود‪.‬‬
‫اما فرض کنید عبارت شما به جزپرانتز شامل کروشه و آکوالد بوده باشد در این صورت شماره گذاری‬
‫کمکی نخواهد کرد ‪ .‬ساده ترین روش جهت تست چنین عبارتی استفاده از پشته است ‪.‬‬
‫‪‬‬
‫})‪{A*(B+C‬‬
‫جهت بررسی عبارتی که به جز پرانتز ازمحدود کننده های دیگرمانند کروشه یا آکوالد کمک می گیرند‬
‫از پشته استفاده می کنیم ‪ .‬پیمایش عبارت را از ابتدای عبارت اغاز می کنیم‪.‬با دیدن هر باز کننده‬
‫آنرابه باالی پشته اضافه می کنیم وبا مشاهده هرخاتمه دهنده یک نمادازباالی پشته حذف می کنیم‬
‫نماد حذف شده می بایست با باز کننده ای که مشاهده شده مطاقبت داشته باشد‪.‬‬
‫شرایط غلط بودن عبارت‪:‬‬
‫مثال ‪({ )}:‬‬
‫‪-1‬خاتمه دهنده با عنصر باالی پشته مطابقت نداشته باشد‬
‫‪-2‬در طول پیمایش عبارت مجبور باشیم از پشته خالی حذف کنیم مثال ‪}(({ }) :‬‬
‫مثال‪{( )}) :‬‬
‫‪-3‬پس از خاتمه پیمایش پشته خالی نشده باشد‬
: ‫شبه کدی برای بررسی صحت عبارت‬
‫ یک رشته خالی است‬s
V=1;
While (‫)به انتهای رشته نرسیده ای‬
{
Symb = ‫; نماد ورودی بعدی‬
If ) symb == ‘)’ || symb == ‘]’ || symb == ‘{‘(
Push(s,symb);
If ) symb == ‘(’ || symb == ‘[’ || symb == ‘{’(
{
If (empty (s))
{
V=0;
Break ;
}
Else
{
Symb 2 = pop (s) ;
If ( !match (symb, symb 2))‫ دونماد را از نظر هم گروه بودن چک کند‬match‫فرض کنیم‬
{
V=0;
Break;
}//Else
}//if
}//while
If (!empty (s))
V=0;
If (v == 0)
Printf )“ ‫;(”عبارت غلط است‬
Else
Printf )“‫;(”عبارت صحیح است‬
}
‫صف‪:‬‬
‫صف مجموعه اي ازعناصر مرتب است كه هرعنصر از ابتداي صف حذف شده و در انتهاي صف‬
‫درج مي شود‪.‬‬
‫)‪FIFO (First In First Out‬‬
‫به صف نیز ‪Queue‬گفته مي شود‪.‬‬
‫از آنجا كه درج صف ازدوطرف انجام مي شود مي بایست موقعیت عنصرابتدا وانتهاي صف را بدانیم‬
‫معموال به عنصر ابتدا )‪ Front (F‬و به عنصر انتهاي صف ) ‪ Rear ( R‬گفته مي شود‪.‬‬
‫اعمال ابتدایي روي صف‪:‬‬
‫‪-1‬عمل درج در صف كه به آن‪Insert‬نیز گفته مي شود‪ .‬براي انجام عمل درج معموال به دو پارامتر‬
‫نیازمندیم ‪.‬‬
‫الف) صفي كه قرار است در آن عنصر جدید درج شود‪.‬‬
‫ب) عنصر جدید كه قرار است وارد صف شود‪.‬‬
‫‪-2‬عمل حذف از صف كه به آن ‪ Remove‬گفته مي شود ‪،‬این عمل در صورت خالي نبودن صف‬
‫عنصر اول را حذف مي كند‪،‬براي انجام عمل ‪.Remove‬به یك عمل نیاز داریم آن هم نام صف است‪.‬‬
‫صف نیز مانند پشته فضایي نامحدود تصور مي شود كه در عمل به علت نامحدود بودن فضا این گونه‬
‫نیست بنابراین باید در نظر گرفت كه تعداد اقالم درج شده در صف باعث سرریز نشود همچنین‬
‫واضح است كه از یك صف خالي نمي توان حذف كرد چون منجــر به پا ریز مي شود‪.‬‬
‫پیاده سازي صف در زبان‪: C‬‬
‫براي پیاده سازي صف از یك آرایه كمك مي گیریم ‪.‬جهت نگهداري موقعیت ابتدا و انتهاي صف‬
‫متغیر به نام هاي ‪ F,R‬در آرایه استفاده مي كنیم ‪ .‬دو‬
‫‪# Define Max 100‬‬
‫‪Struck Queue‬‬
‫{‬
‫;]‪Char Items [Max‬‬
‫;‪Int f, r‬‬
‫;}‬
‫پیاده سازي تابع‪:Insert‬‬
‫)‪Void Insert (Queue *q, Char x‬‬
‫{‬
‫)‪If (q r == Max-1‬‬
‫;)" ‪Print f ("Queue is full‬‬
‫‪Else‬‬
‫{‬
‫;‪q r ++‬‬
‫;‪q Items [q r] =x‬‬
‫}‬
‫}‬
:Remove‫پیاده سازي تابع‬
Char Remove (Queue *q)
{
Char x;
If (empty (q))
Print f ("Queue is empty");
Else
{
X=qItems [qf];
qf++;
Return(x);
}
}
‫پیاده سازي تابع‪:Empty‬‬
‫)‪Int empty (Queue *q‬‬
‫{‬
‫)‪If (q f >q r‬‬
‫;)‪return (1‬‬
‫‪else‬‬
‫;)‪return (0‬‬
‫}‬
‫صف به شكلي كه پیاده سازي شد یك ایراداساسي دارد وآن این است كه پس از تعدادي عمل درج‬
‫حذف ممكن است به حالتي ‪ r‬به آخرین اندیس آرایه رسیده باشدوعلي رغم خالي بودن و‬
‫خانه هاي قبل از ‪F‬برخورد نتوان عنصر دیگري به صف اضافه كرد ‪.‬‬
‫براي حل این مشكل راه حل هایي وجود دارد مثال مي توان لحظه ي رسیدن‪r‬به آخرین اندیس تمامي‬
‫عناصررابه ابتداي آرایه منتقل كرد یا اینكه با هر بارعمل حذف عناصر صف یك واحد به سمت چپ‬
‫انتقال داده شود هــردو پیشنهاد مستلزم تعداد بسیار زیادي عمل‪Shift‬است راه حل بهتر استفاده‬
‫از صف هاي دایره اي است ‪.‬‬
‫صف هاي دایره اي (چرخشي)‪:‬‬
‫دریك صف چرخشي با آرایه به گونه اي رفتار مي شود كه به نظر مي رسد سلول اندیس]‪Max [i‬‬
‫قبل از سلول اندیس صفر قرار گرفته است در این صورت تمامي اصولي كه در صفهاي خطي گفتیم‬
‫میبایست اصالح شود در صف های دایره ای ‪f>r‬نمي تواند نشان دهنده ي خالي بودن صف‬
‫شرط‬
‫باشد همچنین شرط ‪ R==max-1‬نشان دهنده پر بودن صف نیست تعداد عناصر داخل صف نیز‬
‫نمي تواند از رابطه ‪R-f+1‬به دست آید ‪.‬‬
‫شرایط خالي بودن صف را به صورت‪ F==R‬در نظر مي گیریم یعني زماني كه صف خالي است‪F,R‬‬
‫به خانه ي واحدي مراجعه مي كند در اثر این عمل مشكلي پیش مي آید و آن این است كه اگـــر آرایه‬
‫كامال پر شود ‪R‬با ‪ F‬برابر خواهدبود براي پیشگیري ازچنین مشكلي فرض مي كنیم كه خانه متعلق‬
‫به‪ F‬همواره باید خالي باشد ‪.‬‬
:Insert‫پیاده سازي تابع‬
Void Insert (Queue *q , Char x )
{
If ((qr+1) % Max ==q f)
Print f ("Queue is full ");
Else{
q r =(qr+1)% Max ;
q Items [q r] =x;
}
: Empty ‫پیاده سازي تابع‬
Int empty (Queue *q)
{
if (q f == q r)
Return (1);
Else
Return (0); }
: Remove‫پیاده سازي تابع‬
Char Remove (Queue *q)
{
Char x;
If (empty (q))
Print f )"Queue is empty”(;
Else
{
q f=(qf+1)%Max;
x=q Items [qf];
Return (x);
}
}
‫صف اولویت‪:‬‬
‫در صف اولویت تربیت ورود و خروج به صورت ‪Fifo‬نیست ‪ .‬در این صفها تربیت خروج بر اساس‬
‫اولویت عناصر است از دیدگاهي ساده تر مي توان صفها ي اولویت را به دو شکل صف اولویت‬
‫صعودي وصف اولویت نزولي دسته بندي كرد‪ .‬در صف اولویت صعودي عناصر مي توانند به‬
‫هرترتیبي واردشونداما عمل حذف یك عنصر همواره روي عناصر كوچك تر انجام مي پذیرد ‪.‬‬
‫درج و حذف در صف اولویت صعودي‪:‬‬
‫‪ -1‬درج ‪ :‬عنصر جدید در انتهاي صف درج مي شود ‪( .‬یک عمل)‬
‫حذف ‪ :‬با جستجو در صف كوچكترین عنصر پیدا شده و حذف مي شود ‪ n ( .‬مقایسه)‬
‫‪ -2‬درج ‪ :‬عنصر جدید در محل منطقي اش (به كمك جست و جو ) درج شود ‪ n/2(.‬مقایسه)‬
‫حذف ‪ :‬از ابتداي صف (یک عمل)‬
‫نکته ‪ :‬از نظر تعداد مقایسات روش دوم از روش اول بهتــر است ‪.‬‬
‫مثال‪:‬‬
‫‪186924‬‬
‫روش اول ‪1 8 6 9 2 4 :‬‬
‫روش دوم ‪9 8 6 4 2 1 :‬‬
‫نکته ا ی راجع به پیاده سازی پشته ها در آرایه ها‪:‬‬
‫می توان با استفاده از یک آرایه دو پشته را پیاده سازی کرد در این صورت پشته اول از چپ به‬
‫راست و پشته دوم از راست به چپ در آرایه قرار می گیرد ‪.‬‬
‫;]‪x=Items [top2‬‬
‫حذف از پشته دوم‬
‫;‪top2++‬‬
‫;‪top2--‬‬
‫درج در پشته دوم‬
‫;‪Items[top]=x‬‬
‫‪ : top1 == -1‬شرط خالی بودن پشته اول‬
‫‪ : top2 == max‬شرط خالی بودن پشته دوم‬
‫‪ :Top1 + 1 == top2‬شرط پر بودن هردو پشته‬
‫]‪x=Items[top1‬‬
‫حذف از پشته اول‬
‫;‪top1--‬‬
‫;‪top1++‬‬
‫درج در پشته اول‬
‫; ‪Items[top]=x‬‬
‫در یک آرایه می توان چندین پشته را پیاده سازی کرددراین صورت می بایست آرایه را تقسیم بر‬
‫تعداد پشته ها کنیم فرضا اگر آرایه ‪ 20‬سلول دارد و تعداد پشته ها ‪ n=4‬است هر پشته ‪ 5‬خانه از‬
‫آرایه را اشغال خواهد کرد ‪.‬‬
‫‪  max‬تعداد سلول های آرایه‬
‫]‪b [i] = i * [max/n‬‬
‫‪n‬تعداد پشته ها‬
‫‪top [i] = i * [max/n]-1‬‬
‫هر پشته ‪ max/n‬سلول اشغال می کند‪.‬‬
‫در یک آرایه می توان چندین پشته را پیاده سازی کرددراین صورت می بایست آرایه را تقسیم بر‬
‫تعداد پشته ها کنیم فرضا اگر آرایه ‪ 20‬سلول دارد و تعداد پشته ها ‪ n=4‬است هر پشته ‪ 5‬خانه از‬
‫آرایه را اشغال خواهد کرد ‪.‬‬
‫]‪b [i] = i * [max/n‬‬
‫‪top [i] = i * [max/n]-1‬‬
‫هر پشته ‪ max/n‬سلول اشغال می کند‪.‬‬
‫‪ max‬تعداد سلول های آرایه‬
‫‪ n‬تعداد پشته ها‬
‫لیست هاي پیوندي‪:‬‬
‫مشكل بزرگ آرایه ها آن است كه جهت پیاده سازي ساختارهایي مثل صف و پشته نمي دانیم كه دقیقا‬
‫چند سلول از حافظه مورد نیاز است پس مجبوریم حداكثــر برآورد رادرانتخاب تعداد عناصر‬
‫آرایه‬
‫اعمال كنیم این كار باعث مي شود كه در بسیاري از موارد حافظه هــدر رود و بالاستفاده باقي بماند‬
‫یكي از راه كارهاي از بین بردن این مساله استفاده از لیست هاي پیوندي است ‪.‬‬
‫فرض كنید عناصر پشته و یا صف ‪،‬در داخل خودشان آدرس عنصر بعدي را داشته باشند چنین ترتیبي‬
‫یك ساختمان داده اي به نام لیست پیوندي خطي راایجاد مي كند هریك ازعناصرتشكیل دهنده‬
‫لیست‬
‫پیوندي ‪ Node‬و یا گره نام دارد ‪.‬‬
‫شكل ساده اي از یك گــره ‪:‬‬
‫بخش ‪ : info‬اطالعات مورد نظر ما را نگه داري مي كند‬
‫بخش ‪ : Next‬یك اشاره گر است كه به گره ي بعدي در لیست پیوندي اشاره مي كند ‪.‬‬
‫یك لیست پیوندي خطي معموال به شكل زیر است‪:‬‬
‫براي دسترسي به لیست پیوندي از یك اشاره گر خارجي به اولین گره در لیست پیوندي اشاره مي كند‬
‫استفاده مي كنیم‪.‬‬
‫نكته‪ :‬اشاره گر در آخرین گره مقدار ‪Null‬یا تهي دارد این بدان معنا است كه پس از این گره ‪،‬گره‬
‫دیگري در لیست پیوندي وجود ندارد‪.‬‬
‫نكته‪ :‬براي پیاده سازي گره مي توان از یك ساختمان كمك گرفت به عنوان مثال ساختمان زیر گره اي‬
‫را تشریح مي كند كه بخش ‪ info‬در آن از نوع ‪Char‬است‪.‬‬
‫‪Struck node‬‬
‫{‬
‫;‪Char info‬‬
‫;‪Node * next‬‬
‫;}‬
‫اگر‪ p‬اشاره گر به گره باشد ‪(pinfo‬قسمت اطالعاتي ‪ )Info‬در گره را مشخص مي كند و منظور‬
‫از ‪ P next‬اشاره گري است كه در آن گره خارج مي شود‪.‬‬
‫فرض كنیم خواسته باشیم گــره را به لیست پیوندي اضافه كنیم برا ي این كار ابتدا مي بایست گره‬
‫جدیدي را ایجاد كنیم فرض كنید تابعي به نام ‪ Get node‬وجود دارد كه وظیفه ي ایجاد گره ي جدید‬
‫و تولید آدرس آن را به عهده دارد پس از ایجاد گره جدید بخش ‪ Info , Next‬آن را مقداردهي‬
‫هاي‬
‫مي كنیم‪.‬‬
‫;) ( ‪P=get node‬‬
‫;‪P info=x‬‬
‫;‪P next=list‬‬
‫;‪List=p‬‬
‫پیاده سازي تابع ‪: Get node‬‬
‫در زبان ‪ C‬تابعي وجود دارد به نام ‪ malloc‬كاربرد این تابع بدین صورت است كه به اندازه عدد‬
‫ذكر شده درپرانتزجلوي آن حافظه رابه شمااختصاص مي دهد براي اینكه بتوانیم بتوانیم به اندازه ی‬
‫یك گره فضا بگیریم از این تابع به شكل زیر استفاده مي كنیم‪.‬‬
‫))‪Malloc (size of (node‬‬
‫فضاي اختصاص داده شده مي بایست در قالب یك گره پیكربندي شود بدین منظور مي بایست بنویسیم‪:‬‬
‫))‪Node *malloc (size of (node‬‬
‫*ذكــر شده جلوی ‪node‬بدین خاطر است كه آدرس حافظه ي اختصاص داده شده تولید شده و نهایتا‬
‫به وسیله ي تابع ‪ Get node‬برگشت داده شود شکل تابع ‪ get node‬براساس آنچه گفته‬
‫شدبه صورت زیر است‪:‬‬
‫( )‪Node *get node‬‬
‫{‬
‫))‪Return ((node *) malloc (size of (node‬‬
‫}‬
‫حذف یك گره از ابتداي لیست پیوندي ‪:‬‬
‫‪list‬‬
‫;‪P=list‬‬
‫;‪List= list next‬‬
‫;‪X= p Info‬‬
‫;)‪Free (p‬‬
‫پیاده سازي پشته ها با استفاده از لیست هاي پیوندي خطي‪:‬‬
‫عمل افزودن یك عنصر به ابتداي لیست پیوندي مانند اضافه كردن عنصري در باالي پشته است و‬
‫عمل حذف اولین عمل عنصر از لیست پیوندي مانند حذف عنصر باالي پشته مي باشد بنابراین‬
‫توابع ‪ push , pop‬را مي توان به شكل زیر پیاده سازي كرد‪.‬‬
‫ابتدا تابع ‪ empty‬را طراحي مي كنیم ‪.‬‬
:Empty ‫پیاده سازي تابع‬
Int empty (node *p)
{
If (p==Null)
Return (1);
Else
Return (0);
}
:Push ‫پیاده سازي تابع‬
Void push (node *list, char x)
{
Node *p;
P=Get node ();
Pinfo=x;
P next=list;
list=p;
}
:Pop ‫پیاده سازي تابع‬
Char pop (node *stack)
{
Node *p;
Char x;
If (empty (stack))
Print f ("stack is empty");
Else
{
P=stack;
stack = stack  next;
x=pinfo;
Free (p);
Return (x);
}
}
‫پیاده سازي صف ها به كمك لیست ها ي پیوندي خطي ‪:‬‬
‫اگر لیست پیوندي خطي به گونه اي مدیریت شود كه اولین عنصر ورودي ‪ ،‬اولین عنصر خروجي‬
‫باشد مي توان گفت یك صف پیاده سازي شده است در نتیجه مجبوریم از یك طرف لیست پیوندي عمل‬
‫حذف و در طرف دیگر آن عمل درج را انجام دهیم‪.‬‬
:Insert ‫پیاده سازي تابع‬
Void Insert (node *p , char x)
{
P=Get node ();
Pinfo=x;
P next=Null;
If (r==Null)
{
f=P;
r=P;
}
Else
{
r next=P;
r =P;
}
}
:Remove ‫پیاده سازي تابع‬
Char Remove (node *p )
{
Char x;
If (f==Null)
Print f ("Queue is empty");
Else {
P=f;
f=f next;
X=pinfo;
Free (p);
If (f==null)
f=null;
Return (x);
}
}
‫معایب پیاده سازي صف و پشته با استفاده از لیست هاي پیوندي‪:‬‬
‫‪-1‬هر گره در لیست پیوندي از هر سلول آرایه فضاي بیشتري تلف مي كند‪.‬‬
‫‪-2‬مدیریت لیست هاي پیوندي نسبت به آرایه مشكل تر است‪.‬‬
‫به طور كلي لیست ها پیوندي و آرایه ها را مي توان مورد ارزیابي قرار داد‪.‬‬
‫مزایاي لیست پیوندي نسبت به آرایه ها ‪:‬‬
‫عالوه بر آنچه كه گفته شد در لیست هاي پیوندي درج و حذف از میا نه ي لیست پیوندي به سادگي‬
‫امكان پذیر است اما در آرایه ها هر عمل درج و هر عمل حذف نیاز به ‪ Shift‬دادن عناصر آرایه‬
‫دارد‬
‫مزایاي آرایه نسبت به لیست پیوندي ‪:‬‬
‫عالوه بر آنچه که گفته شد دسترسي به هر یك از عناصر آرایه به شكل مستقیم انجام مي شود اما در‬
‫لیست های پیوندي براي رسیدن به گره ‪n‬ام مي بایست ‪n-1‬گره پشت سر آن پیمایش شده باشد ‪.‬‬
‫ به گره اي اشاره كــرده با شدگره بعداز آن را حذف‬p‫شبه كدي بنویسید كه در یك لیست پیوندي اگر‬
: ‫كند‬
Delafter (p)
{
If ( p next ==Null)
Print f ("can not remove ")
p
Else
{
B
C
D
E
A
q= p next;
P next= q next;
q
Free (q);
}
}
‫فرض كنید خواسته با شیم بعد از گره اي كه ‪ P‬به آن اشاره مي كند گره جدیدي را درج كنیم‪.‬‬
‫)‪Insafter (p, x‬‬
‫{‬
‫;)( ‪q=Get node‬‬
‫;‪q Info = x‬‬
‫;‪next‬‬
‫;‪q Next = p next‬‬
‫;‪P Next = q‬‬
‫‪q‬‬
‫}‬
‫نكته ‪ :‬در بسیاري از كاربردها مي بایست لیست پیوندي پیمایش شود معموال براي پیمایش لیست هاي‬
‫پیوندي از یك یا دو اشاره گر كمكي استفاده مي كنیم كه به دنبال یكدیگر درون لیست حركت مي كنند ‪.‬‬
‫مثال‪:‬در یك لیست پیوندي حاوي عدد صحیح كلیه ي گره هایي را كه حاوي عدد ‪ 4‬هستند را حذف‬
‫كنید‬
While (list  info == 4 && list! = Null){
Pop (list);
p = list;
q = list Next;
While (q! = Null)
{
If (q info == 4)
{
Delafter (p);
q = p Next;
}
Else {
p = p Next;
q = q Next;
}
}
‫لیست مرتب‪:‬‬
‫لیستي كه درآن عناصر کوچکترقبل ازعناصر بزرگتر قرار گرفته باشند ‪ .‬بنابراین اگر بخواهیم عنصر‬
‫جدیدي به آن اضافه كنیم مي بایست به گونه ای باشد كه ترتیبش هم نخورد‪.‬‬
‫می خواهیم شبه كدي براي درج یك عنصر جدید در داخل لیست مرتب بنویسیم ‪.‬‬
‫‪ -1‬عنصر جدید از تمامي عناصر لیست كوچكتر است ‪.‬‬
‫‪ -2‬مقدار جدید به گونه اي است كه در میان لیست قرار مي گیرد‪.‬‬
‫‪ -3‬عنصر جدید از تمام عناصر لیست بزرگتر است‪.‬‬
1)
If (x< list info)
Push (list, x);
Else
{
p=list;
q=list  Next;
While (qinfo < x)
{
p=p Next;
q=q Next;
}
Insafter (p, x)
}
2)
If (x< list info)
Push (list, x);
Else
{
p=list;
q=list  Next;
While (qinfo < x && q! =Null)
}
p=p Next;
q=q Next;
}
Insafter (p, x) }
}
‫الگوریتم فوق از آنجا كه عنصر جدید را در محل واقعیش قرار مي گیرد جهت پیاده سازي صفهاي‬
‫اولویت به کار رود این الگوریتم را‪ Place‬نام گذاري مي كنیم‪.‬‬
‫اگر لیست پیوندي ما تهي باشد چه كار باید بكنیم؟‬
‫)‪If (x< list info || list == Null‬‬
‫نکته ‪ :‬براي پیاده سازي صف اولویت مي توان از پیاده سازي لیست پیوندي استفاده كنیم فرضا اگر‬
‫صف اولویت صعودي باشد مي توان از صف اولویت صعودي خود استفاده كنیم ‪.‬‬
‫نکته ‪ :‬صف اولویت نزولي مشابه با مواردي كه در پیاده سازي صف صعودي گفته شد قابل پیاده‬
‫سازي است‪.‬‬
‫نکته‪ :‬در بعضي از كتابها به ‪ Info‬از كلمه ي ‪ Data‬و به جاي ‪ Next‬از كلمه ‪ Link‬استفاده‬
‫جای‬
‫مي شود ‪.‬‬
‫در كدهاي زبان پاسكال به جاي دستوراتي مثل ‪ p info‬از ‪ p info‬و ‪ p next‬از‬
‫‪ p  info‬استفاده مي شود‪.‬‬
‫عمل درج در ابتداي لیست با عمل درج در میانه یا انتهاي لیست پیوندي تفاوت ساختاري داشت ‪،‬براي‬
‫درج در ابتدا از ‪ Push, Insert‬استفاده می شود وبرای درج در انتها یا میانه از ‪Insafter‬‬
‫استفاده مي شود ‪.‬‬
‫در برخي مواقع براي اینكه درج یكسان درآید ( همواره به صورت ‪ )insafter‬یك گره اضافه به نام‬
‫گره راس درابتداي لیست درنظرمي گیریم حتي زماني كه لیست پیوندي تهي است وگره راس‬
‫موجود است‪.‬‬
‫بخش ‪ Info‬درگره راس دربرخي موارد بالاستفاده قرار مي گیرد و در برخي دیگر از موارد اطالعاتي‬
‫از لیست پیوندي در گره قرار مي گیرد مثال مي توان تعداد گره هاي موجود را در آن ثبت كنیم‪.‬‬
‫و در برخي دیگر گره راس مي تواند دو اشاره گر یكي به ابتدا و دیگري به انتها ي لیست پیوندي‬
‫داشته باشد‪.‬‬
‫از لیست هاي پیوندي مي توان براي پیاده سازي چند جمله ایها استفاده كرد در این صورت هر گره‬
‫شامل سه بخش خواهد بود‪.‬‬
‫فرض كنید دو چند جمله اي دارید و مي خواهید آنها را با هم جمع كنید‪.‬‬
‫‪7x^5 + 3x^3 – 6x^2+ 4‬‬
‫‪5x^6-4x^5+2x^4+2x^2-x‬‬
‫هنگام جمع دو چند جمله اي حالتهاي زیر مي تواند وجود داشته باشد ‪:‬‬
‫‪)1‬دو جمله اي كه با آن مواجه هستیم هم توان باشند ‪:‬ضرایب با هم جمع شوند وهردوجمله راپشت‬
‫سرمی گذاریم‪.‬‬
‫‪)2‬یكي از جمالت توان بیشتري دارد آن جمله انتخاب شده و پشت سر گذاشته مي شود ‪.‬‬
p=list1;
q=list2;
List3=Get node ();
If ( p t = = q t)
{
List3 t= p t
List3 z=p z + q z;
p=p  Next;
q=q  Next;
}
Else if (p t > q t)
{
List3 t=p t;
List3 z=p z;
p=p Next;
}
Else
{
List3 t=q t;
List3 z=q z;
q=q next;
r=list3;
While (p! =Null && q! =Null)
{
If (p t==q t)
{
Insafter (r, p z + q z, p t);
p= p Next;
q= q next;
r = r Next;}
Else if (p t >q t)
{
Insafter (r, p z, p t);
r=r Next;
}
Else
{
Insafter (r, q z, q t);
r=r Next;
}
}//while
If (p! =Null)
{
While (p! =Null)
{
Insafter (r, p t, p z);
r= r Next;
p=p  Next;
}
}
If (q! =Null)
{
While (q! =Null);
{
Insafter (r, q t, q z);
r= r Next;
q= q Next;
}//while
}
‫لیست هاي پیوندي دایره ا ي‪:‬‬
‫اگر اشاره گر خارج شده از آخرین گره به جاي ‪ Null‬به گره ابتدایي اشاره كند ساختار جدیدي به نام‬
‫لیست پیوندي دایره اي پدید مي آید‪.‬‬
‫در لیست هاي پیوندي دایره اي به خاطر بسته بودن لیست مي توان از هر نقطه لیست به نقاط دیگر‬
‫دسترسي پیدا كرد‪.‬‬
‫براي آنكه مدیریت لیست ساده تر انجام شود اشاره گر خارجي به لیست را روي آخرین گره فرض مي‬
‫گیریم در نتیجه گره ي بعد از آن گره ي اول خواهد بود‪.‬‬
‫به وسیله ي لیست هاي دایره اي میتوان پشته ها وصف ها را پیاده سازي كرد‪.‬‬
‫پشته ها درلیست هاي پیوندي دایره اي ‪:‬‬
‫‪C‬‬
‫‪B‬‬
‫‪A‬‬
: Push ‫شبه كدي براي تابع‬
Void push (stack, x)
{
p=Get node ( );
p info=x;
If (stack! =Null)
{
p Next =stack next;
Stack next=p;
}
Else
{
p Next=p;
Stack=p;
}
}
: Pop ‫شبه كدي براي تابع‬
Char pop (stack)
{
If (stack == Null)
Print f ("stack is empty);
Else
{
P= stack Next;
Stack Next=p Next;
X=p info;
If (p==stack)
Stack=Null;
Free (p);
Return (x);
}
}
‫پیاده سازي صف ها با استفاده از لیست هاي پیوندی دایره ای‬
: Insert ‫پیاده سازي تابع‬
Void Insert (queue, x)
{
p=Get node ( );
p  info = x;
If (queue! =Null)
{
p Next = queue Next;
queue Next=p;
}
Else {
p Next=p;
queue =p;
}
queue = queue Next;
}
f
r
q
A
B
C
null
q
q
q
: Remove ‫پیاده سازي تابع‬
Char remove (queue)
{
If (queue == Null)
Print f ("queue is empty");
Else {
p=queue Next;
queuenext=p Next;
X=p Info;
If (p==queue)
queue == Null;
Free (p);
Return (x);
}
}
‫لیست هاي دو پیوندي‪:‬‬
‫یكي از مشكالت بزرگ لیست هاي یک پیوندي (خواه خطي باشد خواه دایره اي ) آن است كه امكان‬
‫پیمایش معكوس در آن ها وجود ندارد این مشكل به وسیله ي لیست هاي دو پیوندي قابل حل است‪.‬‬
‫نكته ‪ :‬لیست هاي دو پیوندي را گاهي لیست هاي پیوندي دو طرفه نیز مي گویند‪.‬‬
‫شكل هر گره در لیست هاي دو پیوندي به شكل زیر است‪.‬‬
‫نكته ‪ :‬اشاره گر هاي ‪ Left, Right‬را در بعضي كتاب ها به ترتیب ‪ Prev , Next‬تعریف‬
‫كرده اند‪.‬‬
‫همان طور كه گفته شد در لیست ها ي دو پیوندي مي توان از هر نقطه به گره بعدي ویا قبلي‬
‫دسترسي پیدا كرد‪.‬از جمله كارهایي كه به سادگي مي توان روي لیست هاي در پیوندي انجام داد حذف‬
‫مستقیم گره اي است كه ‪ p‬بدان اشاره مي كند‪.‬‬
‫به عنوان مثال در یك لیست دو پیوندي زیر مجموعه دستورات باعث حذف گره ‪ p‬مي شود‪.‬‬
‫‪r‬‬
L=p left;
R=p right;
L right =r;
R left=l;
X=p info;
Free (p);
‫فرض كنید خواسته باشید در یك لیست دو پیوندي سمت راستي كه گره بدبن اشاره مي كند گره جدیدي‬
.‫را درج كنیم‬
Q=Get node ();
Q Info=x;
r= p right;
Q Right=r;
Q Left=p;
P right=q;
R left=q;
‫درختها‪:‬‬
‫درخت دودویی ‪:‬‬
‫یک درخت دودویی ساده ترین شکل درخت می باشد که از سه مجموعه تشکیل شده است‬
‫مجموعه اول یک عنصر به نام ریشه دارد و دو مجموعه دیگر به نام زیر درخت چپ و زیر درخت‬
‫راست‬
‫موسوم است ‪ .‬هر یک از زیر درخت ها می تواند تهی باشد‪.‬‬
‫در شکل فوق ‪ A‬ریشه درخت‪ B ،‬ریشه زیر درخت چپ و ‪ c‬ریشه زیر درخت راست می باشد ‪.‬‬
‫همانطور که در شکل می بینید زیر درخت چپ و راست ‪B‬شامل ‪ E , D‬هستند‪.‬‬
‫هر عنصر درخت دودویی گره نامیده می شود ‪ .‬در مثال قبل ‪ 9‬گره وجود دارد ‪ .‬گره ای که زیر درخت‬
‫چپ و راست خالی داشته باشد برگ نامیده می شود ‪.‬‬
‫ریشه و ‪ B‬ریشه زیر درخت چپ یا راست آن باشد آنگاه ‪ A‬را پدر ‪ B‬و ‪B‬را پسرچپ یا راست‬
‫اگر ‪A‬‬
‫َََ‪ A‬می نامیم‪.‬‬
‫اگر‪ A‬پدر ‪ B‬یا پدرچند گره باالتراز ‪ B‬باشد ‪ A‬راجد ‪ B‬و ‪ B‬رانوه ی ‪ A‬می نامیم‪.‬اگر ‪B‬پسر چپ‬
‫َََ‪ A‬یا نوه ی پسر چپ ‪A‬باشد آنگاه ‪ B‬نوه ی چپ ‪ A‬محسوب می شود ‪.‬‬
‫تعریف مشابهی برای نوه ی راست نیز می توان ارائه داد‪.‬‬
‫اگر دو گره فرزندان چپ و راست یک پدر باشند با هم برادرند‪.‬‬
‫نکته‪ :‬در برخی کتابها به جای پدر ازکلمه والد یا )‪ (parent‬استفاده می شود به جای پسر از واژه‬
‫فرزند وبه جای برادر از واژه همزاد استفاده می شود‪.‬‬
‫درخت دودویی محض ‪:‬‬
‫درختی که هر گره آن یا فرزند ندارد یا دو فرزند دارد‪.‬‬
‫یک درخت دودویی محض اگر‪ n‬برگ داشته باشد‪ 2n-1‬گره دارد‬
‫یک درخت دودویی کامل می تواند به شکل زیر شماره گذاری شود‪:‬‬
‫در برخی کتابها سطح را از صفر شروع می کنند‪.‬‬
‫مثال درخت باال سه عمق دارد‪.‬‬
‫درخت دودویی پر ‪:‬‬
‫درختی که محض باشد و تمام برگ های آن در یک سطح قرار داشته باشد‪.‬‬
‫شکل های ‪ 1،2،3‬هم محض هستند هم پر ولی شکل ‪ 4‬فقط محض است ‪.‬‬
‫درخت دودویی پر باید ساختار مثلثی داشته باشد ‪.‬‬
‫اگر درخت دودویی پر عمقی برابر با ‪ D‬باشد تعداد گره های آن برابر است با ‪:‬‬
‫تعداد گره ها ‪ tn‬عمق ‪D‬‬
‫‪1‬‬
‫‪1‬‬
‫)‪( tn1‬‬
‫‪2‬‬
‫‪3‬‬
‫‪tn = 2 ^ d – 1‬‬
‫‪D = 2 ^ d = tn + 1  d = log‬‬
‫‪2‬‬
‫‪3‬‬
‫‪7‬‬
‫درخت دودویی کامل ‪:‬‬
‫اگر درخت دودویی کامل ‪ D‬شرایط زیر داشته باشد کامل است ‪.‬‬
‫‪-1‬کلیه برگهای آن حداکثر در‪ 2‬سطح ‪ D‬و ‪ D-1‬واقع شده باشد‪.‬‬
‫‪-2‬درخت از چپ به راست پر شود ‪.‬‬
‫‪-3‬اگر آخرین سطر برگهای درخت حذف شود یک درخت پر پدیدار می شود ‪.‬‬
‫یک درخت دودویی کامل می تواند به شکل روبرو شماره گذاری شود‪:‬‬
‫ریشه شماره ‪1‬‬
‫‪1‬‬
‫‪3‬‬
‫هرفرزند چپ ‪2‬برابر پدرش‬
‫‪2‬‬
‫‪7‬‬
‫‪4‬‬
‫‪5 6‬‬
‫هر فرزند راست ‪2‬برابر پدرش ‪1+‬‬
‫یک درخت دودویی کامل را می توان به کمک آرایه پیاده سازی کرد ‪.‬‬
‫در این صورت فرزندان چپ وراست هریک ازعناصر آرایه درموقعیتهای دوبرابر و دو برابر ‪ ++‬قرار‬
‫دارد ‪ ،‬همچنین برای پیدا کردن پدر هر گره کافیست اندیس مربوط به آن را تقسیم بر ‪ 2‬کرده و جزء‬
‫صحیح آنرا انتخاب نمود ‪.‬‬
‫اعمال ابتدایی روی درخت دودویی ‪:‬‬
‫چند عمل ابتدایی را روی درخت دودویی می توان انجام داد قبل از شرح این اعمال می بایست ساختار‬
‫گره را بررسی کرد یک گره در ساده ترین حالت می تواند مشابه گره ای در لیست دو پیوندی باشد ‪.‬‬
‫اگر از چنین روشی استفاده کنیم پیمایش به سمت باال امکان پذیر نیست‪ .‬برای حل این مشکل درپاره‬
‫ای از موارد اشاره گری به سمت باال در گره ایجاد می شود‪.‬در نتیجه می توان گره را با ساختمان‬
‫‪Struct node‬‬
‫زیر پیاده سازی کرد ‪:‬‬
‫{‬
‫;‪Char info‬‬
‫};‪Node *left,*right,*father‬‬
‫توجه ‪ :‬واضع است که فقط در گره ‪father‬برابر‪ null‬است همچنین واضح است که در تمامی‬
‫برگ ها اشاره گرهای‪ right,left‬برابر ‪ null‬هستند‪ .‬ریشه‬
‫نکته‪ :‬در موارد بسیار نادری یک گره اشاره گر برادر خواهد داشت ‪.‬‬
‫می توان تابعی به نام )‪Isright (p‬طراحی کرد )‪ Isright (p‬در صورتی ‪ True‬برگشت خواهد داد‬
‫که خود گره ‪ p‬فرزند گره سمت راستی پدرش باشد وگرنه ‪ False‬برگشت می دهد ‪.‬‬
‫تابع )‪: Isleft (p‬مشابه )‪ Isright (p‬است منتهی برای فرزند چپ ‪.‬‬
‫)‪Make tree(x‬اولین گره یعنی ریشه درخت را می سازد این تابع یک گره حاوی ‪ x‬راایجادمی کند‬
‫هر سه اشاره گر خارج شده از این گره ‪ Null‬است پس آدرس گره ساخته شده را بر گشت می دهد‪.‬‬
‫;)‪Tree=maketree(a‬‬
‫‪Setleft‬با پارامتر های (‪: )p,x‬در صورتی که سمت چپ گره ‪p‬گره ای موجود نباشد گره جدیدی‬
‫حاوی‪ x‬سمت چپ ‪ p‬ایجاد می کند‪.‬‬
‫‪setright‬مشابه ‪ setleft‬برای فرزند سمت راست می باشد ‪.‬‬
‫نمونه ای از کاربرد درخت دودویی‪:‬‬
‫درخت دودویی ساختمان داده ای است که در فرایند تصمیم گیریهای دو طرفه بسیار پر کاربرد است ‪.‬‬
‫هنگام کار با درخت ها همواره مایلیم درخت هایی بسازیم که تمامی شاخه های آن به شکل نرمال رشد‬
‫کرده باشد منظور ما از یکی درخت نرمال درختی است که تفاوت سطح برگ های آن به طور کلی زیاد‬
‫نباشد واضح است که در بهترین حالت دنبال یک درخت پر یا کامل باشیم ‪.‬‬
‫نکته ‪ :‬اگر این حالت ایده آل را در نظر بگیریم طبق آنچه گفته شد عمق درخت پر از رابطه زیر بدست‬
‫می آید‪.‬‬
‫=‪tn‬‬
‫‪=tn+1‬‬
‫‪‬‬
‫‪tn1‬‬
‫‪1‬‬
‫‪d‬‬
‫‪log‬‬
‫‪d=2‬‬
‫‪2n‬‬
‫‪2‬‬
‫‪n‬‬
‫‪log‬‬
‫یک درخت نرمال‬
‫≈ ‪( d‬عمق درخت) ‪ :‬در ‪2‬‬
‫‪number of nods‬‬
‫‪2‬‬
‫‪log‬‬
‫حال فرض کنید که خواسته باشید در میان لیستی از عناصر ‪ ،‬عناصر تکراری را یافته یا حذف کنید‪.‬‬
‫)‪n‬تعداد عناصر) ‪ ≈ nn  1‬تعداد مقایسات ‪ :‬برای درج ‪n‬گره در چنین درختی‬
‫یک روش برای اینکار این است که عنصر‪2‬اول را با‪ n-1‬عنصر باقیمانده مقایسه کنیم ودر این مسیر‬
‫عناصر تکراری را چاپ کنیم (تعداد مقایسات ‪ )n-1‬باشد سپس عنصردوم را با ‪ n-2‬عنصر باقیمانده‬
‫مقایسه کنیم که در این صورت ‪ n-2‬مقایسه دیگر انجام می شود این کار تا انتهای لیست باید تکرار‬
‫شود در این صورت تعداد کل مقایسات از رابطه زیر بدست می آید ‪:‬‬
‫=‪= (n - 1) + (n - 2)+(n-3(+…+1‬تعداد کل مقایسات‬
‫روش بهتراستفاده ازیک درخت دودویی است دراین روش عنصر اول لیست ریشه درخت را می سازد‬
‫عناصر باقیمانده به گونه ای وارد درخت می شوند که ریشه هر زیر درخت از نوه های چپ بیشتر‬
‫باشد و از نوه های راست کمتر ‪.‬‬
‫‪6 3 9 1 4 7 8 7 2 1 5 10‬‬
‫تعداد مقایسات برابر است با عمق گره )‪Log (n‬‬
‫تعداد مقایسات در مثال فوق برای یک گره برابر است با ‪:‬‬
‫)تعداد گره ها( ‪ ≈ log2‬تعداد مقایسات برای یک گره جدید‬
‫‪n‬‬
‫)‪n‬تعداد عناصر( ‪ ≈ n log2‬تعداد مقایسات برای درج ‪N‬گره در چنین درختی‬
‫‪N=100‬‬
‫‪: (1000*999)/2 ≈ 500000‬روش اول‬
‫‪ :1000 * log2 1000 =10000‬روش دوم‬
‫‪6‬‬
‫‪3‬‬
‫‪9‬‬
‫‪7‬‬
‫‪10‬‬
‫‪8‬‬
‫‪4‬‬
‫‪5‬‬
‫‪1‬‬
‫‪2‬‬
‫‪‬‬
: ‫شبه کد عناصر تکراری‬
‫اولین عنصر باشد‬x ‫اگر‬
Tree=maketree(x);
While(‫{)عددی در لیست وجود دارد‬
X=‫;عدد بعدی لیست‬
p=tree;
q=tree;
While(q!=null && p  info !=x){
p=q;
If (x>pinfo)
q=qright;
Else
q=qleft;
}//while
If(x==pinfo)
printf(“%c”,x);
Else{
if(x>pinfo)
setright(p,x);
else
setleft(p,x);}
}
‫پیمایش درخت ‪:‬‬
‫پیمایش درخت حرکت در سر تا سر درخت و مالقات تمام گره هاست ‪.‬‬
‫سه روش پیمایش در درختها وجود دارد ‪:‬‬
‫‪(VLR) Preorder‬‬
‫‪-1‬پیش ترتیب‬
‫‪(LVR) Inorder‬‬
‫‪-2‬میان ترتیب‬
‫‪(LRV) Postorder‬‬
‫‪-3‬پس ترتیب‬
‫براي پیمایش ‪Preorder‬سه عمل زیر باید انجام شود‪:‬‬
‫‪)1‬مالقات ریشه‬
‫‪ )2‬پیمایش زیر درخت چپ به روش ‪preorder‬‬
‫‪ )3‬پیمایش زیر درخت راست به روش ‪preorder‬‬
‫‪Preorder : ABDFGHEICJKL‬‬
‫براي پیمایش ‪ Inorder‬سه عمل زیر باید انجام شود‪:‬‬
‫‪ )1‬پیمایش زیر درخت چپ به روش ‪inorder‬‬
‫‪ )2‬مالقات ریشه‬
‫‪ )3‬پیمایش زیر درخت راست به روش ‪inorder‬‬
‫‪inorder : DGFHBIEAJCLK‬‬
‫برای پیمایش ‪ postorder‬سه عمل زیر باید انجام شود‪:‬‬
‫‪)1‬پیمایش زیر درخت چپ به روش ‪postorder‬‬
‫‪)2‬پیمایش زیر درخت راست به روش ‪postorder‬‬
‫‪)3‬مالقات ریشه‬
‫‪Postorder : GHFDIEBJLKCA‬‬
‫نكته‪ :‬یكي از روش هاي مرتب سازي استفاده از درختان دودویي است اگر درخت مربوط به پیدا کردن‬
‫اعداد تكراري را به گونه اي ایجاد كنیم كه عناصر تكراري نیز داخل درخت درج شو د با پیمایش‬
‫‪Inorder‬آنها ‪،‬اعداد به ترتیب صعودي ‪sort‬مي شود‪.‬‬
‫به چنین درختي ‪ ،‬درخت جست و جوي دودویي )‪ (binary search tree‬محض گفته مي شود‪.‬‬
‫نكته‪ :‬مي توان یك عبارت حاوي عملوندها وعملگرها رابه وسیله ي یك درخت دودویي محض‬
‫پیمایش‬
‫كرد‪.‬‬
‫بدین منظور ابتداعبارت را پرانتز گذاري کرده و سپس از داخلي ترین پرانتزهازیردرخت را می سازیم‬
‫ودرخت را از پایین به باال تكمیل می کنیم‪.‬‬
‫))‪(((A*B)-((C/D)*E)) + (F*G‬‬
‫اگر درخت به درستي ایجاد شده باشد سه پیمایش ‪ Inorder ,postorder ,preorder‬آن به‬
‫ترتیب معادل ‪ Infix, postfix, prefix‬عبارت را تولید مي كند‪.‬‬
‫درخت هاي دودویي نخي ‪:‬‬
‫اگر در ساختارهاي درختي دقت كنید خواهید دید كه اشاره گر ‪Left,Right‬تمامي برگها ‪Null‬مي‬
‫باشد همچنین گره هایي كه فقط یك فرزند دارند صاحب یك اشاره گر ‪Null‬نیز هستند‪.‬‬
‫تعداد زیاد اشاره گر هاي ‪Null‬كه بالاستفاده مانده اند ایده اي براي تولید درختاني به نام درختان‬
‫نخي شده است‪.‬در درختان نخي هر اشاره گر ‪Null‬كه از گره خارج مي شود به گره اي اشاره خواهد‬
‫کرد كه در پیمایش ‪Inorder‬گره بعدی یا قبلی محسوب شوداگر اشاره گر ‪ right‬تهی باشد آن‬
‫را به گره ای وصل می کند که در پیمایش ‪ inorder‬گره بعدی ما محسوب شده وگرنه به گره‬
‫ماقبل وصل مي كنیم‪.‬‬
‫مثال ‪ :‬در درخت زیر اشارهگرهای نخی را به درخت اضافه می کنیم ‪.‬‬
‫‪Inorder : DGFHBIEAJCLK‬‬
‫نمایش لیست هاي پیوندي با استفاده از درختان دودویي‪:‬‬
‫همان طور كه به خاطر دارید در یك لیست پیوندي رسیدن به ‪K‬امین عنصر مستلزم به پیمایش ‪K-1‬‬
‫عنصر ماقبل است‪.‬‬
‫مي توان یك لیست را روي یك درخت سوار كرد به گونه اي كه یافتن یك عنصر خاص با سرعت‬
‫بیشتري انجام شود ‪ .‬به مثال زیر توجه کنید‪:‬‬
‫لیستي مانند لیست زیر را در نظر بگیرید‪:‬‬
‫‪A‬‬
‫‪B‬‬
‫‪C‬‬
‫‪D‬‬
‫‪E‬‬
‫‪F‬‬
‫‪G‬‬
‫‪H‬‬
‫‪I‬‬
‫‪J‬‬
‫مي توان عناصر این لیست را به عنوان برگ هاي یك درخت دودویي قرار داد با این شرط كه با‬
‫پیمایش ‪Inorder‬ترتیب عناصر لیست حفظ شود یك نمونه از چنین درختي به شكل زیر است‪:‬‬
‫داخل هر گره غیر برگ عددي قرار مي گیرد كه نشان دهنده ي برگ هاي موجود در زیر درخت چپ‬
‫آن گره است‪.‬‬
‫عدد نوشته شده در هر گره به ما مي گوید كه كدام زیر درخت را طي كنیم اگر به دنبال عنصري‬
‫هستید كه از آن كمتر است زیر شاخه ي سمت چپ وگرنه زیر شاخه ي سمت راست را انتخاب كنید‬
‫اگر زیر درخت سمت راست انتخاب شود به اندازه ي شماره ي گره مي بایست از عدد جست و جو كم‬
‫كنید واگر كمتر و یا برابر باشد سمت چپ ‪.‬‬
‫براي یافتن یك گره ي خاص مي توان شبه كد زیر را ارائه كرد‪.‬‬
‫به دنبال ‪k‬امین گره می گردیم‪.‬‬
‫;‪r=k‬‬
‫;‪p=tree‬‬
‫( ‪ P‬به برگي نرسیده است‪While ( .‬‬
‫{‬
‫)‪If (r<=p Info‬‬
‫;‪p=p left‬‬
‫‪Else‬‬
‫{‬
‫;‪r=r- p Info‬‬
‫;‪p=p right‬‬
‫}‬
‫}‬
‫واضح است در چنین درختي سرعت دستیابي بیشتر خواهد شد تعداد مقایسات دراین درخت حداكثر به‬
‫اندازه ي عمق آن خواهد بود واگر درخت به شكل نرمال رشد كرده باشد عمق درخت برابر است‬
‫با ‪ log n‬یعني حداكثر تعداد مقایسات برابر با ‪log n‬خواهد شد اما حداكثر تعداد مقایسات در‬
‫داخل یك لیست برابر با ‪ n‬خواهد بود‪.‬‬
‫درخت هاي عمومي ‪:‬‬
‫یك درخت عمومي به طور كلي مجموعه اي از عناصر یك لیست غیر تهي است كه یكي از آن ها به‬
‫نام ریشه و ما بقي به ‪m>=0‬زیر مجموعه ي مجزا تقسیم مي شود كه هر یك درخت مي باشد‬
‫هرعنصر درخت گره نامیده مي شود‪.‬‬
‫مفاهیم پدر‪ ،‬پسر ‪،‬برادر ‪ ،‬جد ‪ ،‬نوه ‪ ،‬سطح وعمق همانند مفاهیم گفته شده در درختان دودویي است ‪.‬‬
‫درجه ي هر گره برابر است با تعداد فرزندان آن گره ‪.‬‬
‫درجه ي درخت برابر است با بیشترین درجه ي موجود در كل درخت‪.‬‬
‫درخت مرتب‪:‬‬
‫درختي است كه زیر درخت هر گره ي آن مجموعه ي مرتبي را تشكیل داده است‪.‬‬
‫در درخت مرتب پسران هر گره معموال به نام پسر اول ‪ ،‬پسر دوم و‪ ...‬تا پسر آخر نامیده مي شود این‬
‫نامگذاري معموال از چپ به راست انجام مي شود ‪.‬‬
‫اولین پسر پیرترین پسر و آخرین پسر جوان ترین پسر است‪.‬‬
‫تبدیل درخت عمومي به دودویي ‪:‬‬
‫‪)1‬ارتباط بین هرپدربا کلیه فرزندانش به جز اولین فرزند قطع مي شود‪.‬‬
‫‪)2‬ارتباط جدیدي بین اولین فرزند تا آخرین فرزند به وجود مي آید ‪.‬‬
‫‪ )3‬گره هایي كه حاوي اتصال جدید شده اند ‪ 45‬درجه در جهت حركت عقربه هاي ساعت دوران مي‬
‫كنند‪.‬‬
‫اگر پیمایش ‪preorder,inorder‬درخت دودویی رابه ما داده باشند می توانیم درخت دودویی‬
‫معادل آن را بسازیم به مثال زیر توجه کنید‪:‬‬
‫‪A‬‬
‫‪Preorder: A B C D E F G H I‬‬
‫‪Inorder: C B D A G F I H E‬‬
‫‪B‬‬
‫‪E‬‬
‫‪F‬‬
‫‪H‬‬
‫‪D‬‬
‫‪C‬‬
‫‪G‬‬
‫‪I‬‬
‫به دو پیمایش فوق توجه کنیدهمان طور که مشاهده می شود در پیمایش‪ preorder‬اولین عنصر‬
‫مشاهده شده ریشه درخت است ‪ .‬پیمایش ‪ inorder‬به ما کمک می کند تا بتوانیم مجموعه‬
‫عناصر موجود در زیر درخت چپ وراست ریشه را تعیین کنیم‪.‬‬
‫همان طور که مشاهده می شود می بایست ‪B,C,D‬زیر درخت چپ و همچنین ‪ E,F,G,H,J‬در‬
‫سمت راست‪.‬‬
‫‪A‬‬
‫‪E FG H I‬‬
‫‪BCD‬‬
‫در ادامه می توان از دو پیمایش نتیجه گرفت گرفت که بین ‪ B ، B,C,D‬ریشه است ‪.‬همچنین در‬
‫زیر درخت راست ریشه ‪ E‬است‪.‬مجددأ می توان به شکل قبل عمل کرد چون در پیمایش‬
‫‪ C، inorder‬قبل از ‪ B‬قرار گرفته فرزند چپ ‪ B‬خواهد بود و به همین دلیل ‪ D‬فرزند راست‬
‫‪ B‬خواهد شد‪.‬‬
‫‪A‬‬
‫‪A‬‬
‫‪B‬‬
‫‪E‬‬
‫‪F‬‬
‫‪IH‬‬
‫‪D‬‬
‫‪F‬‬
‫‪C‬‬
‫‪FGHI‬‬
‫‪B‬‬
‫‪D‬‬
‫‪C‬‬
‫‪G‬‬
‫در واقع برای تشکیل یک درخت ما همواره به ‪ 3‬اطالع نیازمندیم اوالً در هر مرحله ریشه ‪ ،‬چه‬
‫خواهد بود پیدا کردن ریشه از طریق پیمایش ‪ preorder‬معلوم می شود ثانیا ً زیر درخت‬
‫چپ چگونه خواهد بود‪ .‬زیر درخت چپ از طریق ‪ inorder‬فایل تشخیص است ثالثا ً زیر‬
‫درخت راست چگونه خواهد بود‪ .‬زیر درخت راست نیز از طریق ‪ inorder‬پیدا می شود پس‬
‫مراحل کار به شکل زیر خالصه می شود‪ .‬در هر گام‪:‬‬
‫‪-1‬ریشه از طریق ‪ preorder‬پیدا کنید‪.‬‬
‫‪-2‬زیر درخت چپ وزیردرخت راست را از طریق ‪ inorder‬پیدا کنید‪.‬‬
‫این کار تا زمانی که تمام گره ها خالی بوده یا حداکثر یک عنصر داشته باشند ادامه می یابد‪.‬‬
‫درخت حاصل را بدست آورید؟‬.‫ درختی به شکل زیر است‬preorder,inorder:‫مثال‬
Preorder: A B C D E F G H I
Inorder: B C A E D G H F I
A
A
BC
B
DEFGHI
D
C
E
FGHI
F
GH
F
G
H
I
I
‫نکته‪:‬با استفاده از روشی مشابه فوق می توان به کمک ‪ postorder,preorder‬یک درخت‬
‫دودویی به دست آورد‪.‬‬
‫نکته‪:‬پیمایش های ‪ preorder,inorder‬فقط یک درخت را نشان می دهد همچنین به ازای‬
‫پیمایش های ‪ inorder,postorder‬نیز تنها یک درخت به وجود می آیداما با داشتن‬
‫پیمایش های ‪preorder,postorder‬ممکن است بیش از یک درخت پدید آید‪.‬‬
‫توجه‪:‬به وسیله ‪ n‬مقدار متمایز می توان به تعداد ترکیب‬
‫‪ 2n ‬‬
‫‪‬‬
‫‪‬‬
‫‪ n‬‬
‫‪‬‬
‫‪‬‬
‫درخت متمایز ایجاد کرد‪.‬‬
‫‪n 1‬‬
‫!‪n‬‬
‫!)‪m!*(n  m‬‬
‫=‬
‫‪ ‬‬
‫‪n‬‬
‫‪m‬‬
‫!‪6‬‬
‫)‪3!*(6  3‬‬
‫‪4‬‬
‫‪:‬فرمول ترکیب‬
‫=‬
‫‪‬‬
‫‪6‬‬
‫‪3‬‬
‫‪4‬‬
‫جنگل‬
‫جنگل مجموعه اي مرتب از درخت هاي مرتب است‪.‬‬
‫سه روش براي پیمایش درختان جنگل وجود دارد‪.‬‬
‫روش ‪preorder , Inorder , postorder‬‬
‫پیمایش ‪:preorder‬‬
‫‪ )1‬ریشه درخت اول جنگل را مالقات كنید‪.‬‬
‫‪ )2‬جنگل تشكیل شده توسط زیر درخت هاي اولین درخت را در صورت وجود به شكل ‪preorder‬‬
‫پیمایش كنید‪.‬‬
‫‪ )3‬جنگل تشكیل شده توسط زیر درخت هاي باقیمانده جنگل را در صورت وجود به شكل ‪preorder‬‬
‫پیمایش دهید‪.‬‬
‫(طبق شکل صفحه قبل)‬
‫( برادرانم ‪‬فرزندانم ‪ ‬خودم ( ‪Preorder :‬‬
‫‪ABECFGDHIKJ LMORPQN STUWXYZV‬‬
‫درخت اول‬
‫درخت دوم‬
‫درخت سوم‬
‫پیمایش ‪:Inorder‬‬
‫‪ )1‬جنگل تشكیل شده توسط زیر درخت هاي اولین درخت جنگل را در صورت وجود به شكل‬
‫‪Inorder‬پیمایش كنید‪.‬‬
‫‪ )2‬مالقات ریشه درخت اول جنگل‪.‬‬
‫‪ )3‬جنگل تشكیل شده توسط درخت هاي باقیمانده جنگل را در صورت وجود به شكل ‪Inorder‬‬
‫پیمایش دهید‪.‬‬
‫)برادرانم ‪‬خودم ‪‬فرزندانم) ‪Inorder :‬‬
‫‪EBFGCHKIJDA‬‬
‫‪ROPQMNL TXYZWUVS‬‬
‫(طبق شکل صفحه قبل)‬
‫درخت اول‬
‫درخت دوم‬
‫درخت سوم‬
‫پیمایش ‪: Postorder‬‬
‫‪ )1‬جنگل تشكیل شده توسط زیردرخت هاي اولین درخت جنگل را در صورت وجودبه شكل‬
‫‪postorder‬پیمایش كنید‪.‬‬
‫‪ )2‬جنگل تشكیل شده توسط زیر درخت هاي تشكیل شده را در صورت وجود به شكل ‪Postorder‬‬
‫پیمایش دهید‪.‬‬
‫‪ )3‬ریشه اولین درخت جنگل را مالقات كنید‪.‬‬
‫(طبق شکل صفحه قبل)‬
‫(خودم‪‬برادرانم ‪‬فرزندانم) ‪Postorder :‬‬
‫‪EGFKJIHDCB‬‬
‫‪RQPONM‬‬
‫‪ZYXWVUTSLA‬‬
‫درخت اول‬
‫درخت دوم‬
‫درخت سوم‬
‫نكته‪:‬‬
‫اگر یك درخت عمومي را تبدیل به دودویي كنید در هر دو درخت هر سه پیمایش مي بایست نتیجه ي‬
‫یكساني در بر داشته باشد‪.‬‬
‫‪Preorder:ABECFGDHIKJ‬‬
‫‪Inorder:EBFGCHKIJDA‬‬
‫‪Postorder:EGFFKJIHDCBA‬‬
‫كدهاي هافمن‪:‬‬
‫الفبایي با ‪n‬عالمت وجود دارد یك پیام طوالني از نمادهاي این الفبا موجود است مي خواهیم پیام را‬
‫به صورت رشته اي طوالني از بیت ها به رمز درآوریم‪.‬‬
‫مثال‪:‬فرض كنید الفباي شما از ‪ 4‬حرف ‪A,B,C,D‬تشكیل شده باشد‪.‬‬
‫اگر نماد ها به شكل فوق انتخاب شده باشند براي كد كردن ‪ 8‬حرف به ‪ 16‬بیت نیازمندیم‪.‬‬
‫‪A B A C C D A A = 111011010100111116 bit‬‬
‫کد‬
‫‪11‬‬
‫‪10‬‬
‫‪01‬‬
‫‪00‬‬
‫نماد‬
‫‪A‬‬
‫‪B‬‬
‫‪C‬‬
‫‪D‬‬
‫اگر نماد ها به شكل فوق انتخاب شده باشند براي كد كردن ‪ 8‬حرف به ‪ 16‬بیت نیازمندیم‪(8*2=16).‬‬
‫در روش هافمن تعداد تكرارعال َِِیم مد نظر قرار مي گیرد به این صورت كه درخت دودویي ایجاد مي‬
‫شود كه ریشه ي آن تمام عالیم موجود در ریشه است ‪.‬سپس فرزند چپ درخت همان نمادي است كه‬
‫بیشترین تكرار را دارد و فرزند راست آن نمادهاي باقي مانده است‪.‬‬
‫زیر درخت هاي سمت راست نیز بنا به همین قانون توسعه مي یابد‪.‬‬
‫بر اساس رشته فوق تكرار عالیم درخت بدین صورت پدید مي آید‪.‬‬
‫براي پیاده كردن هر نماد به روش زیر عمل مي كنیم‪:‬‬
‫از برگ حاوي عالمت مورد نظر شروع كرده و به سمت باالي درخت حركت كنید در مسیر پیشروي‬
‫اگر از زیر درخت چپ به ریشه رسیدید (‪)0‬را به سمت چپ كد حاصل اضافه كنید وگرنه (‪ )1‬را اضافه‬
‫كنید این كار تا رسیدن به ریشه ي اصلي درخت ادامه پیدا مي كند‪.‬‬
‫‪A=0‬‬
‫‪C = 10‬‬
‫‪B = 110‬‬
‫‪D = 111‬‬
‫مروري بر پیچیدگي ها ‪:‬‬
‫الگوریتم هاي مختلفي براي انجام اعمال مختلف طراحي شده اند هر الگوریتم معیارهایي دارد كه مي‬
‫توان به وسیله ي آن معیارها چند الگوریتم مختلف را با یكدیگر مقایسه كرد به عنوان مثال در روش‬
‫جست و جو ما با الگوریتم هاي مختلفي مواجه هستیم كه هر یك كارایي خاص خود را دارد اگر‬
‫خواسته باشیم الگوریتم هاي مختلف را با یكدیگر بسنجیم مي بایست روشي استاندارد براي سنجش‬
‫آن ها داشته باشیم كه مورد پذیرش همگان باشد‪ .‬براي مقایسه الگوریتم ها باید معیارهایي انتخاب‬
‫شود كه وابسته به كامپیوتر ‪ ،‬برنامه نویس ‪ ،‬زبان برنامه نویسي و امثال آن نباشد‪ .‬بحث پیچیدگي‬
‫الگوریتم ها مي تواند به معناي درجه سختي الگوریتم باشد براي پیدا كردن پیچیدگي الگوریتم ها‬
‫ساده ترین راه آن است كه ابتدا عمل اصلي الگوریتم را حدس بزنیم به مثال زیر توجه كنید‪.‬‬
‫الگوریتم ‪:1‬‬
‫)‪Int search (into s [ ],int n,int x‬‬
‫{‬
‫;‪Int i=0‬‬
‫)‪While (s [i]! =x && i <=n-1‬‬
‫;‪i++‬‬
‫)‪If (i>=n‬‬
‫;)‪Return (-1‬‬
‫‪Else‬‬
‫} ;)‪Return (i‬‬
‫الگوریتم فوق به روش جست و جوي خطي معروف است در این روش عنصر مورد جست و جو (‪)X‬‬
‫قرار است در بازه اي از عناصر به نام ‪S‬جست و جو مي شود اگر عنصر مورد نظر در آرایه ي ‪S‬‬
‫قرارداشت اندیس آرایه را كه شامل ‪X‬است برگشت خواهد شد وگرنه ‪ -1‬برگشت داده می شود (‪-1‬‬
‫یعني عنصر مورد نظر وجود نداشت‪).‬در الگوریتم فوق عنصر ‪ X‬ابتدا با اولین اندیس ‪S‬مقایسه‬
‫میشود اگر برابر نبود مقایسه با عنصربعدي انجام خواهد شد‪ .‬انجام مقایسات تا لحظه اي ادامه‬
‫پیدا مي كند كه یا عنصر پیدا شده باشد یا اینكه از محدوده ي ‪S‬عبور كرده باشیم ‪.‬در الگوریتم‬
‫فوق عمل مقایسه عمل اصلي الگوریتم است‪.‬‬
‫الگوریتم ‪:2‬‬
‫{)‪Int max (int s [ ], int n‬‬
‫;‪Int max=0, i‬‬
‫;]‪Max=s[0‬‬
‫{)‪For (i=0, i<= n-1, i++‬‬
‫)]‪If (max < s[i‬‬
‫};]‪max=s[i‬‬
‫};)‪Return (max‬‬
‫در الگوریتم فوق نیز عمل اصلي مقایسه ‪Max‬با ]‪S[i‬مي باشد دستور ;]‪max=s[i‬نمي توانست‬
‫عمل اصلي با شد زیرا این دستور بعضي اوقات انجام مي شود امادربرخی ازمواردانجام نمی شود‬
‫پس مي توان گفت ‪:‬دستور اصلي دستوري است كه بیشترین تعداد تكرار را در الگوریتم دارا با‬
‫شد‪.‬‬
‫الگوریتم ‪:3‬‬
‫)‪Int Sum (int s [ ], int n‬‬
‫{‬
‫;‪, sum=0‬ه‪Inti‬‬
‫)‪For (i=0, i< =n, i++‬‬
‫;]‪Sm = sm+s[i‬‬
‫;)‪Return (sm‬‬
‫}‬
‫در الگوریتم فوق عمل اصلي عمل جمع ‪Sm‬با ]‪S[i‬مي باشد پس از شناخت عمل اصلي مي بایست‬
‫تعداد تكرار هاي آن را بدست آورید در اكثر الگوریتم ها این تعداد بر اساس ‪ n‬بدست مي آید (‪ n‬تعداد‬
‫عناصروروی است)در الگوریتم ها ي دوم و سوم تعداد تكرار عمل اصلي ‪n‬مرتبه مي باشد در‬
‫الگوریتم اول تعداد تكرار اعمال اصلي مي تواند یك یا دو یا ‪ ...‬یا ‪n‬مرتبه بوده باشد پس از‬
‫تعیین تكرار هاي عمل اصلي معموال رابطه اي بر اساس ‪n‬پیدا مي شود معموال یك چند جمله اي‬
‫بر اساس ‪n‬پیدا مي شود در چند جمله اي بدست آمده كافي است بزرگترین جمله را انتخاب كرده‬
‫ضرایب ثابت آن را حذف كنید آنچه كه بدست مي آید پیچیدگي الگوریتم شما است ‪.‬‬
‫در الگوریتم دوم تعداد اعمال اصلی برابر ‪n‬است پس مي توان گفت پیچیدگي الگوریتم ‪n‬مي باشد‪.‬‬
‫هنگام پیدا كردن پیچیدگي به طور كلي با دو گروه از الگوریتم ها مواجه هستیم ‪.‬‬
‫‪ )1‬الگوریتم هایي كه پیچیدگي آن ها وابسته به مقادیر ورودي نیست به عنوان مثال الگوریتم سوم یا‬
‫‪sum‬بدون توجه به این كه چه مقداري در ‪S‬قرار دارند آنها را با هم جمع كنند هم چنین در‬
‫الگوریتم ‪max‬اگرچه عناصر ]‪S[i‬مهم هستند الگوریتم مجبور است تمام آن ها را بررسي كند تا‬
‫بتواند ‪ max‬را بیابد‪.‬‬
‫‪ )2‬الگوریتم هایي كه پیچیدگي آن ها وابسته به مقادیر ورودي است به عنوان مثال تعداد تكرار ها‬
‫در الگوریتم ‪Search‬وابسته به این است كه عناصر مورد جست و جو در كجاي ‪S‬واقع شده با‬
‫شد‪ .‬الگوریتم هایي كه پیچیدگي آن ها وابسته به مقادیر ورودي نیست گروه اول از الگوریتم هاي ما‬
‫بودند پیچیدگي این الگوریتم ها را با نماد )‪T(n‬نشان مي دهیم‪.‬‬
‫)‪T (n‬عبارت است از پیچیدگي زماني الگوریتم مورد نظر بر اساس ‪n‬عنصر ورودي ‪.‬الگوریتم‬
‫هایي كه پیچیدگي زماني آن ها وابسته به مقادیر ورودي است با سه نماد زیر پیچیدگي آن ها را نشان‬
‫مي دهیم‪.‬‬
‫بهترین حالت‬
‫)‪B (n‬‬
‫حالت متوسط‬
‫)‪A (n‬‬
‫بدترین حالت‬
‫)‪W (n‬‬
‫به عنوان مثال الگوریتم پیدا كردن یك عنصر خاص (جست و جوي خطي )را در نظر بگیرید در‬
‫بهترین حالت با یك مقایسه عنصر مورد نظر پیدا مي شود بنابراین ‪ B (n)=1‬در بدترین حالت با‪n‬‬
‫مورد نظر ‪‬پیدا مي شود ‪ w(n)=n‬و در حالت متوسط تقریبا نیمي از عناصر‬
‫مقایسه عنصر‬
‫‪n ‬‬
‫‪‬‬
‫مقایسه مي شود ‪ .  An ‬در الگوریتم حاصل جمع تعداد اعمال اصلي به مقادیر ورودي‬
‫‪2‬‬
‫‪‬‬
‫وابسته نیست و همواره ‪ n‬عمل جمع باید انجام شود ‪.‬در این صورت مي گوییم ‪T(n)=n‬هم چنین‬
‫براي پیدا كردن بزرگترین عنصر در میان لیست تمامي عناصر لیست باید مقایسه شود و این‬
‫الگوریتم نیز به مقادیر ورودي وابسته نیست پس تعداد اعمال اصلي آن بر اساس( ‪ T(n‬بیان مي‬
‫شود ‪.‬‬
‫مثال‪:‬مرتب سازي حبابي را در نظر بگیرید ‪.‬‬
‫‪n 1 ‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪2‬‬
‫‪‬‬
‫‪n‬‬
‫‪‬‬
‫)‪1+2+3+…+ )n-2) (n-1‬‬
‫مقایسه )‪ =(n-1‬مرحله اول‬
‫مقایسه )‪ =(n-2‬مرحله دوم‬
‫مقایسه )‪ =(n-3‬مرحله سوم‬
‫در الگوریتم مرتب سازي حبابي )‪(bobel sort‬عمل اصلي ‪ ،‬عمل مقایسه است ‪.‬تعداد مقایسات در‬
‫این الگوریتم برابر است با ‪ n  n 1‬یعني پیچیدگي الگوریتم در حالت معمولي ‪ n  n 1‬مي با شد‬
‫‪2‬‬
‫‪2‬‬
‫‪.‬‬
‫مثال ‪:‬جست و جوي دودویي )‪(binnary search‬‬
‫در روش جست و جوي دودویي فرض مي شود كه عناصر موجود مرتب هستند وقراراست عنصري‬
‫در میان آن ها پیدا شود براي سرعت بخشیدن به جست و جو عنصر مورد نظر با عنصر میان لیست‬
‫مقایسه مي شوداگر برابر باشد جست و جو خاتمه مي یابد وگرنه بررسي مي شود كه میانه لیست از‬
‫عنصر مورد نظر بزرگتر است یا كوچكتر اگر میانه لیست از عنصر جست و جو بزرگتر باشد جست و‬
‫جو را در بازه ي چپ لیست تكرار مي كنیم وگرنه در با زه ي راست لیست جست و جو انجام مي شود‬
‫این كار تا رسیدن به عنصر مورد نظر و یا پیدا نشدن آن تكرار مي شود ‪.‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪n‬اگر ‪n‬عنصر در اختیار ما باشد در روش جست و جوي دودویي حداكثر تعداد مقایسات برابر‬
‫‪ log 2‬خواهد بود‪ .‬از دو مثال فوق مشاهده مي شود كه ممكن است تعداد اعمال اصلي در یك‬
‫الگوریتم همواره مثل ‪An+b‬نباشد‪.‬ممكن است تعداد اعمال اصلي تواني از ‪n‬و یا ‪ Log n‬بدست‬
‫آید‪.‬‬
‫‪1‬‬
‫‪1‬‬
‫‪ n 1 = 1‬‬
‫‪‬‬
‫‪nn 1 = n2  n‬‬
‫‪2‬‬
‫‪2‬‬
‫‪2‬‬
‫‪2‬‬
‫‪‬‬
‫‪‬‬
‫‪n‬‬
‫براي سنجش الگوریتم ها به طور استاندارد آن ها را در گروه هایي دسته بندي مي كنند به این گروه‬
‫ها گروه هاي پیچیدگي مي گوییم ‪.‬گروه هاي پیچیدگي معروف‪n‬عبارت اند از‪:‬‬
‫‪n‬‬
‫‪C‬‬
‫‪n‬‬
‫‪n^2‬‬
‫!‪n^2log n n^3 … 2^n 3^n n‬‬
‫‪n log‬‬
‫‪log‬‬
‫‪2‬‬
‫‪2‬‬
‫عدد ثابت‬
‫هنگام دسته بندي الگوریتم ها در گروه هاي پیچیدگي از ‪ 3‬نماد زیر استفاده مي شود‪:‬‬
‫‪: Big O‬‬
‫اگر پیچیدگي در گروه ‪O‬بزرگ قرار بگیرد به این معنا است كه الگوریتم در بدترین حالت پیچیدگي‬
‫اش در محدوده ي ‪O‬واقع شده است به عنوان مثال ‪:‬‬
‫‪1 2 1‬‬
‫‪2‬‬
‫‪n  n €O n‬‬
‫‪2‬‬
‫‪2‬‬
‫از دیدگاه نموداري ‪ ،‬نمودار الگوریتمي كه متعلق به ‪ O‬یك پیچیدگي باشد زیر نمودار گروه پیچیدگي‬
‫‪n € O n2‬‬
‫قرار خواهد گرفت‪.‬‬
‫‪ Ω‬امگا ‪:‬‬
‫اگر یك تابع پیچیدگي (منظور رابطه اي است كه تعداد اعمال اصلي را بیان مي كند) متعلق به ‪ Ω‬یك‬
‫گروه باشد آن گاه تابع پیچیدگي شما در بهترین حالت در گروه پیچیدگي ذكرشده واقع خواهد شد به‬
‫بیان دیگر تابع پیچیدگي شما از نظر نموداري باالي گروه پیچیدگي یاد شده واقع مي شود‪.‬‬
‫‪ : N € O n2‬تابع پیچیدگي‬
‫(‪ : N 2  € Ω )n‬گروه پیچیدگي‬
‫‪ ‬‬
‫‪ ‬‬
‫‪ ‬‬
‫نماد ‪:Ө‬‬
‫اگر هم تابع پیچیدگي بتواند هم در گروه پیچیدگي ‪O‬هم در گروه پیچیدگي ‪ Ω‬واقع شود آن گاه مي‬
‫توان گفت تابع پیچیدگي متعلق به ‪ Ө‬گروه پیچیدگي است ‪.‬ساده ترین روش شناخت ‪ Ө‬استفاده از حد‬
‫و یا ‪Lim‬مي باشد ‪.‬‬
‫اگر‬
‫مقداري ثابت =گروه پیچیدگي ‪ /‬تابع پیچیدگي ‪Lim‬‬
‫∞‪n‬‬
‫آن گاه‬
‫(گروه پیچیدگي ) ‪ € Ө‬تابع پیچیدگي‬
‫مثال‪:‬در جست و جوي خطي تعداد اعمال اصلي برابر با ‪ n‬بود (در بدترین حالت ) تابع پیچیدگي در‬
‫بد ترین حالت یعني ‪F(n)=n‬خواهد بود‪.‬از آن جا كه ‪Lim n/n=1‬آن گاه مي توان گفت‬
‫پیچیدگي روش جست و جوي خطي در بدترین حالت متعلق به ) ‪ Ө (n‬است هم چنین چون كلمه‬
‫ي بد ترین حالت ذكر شده است مي توان گفت به )‪O (n‬تعلق دارد‪.‬‬
‫در مثال دوم ‪Max‬تعداد اعمال اصلي برابر با ‪n‬است و پیچیدگي آن متعلق به )‪Ө(n‬است ‪.‬‬
‫در مثال سوم)‪ (sum‬پیچیدگي الگوریتم متعلق به )‪ Ө (n‬خواهد بود‪.‬‬
‫در مثال چهارم)مرتب سازی حبابی) تعداد اعمال اصلي از رابطه ي زیر بدست مي آید‪.‬‬
‫‪ ‬‬
‫‪2‬‬
‫پیچیدگي این الگوریتم متعلق به ‪ Ө n‬مي باشد ‪.‬‬
‫‪1 2 1‬‬
‫‪n  n‬‬
‫‪2‬‬
‫‪2‬‬
‫= )‪F (n‬‬
‫در جست و جوي دودویي پیچیدگي الگوریتم در بدترین حالت ‪ Ө log n ‬خواهد بود این جا نیز مي‬
‫‪n‬‬
‫توان گفت پیچیدگي متعلق به ‪ O log 2‬خواهد بود‪.‬‬
‫نکته ‪ :‬در رابطه با درختان نرمال گفته بودیم که یک درخت نرمال درختی است که عمق تمامی‬
‫شاخه‬
‫های آن تقریبا هم اندازه باشد ‪ .‬تعریف دقیقتری به نام درخت ‪ AVL‬وجود دارد ‪.‬‬
‫درخت ‪ : AVL‬درختی که تفاضل ارتفاع هر دو زیر درخت آن برابر با ‪ 0‬یا ‪ 1‬باشد ‪.‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫تفاضل زیر درخت ‪ A‬برابر ‪، 0‬‬
‫تفاضل زیر درخت ‪ B‬برابر ‪ 1‬و‬
‫تفاضل زیر درخت ‪ C‬برابر ‪ 1‬است‪.‬‬
‫روش هاي مرتب سازي‪:‬‬
‫الگوریتم هاي مرتب سازي زیادي وجود دارد كه برخي از آن ها مطا لعه شده اند به عنوان مثال‬
‫‪2‬‬
‫روش مرتب سازي حبابي با پیچیدگي ‪ n‬ونیز استفاده از یك درخت جست و جوي دودویي و‬
‫پیمایش ‪ Inorder‬آن با پیچیدگي(‪ ) nlog n‬قبال بررسي شد‪.‬‬
‫مرتب سازي درج ساده یا ‪:Insertion sort‬‬
‫در این روش لیستي از اعداد نا مرتب وجود دارد قصد داریم آن ها را یكي یكي برداشته و یك صف‬
‫اولویت صعودي به وسیله ي آن ها ایجاد كنیم هر عنصر جدید از ابتداي لیست مقایساتش را آغاز مي‬
‫كند وبا پیشروي در لیست در محل منطقي اش درج مي گردد‪.‬‬
‫مثال‪:‬در بدترین حالت وبهترین حالت ‪ θ‬الگوریتم جه خواهد بود؟‬
‫‪7‬‬
‫‪2‬‬
‫‪9‬‬
‫‪4‬‬
‫‪6‬‬
‫‪8‬‬
‫‪3‬‬
‫‪7‬‬
‫‪2‬‬
‫‪7‬‬
‫‪2‬‬
‫‪7‬‬
‫‪9‬‬
‫‪2‬‬
‫‪4‬‬
‫‪7‬‬
‫‪9‬‬
‫‪2‬‬
‫‪4‬‬
‫‪6‬‬
‫‪7‬‬
‫‪9‬‬
‫‪2‬‬
‫‪4‬‬
‫‪6‬‬
‫‪7‬‬
‫‪8‬‬
‫‪9‬‬
‫‪2‬‬
‫‪3‬‬
‫‪4‬‬
‫‪6‬‬
‫‪7‬‬
‫‪8‬‬
‫‪9‬‬
‫در بهترین حالت یعني زماني كه عناصر به شكل نزولي مرتب هستند روش مرتب سازي درج تنها با‬
‫‪ n-1‬مقایسه قادر است اعداد را مرتب كند در نتیجه مي توان گفت پیچیدگي الگوریتم در بهترین‬
‫حالت از درجه ي ‪ n‬مي با شد یا)‪(Ωn‬برای بهترین حالت‪.‬‬
‫در بدترین حالت یعني زماني كه عناصر ساختاري صعودي دارند هر عنصر جدید مجبور است با تمام‬
‫‪2‬‬
‫عناصر لیست مقایسه شودوپیچیدگی آن) ‪ O( n‬می شود‪.‬‬
‫‪1‬‬
‫‪2‬‬
‫‪3‬‬
‫‪4‬‬
‫‪5‬‬
‫‪1‬‬
‫‪1‬‬
‫‪1‬‬
‫‪2‬‬
‫‪2‬‬
‫‪1‬‬
‫‪2‬‬
‫‪3‬‬
‫)‪1+2+3+...+(n-1‬‬
‫‪2‬‬
‫‪3‬‬
‫‪ nn  1  = 1 n2  1 n‬‬
‫‪1‬‬
‫‪2‬‬
‫‪3‬‬
‫‪4‬‬
‫‪‬‬
‫‪Ө‬‬
‫(‬
‫)‬
‫‪n‬‬
‫‪‬‬
‫‪‬‬
‫‪2‬‬
‫‪2‬‬
‫‪1‬‬
‫‪2‬‬
‫‪3‬‬
‫‪4‬‬
‫‪5 4‬‬
‫‪ 2 ‬‬
‫مرتب سازي سریع یا ‪:Quick sort‬‬
‫در این روش یكي از عناصر موجود در لیست را به عنوان عناصر محوري انتخاب مي كنند ‪ .‬تمام‬
‫عناصر لیست با عنصر محوري مقایسه مي شوند اگر عنصري كوچكتر باشد سمت چپ وگرنه سمت‬
‫راست قرار مي گیرد اعداد كوچكتر و بزرگتر از عنصر محوري ‪ 2‬لیست مجزا را به وجود مي آورند‬
‫براي هریك از لیست هاي بدست آمده عمل فوق را تكرار كنید این كار تا زماني كه تمام عناصر از‬
‫یكدیگر جدا شوند ادامه دارد تا ‪n‬لیست تك عنصري به وجود مي آید‪.‬‬
‫‪5 7 3 9 1 4 6 8‬‬
‫اعداد را به صورت صعودی در نظر می گیریم ‪:‬‬
‫‪5‬‬
‫)‪1+…+)n-1‬‬
‫‪=  nn2 1 ‬‬
‫‪2‬‬
‫‪= 12 n2  12 n = O n‬‬
‫‪ ‬‬
‫‪4‬‬
‫‪3‬‬
‫‪2‬‬
‫تعدادمقایسات‬
‫)‪(n-1‬‬
‫)‪(n-2‬‬
‫)‪(n-3‬‬
‫‪1‬‬
‫در این روش بدترین حالت زماني است كه هربار یك طرف محور كامال خالي باشد به عنوان مثال‬
‫(اعداد شكلي صعودي داشته باشند ) در این صورت مجموع تعداد مقایسات از رابطه ي زیر به دست‬
‫مي آید‪1+2+…+ )n-1) .‬‬
‫‪1‬‬
‫‪ ‬‬
‫پس مي توان گفت پیچیدگي روش ‪Quick sort‬در بدترین حالت ‪bigO n2‬مي باشد‪.‬‬
‫گونه اي است كه تعداد عناصر سمت راست و چپ آن تقریبا برابر است‬
‫در بهترین حالت عنصر به‬
‫‪n‬‬
‫‪ log‬مرحله الزم است تا عناصر كامال جدا شود در هر مرحله‬
‫در این صورت حداكثر‬
‫‪2‬‬
‫حداكثر ‪ n‬مقایسه انجام مي شود بنابراین مي توان گفت كل مقایسات برابر است با‬
‫‪‬‬
‫‪‬‬
‫پس مي توان گفت پیچیدگي ‪Quick sort‬دربهترین حالت ‪ Өn log n‬است ویا ‪ n log n2 ‬‬
‫‪‬‬
‫‪‬‬
‫مي باشد ‪ .‬مي توان ثابت كرد در روش ‪ Quick sort‬در حالت متوسط پیچیدگي اش ‪nlog n‬‬
‫بیشتر نیست ‪.‬‬
‫نكته ‪:‬اگر اعداد كامال تصادفي باشد روش ‪Quick sort‬در روش مرتب سازي جز بهترین هاست‪.‬‬
‫مرتب سازي ادغام یا ‪:Merge sort‬‬
‫در این روش لیست هاي حاوي ‪n‬عنصر به دوزیر لیست هر‬
‫‪2‬‬
‫یك حاوی ‪ n‬عنصر شكسته مي شود هریك از دو عنصرزیر لیست‬
‫مجددا به دو بخش شكسته خواهد شد این عمل آن قدر ادامه‬
‫پیدا مي كند كه ‪n‬لیست تك عنصري پدید آید هریك از لیست‬
‫هاي تك عنصري دو به دو در یكدیگر ادغام مي شوند عمل‬
‫ادغام به گونه ایست كه هر دو زیر لیست را به صورت مرتب‬
‫شده در زیر لیست ادغام مي نماید عمل ادغام زیر لیست ها آن‬
‫قدر تكرار مي شود كه یك لیست مرتب شده پدید آید‪.‬‬
‫از دیدگاه ساده تر مي توان گفت كه روش ‪Merge sort‬به نوع مقادیر ورودي وابستگي ندارد‬
‫مشابه با تحلیل الگوریتم مي توان گفت پیچیدگي ‪Merge sort‬تا لحظه اي كه لیست ها تك عنصري‬
‫مي شوند برابر با(‪ )n log n‬مي شود از طرفي اعمال تركیب تا رسیدن به لیست واحد نیز انعكاسي‬
‫از بخش فوقاني است پس پیچیدگي آن نیز ‪n log n‬خواهد بود نتیجه اینكه پیچیدگي كل مراحل‬
‫همان (‪ )n log n‬است زیرا ( ‪(2n log n‬با پیچیدگي )‪(n log n‬برابر است (چون ‪2‬یك‬
‫ضریب ثابت است ) پس نهایتا به ) ‪ Ө( nlog n‬رسیدیم‪.‬‬
‫مرتب سازي هرمي یا ‪:heap sort‬‬
‫تعریف درخت ‪: heap‬‬
‫درختي است كه پدر مقدارش از فرزندانش بیشتر (كمتر)است ‪.‬‬
‫براساس تعریف فوق دو گونه از درختان ‪heap‬وجود دارد‪.‬‬
‫‪Min heap )2‬‬
‫‪Max heap )1‬‬
‫‪ :Max heap‬درختي است كه اوال ساختارش مثل یك درخت دودویي كامل است و عالوه بر آن مقدار‬
‫هر گره پدر از فرزندانش بیشتر باشد‪.‬‬
‫‪ :Min heap‬درختي است كه اوال ساختارش مثل یك درخت دودویي كامل است و عالوه برآن‬
‫مقدارهرگره ی پدرازفرزندانش کمتراست‪.‬‬
‫تعریف مشابهي را براي ‪Min heap‬نیز مي توان ارائه داد ‪.‬‬
‫در روش ‪heap sort‬فرض مي كنیم كه درخت دودویي همانند یك درخت كامل رشد مي كند هر گره‬
‫جدید كه به درخت اضافه مي شود مقدار جدیدي را در خود خواهد داشت پس از درج مقدار جدید مي‬
‫بایست بررسي كنیم كه قانون درخت به هم نخورده باشد اگر چنین شد جاي فرزند و پدر را با یكدیگر‬
‫عوض مي كنیم این كار ممكن است چندین مرحله تكرار شود‪.‬‬
‫مثال‪:‬اعداد زیر را در یك درخت ‪Min heap‬قرار دهید؟‬
‫‪2‬‬
‫‪1‬‬
‫‪6‬‬
‫‪7‬‬
‫‪4‬‬
‫‪3‬‬
‫‪9‬‬
‫‪5‬‬
‫پس از ایجاد یك ‪Min heap‬از اعداد ورودي مي توانیم آن ها را به شكل زیر از درخت حذف كنیم‬
‫به گونه اي كه اعداد حذف شده ترتیب صعودي داشته باشند‪ .‬محتواي ریشه را با آخرین گره اي كه به‬
‫درخت اضافه شده جا به جا كنید سپس آخرین گره را به عنوان كوچكترین مقدار حذف نمایید این‬
‫اعمال را آن قدر تكرار كنید كه گره اي در درخت باقي نماند‪.‬‬
‫توجه داشته باشید كه در هر مرحله ممكن است مجبور باشید مقادیر گره را جا به جا كنید‪.‬‬
‫تحلیل پیچیدگي ‪:heap sort‬‬
‫در درختان ‪heap‬عمق درخت همواره به طور تقریب ‪ log2n‬است اگر گره اي جدید به درخت‬
‫اضافه شود براي اینكه درخت ‪ Min heap‬باقي بماند ممكن است مقدار آن گره جدید مرتبا جا‬
‫به جا شده اگر این جا به جایي تا ریشه ي درخت ادامه پیدا كند تعداد این جا به جایي ها متناسب با‬
‫عمق درخت تقریبا ‪log n‬خواهد شد حال اگر فرض كنیم كه ‪n‬گره جدید قرار است به درخت اضافه‬
‫شود وبا هر اضافه شدن حداكثر ‪ log2n‬جا به جایي انجام پذیرد كل جا به جایي ها تقریبا برابر با‬
‫‪n log n‬خواهد شد در نتیجه پیچیدگي ساخت یك ‪min heap‬حداكثرازدرجه ي (‪O (n logn‬‬
‫خواهد بود هنگام حذف گره ها نیز ممكن است نیاز به جا به جایي گره ها داشته باشیم كه این تعداد‬
‫نیز مي تواند تا عمق درخت ادامه داشته باشد در نتیجه همانند آنچه كه در تحلیل باال آمده پیچیدگي‬
‫حذف همه ي گره ها برابر با ) ‪O( n log n‬خواهد بودپیچیدگي كل روش ‪heap sort‬برابر با‬
‫مجموع پیچیدگي هاي مربوط به قسمت ساخت درخت که پیچیدگی آن ‪ n log n‬و قسمت تخریب آن كه‬
‫پیچیدگي آن ) ‪)nlog n‬مي با شد كه این پیچیدگي )‪)n log n‬را در پي خواهد داشت ‪.‬‬
‫‪ ‬‬
‫‪ ‬‬
‫‪n log n + n log n= 2 n log n  nlog n‬‬
‫پیچیدگی کامل‬
‫پیچیدگی تخریب پیچیدگی ساخت‬
‫مرتب سازي مبنا یا ‪: Radix sort‬‬
‫دراین روش ابتدا عناصربراساس كم ارزش ترین مكانشان مرتب مي شوند سپس آنچه بدست مي آید‬
‫را بر اساس مكان با ارزش بیشتر مرتب مي كنند این اعمال تا پرارزش تر ین مكان ادامه مي یابد‪.‬‬
‫مثال‪:‬اعداد زیر را به روش ‪Radix sort‬مرتب كنید؟‬
‫‪125,290,43,321,443,118,12,20,39,110,256‬‬
‫بر اساس یکان‬
‫بر اساس دهگان‬
‫بر اساس صدگان‬
‫‪0 290,20,110‬‬
‫‪0‬‬
‫‪0 12,20,39,43‬‬
‫‪1 321‬‬
‫‪1 110,12,118‬‬
‫‪1 110,118,125‬‬
‫‪2 12‬‬
‫‪2 20,321,125‬‬
‫‪2 256,290‬‬
‫‪3 43,443‬‬
‫‪3 39‬‬
‫‪3 321‬‬
‫‪4‬‬
‫‪4 43,443‬‬
‫‪4 443‬‬
‫‪5 125‬‬
‫‪5 256‬‬
‫‪5‬‬
‫‪6 256‬‬
‫‪6‬‬
‫‪6‬‬
‫‪7‬‬
‫‪7‬‬
‫‪7‬‬
‫‪8 118‬‬
‫‪8‬‬
‫‪8‬‬
‫‪9 39‬‬
‫‪9 290‬‬
‫‪9‬‬
‫اگر‪m‬تعداد ارقام بزرگترین عددو‪n‬تعداد اعداد باشد پیچیدگی الگوریتم آن به صورت زیر است‪:‬‬
‫)‪T(n) € (m,n‬‬
‫توابع بازگشتي‪:‬‬
‫توابعي هستند كه در بدنه تابع خود آن تابع فراخواني مي شود ‪.‬‬
‫مثال‪ :‬با استفاده از توابع بازگشتي فاكتوریل ‪ n‬را محاسبه كنید؟‬
‫‪n>=1‬‬
‫)‪n* fact (n-1‬‬
‫‪n ==0‬‬
‫‪1‬‬
‫‪n>=1‬‬
‫)‪n * (n-1‬‬
‫= )‪ fact (n‬‬
‫=!‪n‬‬
‫‪1‬‬
‫‪n=0‬‬
‫)‪int fact(int n‬‬
‫{‬
‫)‪if (n==1‬‬
‫;)‪return(1‬‬
‫‪else‬‬
‫;))‪return (n*fact(n-1‬‬
‫}‬
‫مثال هاي دیگري از توابع بازگشتي‪:‬‬
‫مثال ‪ :1‬با استفاده از توابع بازگشتي ‪ a^b‬را محاسبه كنید؟‬
‫‪b>=1‬‬
‫‪b=0‬‬
‫‪a * a b1‬‬
‫‪b‬‬
‫=‪a‬‬
‫‪1‬‬
‫)‪int power (int a , int b‬‬
‫{‬
‫)‪If (b==0‬‬
‫;)‪return (1‬‬
‫‪else‬‬
‫;))‪return (a * power(a , b-1‬‬
‫}‬
‫) را حساب كنید؟‬a , b) ‫ با استفاده از توابع بازگشتي ب م م‬:2 ‫مثال‬
b
if
a%b ==0
bmm(a,b)=
bmm (b , a%b)
int bmm (int a , int b)
{
If ( a%b ==0 )
return (b);
else
return (bmm (b , a%b ));
}
a%b !=0
‫مثال ‪ :3‬جستجوي دودویي را با استفاده از توابع بازگشتي پیاده سازي كنید؟‬
‫) ‪int binsearch ( int s[n] , x‬‬
‫{‬
‫‪ x‬را با عنصر وسط لیست ‪ s‬مقلیسه كن ‪.‬‬
‫اگر برابر باشد‬
‫بازگشت بده اندیس عنصر وسط را‬
‫وگرنه اگر بزرگتر باشد‬
‫;)‪ , x‬نیمه سمت راست ‪binsearch ( s‬‬
‫;)‪ , x‬نیمه سمت چپ ‪binsearch ( s‬‬
‫{‬
‫روش هاي ‪ merge sort‬و ‪ quick sort‬را نیز مي توان به كمك توابع بازگشتي پیاده سازي كرد‪.‬‬
‫گراف ها‪:‬‬
‫هر گراف ‪ G‬شامل دو مجموعه به نام هاي ‪V,E‬مي باشد ‪.‬‬
‫‪ : V‬مجموعه اي متنا هي و غیر تهي از رئوس مي باشد‪.‬‬
‫‪ : E‬مجموعه اي از زوج راس ها كه به آن یال گفته مي شود‪.‬‬
‫)‪ : V (G‬مجموعه اي از راس هاي گراف ‪G‬‬
‫)‪ : E (G‬مجموعه اي از یال هاي گراف ‪G‬‬
‫براي نمایش یك گراف به شكل زیر عمل مي كنند‪.‬‬
‫گراف بدون جهت ‪:‬‬
‫گرافي است كه در آن زوج رئوسي كه یك یال را نشان مي دهند ترتیبشان بي اهمیت است مثال اگر‬
‫‪v,u‬دو راس طرفین یك یال باشند آن گاه )‪(u,v) , (v,u‬هر دو یك یال را نشان مي دهند‪.‬‬
‫مثال زیر نمایشي از یك گراف بدون جهت است ‪.‬‬
‫}‪V(G)={v1,v2,v3,v4‬‬
‫})‪E(G)={(v1,v2),(v2,v4),(v2,v3),(v4,v2‬‬
‫گراف جهت دار‪:‬‬
‫در گراف جهت دار هر یال با یك زوج مرتب نشان داده مي شود به عنوان مثال یال >‪<u,v‬در یك‬
‫گراف جهت دار یالي است كه از ‪u‬آغاز شده و به ‪v‬ختم مي شود ‪.‬‬
‫مثال زیر نمونه اي از یك گراف جهت دار است ‪:‬‬
‫}‪V(G2)={V1,V2,V3,V4,V5‬‬
‫>‪E(G2)={<V1,V2>,<V2,V1>,<V1,V3>,<V5,V3‬‬
‫}>‪,<V5,V4>,<V4,V1>,<V2,V4‬‬
‫نكته‪:‬معموال در داخل هر راس فقط شماره ي آن نوشته مي شود ‪.‬‬
‫در گراف هایي كه با آن كار مي كنیم محدودیت هاي زیر را در نظر مي گیریم اگر چه گراف ها مي‬
‫توانند این محدوده را نداشته باشند‪.‬‬
‫‪ )1‬یك گراف از هر راس به خودش یالي ندارد(به چنین یال هایي ‪Self edge‬یا خودیالی گفته مي شود‪) .‬‬
‫‪ )2‬در یك گراف یك یال نباید تكرار شود به چنین گراف هایي ‪Multi graph‬گفته مي شود به این‬
‫گراف ها ‪ ،‬گراف چند كاره نیز گفته مي شود ‪.‬‬
‫‪ nn 1 ‬‬
‫‪‬‬
‫‪n| ‬‬
‫‪ 2 ‬‬
‫اگر یك گراف بدون جهت شامل ‪n‬راس داشته باشیم حداكثر تعداد یال هاي آن برابر با ‪n(n-1)/2‬‬
‫مي باشد‪.‬‬
‫‪n‬‬
‫‪e‬‬
‫‪1‬‬
‫‪0‬‬
‫‪2‬‬
‫‪1‬‬
‫‪3‬‬
‫‪3‬‬
‫‪4‬‬
‫‪6‬‬
‫‪5 10‬‬
‫‪ nn 1 ‬‬
‫گراف بدون جهت تعداد یال هاي آن ‪  2 ‬باشد با وجود ‪n‬راس گراف كامل نامیده مي شود‪.‬در‬
‫یك گراف جهت دار بدون راس تعداد یا ل ها برابر )‪n(n-1‬مي باشد‪.‬‬
‫اگر در یك گراف مانند ‪G‬یالي به صورت )‪(u,v‬وجود داشته باشد آن گاه رئوس ‪u,v‬را مجاور‬
‫گویند و یال )‪(u,v‬را یك یال متالقي روي ‪u,v‬مي نامنددر واقع مي توان گفت یال هاي متالقي روي‬
‫راس ‪v‬یال هایي هستند كه یك طرف آن ها راس ‪v‬مي باشد به عنوان مثال گراف زیر را در نظر‬
‫بگیرید‪.‬‬
‫در این گراف راس ‪0,1‬مجاورند و همچنین رئوس )‪(0,3) ,(3,2) ,(0,2‬هریك دو به دو مجاور هم‬
‫هستند اما راس ‪ 1,2‬مجاور هم نمي باشند در این گراف یال هاي متالقي روي راس ‪0‬عبارت اند‬
‫از ‪.(1,0),(2,0),(3,0):‬‬
‫مفاهیم فوق در یك گراف جهت دار نیز مطرح مي شود اگر یال >‪<u,v‬یك یال جهت دار باشد آن گاه‬
‫راس ‪ u‬را مجاور به راس ‪ v‬و راس ‪v‬را مجاور از راس ‪ u‬مي گویند همچنین یال >‪<u,v‬روي دو‬
‫راس ‪ u,v‬متالقي است‪.‬‬
‫مثال‪ :‬در گراف زیر راس ‪0‬به راس ‪1,3‬مجاور است‪.‬‬
‫راس ‪ 3‬مجاور از راس ‪ 0‬است یال ها ي متالقي روي راس ‪0‬عبارت اند از ‪:‬‬
‫>‪<0,1> , <2,0>,<0,3‬‬
‫یك زیر گراف از گراف ‪:G‬‬
‫گرافي مانند ́‪G‬را داریم به نحوي كه )‪E(Ǵ)  E(G), V(Ǵ) V(G‬باشد‪.‬‬
‫به عنوان مثال گراف زیر را در نظر بگیرید تعدادي از زیر گراف ها ي ‪G‬عبارت اند از ‪:‬‬
‫مسیر یا ‪:Path‬‬
‫در یك گراف بدون جهت یك مسیر از راس ‪ U‬به راس ‪ V‬دنباله اي از رئوس مثل ‪Ui1 i2 … ik‬‬
‫‪V‬مي باشد به طوري كه (‪(u,i1),(i1,i2(,….)ik, V‬همگي یال هایي در مجموعه ي )‪E(G‬‬
‫مي باشد ‪.‬‬
‫مسیری از ‪ 0‬تا ‪4‬‬
‫‪0,3,2,1,4‬‬
‫‪0,3,1,4‬‬
‫‪0,4‬‬
‫به عنوان مثال در گراف فوق رئوس ‪0,3,2,1,4‬مسیري را از ‪0‬تا ‪4‬مشخص مي كنند‬
‫(مسیرهاي دیگري نیز مي توان از ‪0‬به ‪4‬پیدا كرد )‬
‫در یك گراف جهت دار نیز مي توان مسیري را تعریف كرد تفاوت آن فقط این است كه مي بایست‬
‫مجموعه ي یال هاي >‪<u,i1>,<i1,i2>,…<ik,v‬همگي در مجموعه ي )‪E(G‬وجود داشته‬
‫باشد‪.‬‬
‫طول مسیر‪:‬‬
‫طول مسیر عبارت است از تعداد یال هاي موجود در آن مسیر‪.‬‬
‫مثال طول مسیر ‪ 0‬تا ‪4‬از مسیر ‪ 0 , 3 , 2 , 1 , 4‬برابر ‪4‬و از مسیر ‪ 0 , 3 , 1 , 4‬برابر ‪ 3‬است‪.‬‬
‫مسیر ساده‪:‬‬
‫مسیري است كه احتماال جز اولین و آخرین راس تمام رئوس متمایز باشد‪.‬‬
‫یك مسیر مي تواند جهت دار یا بدون جهت باشد‪.‬‬
‫‪ : 0 , 1 , 2 , 3 , 5‬مسیر ساده‬
‫‪: 0 , 1 , 2 , 3 , 4 , 1 , 2 , 3 , 5‬مسیر غیر ساده‬
‫سیكل (چرخه)‪:‬‬
‫مسیري ساده است كه راس اول وآ خر آن یكي است ‪.‬به عنوان مثال در این گراف باال )‪ (1,2,3,4‬یك‬
‫سیكل را به وجود آورده است‪( .‬در یك سیكل فقط رئوس اول وآ خر تكراري هستند)‬
‫هم در گراف جهت دار و هم بدون جهت مي توان سیكل را اعمال كرد‪.‬‬
‫در گراف هاي جهت دار معموال به تعاریف فوق كلمه ي جهت دار اضافه مي شود(مثالً مي گویند‬
‫سیكل جهت دار یا مسیر جهت دار) در یك گراف بدون جهت مثل ‪G‬دو راس را همبند گوییم در‬
‫صورتي كه بتوان مسیري از یكي به دیگري پیدا كنیم ‪.‬‬
‫گراف بدون جهت همبند گرافي است كه بتوان بین هر دو راس آن مسیري پیدا كرد به عنوان مثال‬
‫گراف زیر یك گراف غیر همبند است‪.‬‬
‫یك مولفه ي اتصال مانند ‪H‬از یك گراف بدون جهت عبارت است از بزرگترین زیر گراف همبند در آن‬
‫گراف‪ .‬به عنوان مثال در گراف روبرو مولفه اتصال ‪ G2‬میشود چون تعداد عناصر ‪ G2‬از ‪G1‬‬
‫بیشتر است‪.‬‬
‫درخت یك گراف هم بند و بدون چرخه است‪.‬‬
‫گراف كامال همبند‪:‬‬
‫گرافي جهت داراست كه به ازاي هرزوج ‪ u,v‬بتوان مسیري جهت داراز ‪ u‬به ‪v‬واز‪ v‬به ‪ u‬پیدا كرد‪.‬‬
‫درجه گراف بدون جهت‪:‬‬
‫درجه ي یك راس عبارت است ازتعداد یال هاي متالقي روي آن راس درمثال فوق درجه ي راس ‪5=4‬‬
‫و ‪ 0=1‬مي باشد‪.‬‬
‫درجه ي وارده‪:‬‬
‫درجه ي وارده به یك راس در گراف جهت دار عبارت است از تعداد یال هایي كه به آن راس ختم مي‬
‫شود ‪.‬‬
‫راس‬
‫درجه‬
‫درجه‬
‫درجه‬
‫خارجه‬
‫وارده‬
‫‪1‬‬
‫‪2‬‬
‫‪3‬‬
‫‪1‬‬
‫‪0‬‬
‫‪1‬‬
‫‪1‬‬
‫‪0‬‬
‫‪2‬‬
‫‪0‬‬
‫‪2‬‬
‫‪2‬‬
‫‪1‬‬
‫‪1‬‬
‫‪2‬‬
‫‪3‬‬
‫درجه خارجه ‪:‬‬
‫اگر ‪G‬یك گراف بدون جهت با ‪n‬راس باشد كه درجه ي راس ‪I‬ام برابر با‬
‫یك گراف است رابطه ي زیر صحت دارد‪.‬‬
‫نصف حاصل جمع درجه تمام رئوس‬
‫معموال اگر كلمه ي جهت دار گفته نشود منظور یك گراف بدون جهت است‪.‬‬
‫‪ di‬و ‪e‬تعداد یال هاي‬
‫‪e = ) ∑ di (/2‬‬
‫نمایش گراف‪:‬‬
‫‪)1‬ماتریس مجاورتي ‪:‬‬
‫براي یك گراف ‪ G‬با ‪n‬راس ماتریس مجاورتي آرایه اي دو بعدي و ‪n*n‬مي باشد كه آن را ‪A‬مي‬
‫نامیم اگر )‪(i,j‬در گراف بدون جهت یا یال >‪<i,j‬در گراف جهت دار وجود داشته باشد آن گاه‬
‫‪A(i,j)=1‬وگرنه ‪0‬خواهد بود‪.‬‬
‫‪0‬‬
‫‪0‬‬
‫‪0‬‬
‫‪0‬‬
‫‪A[i][j]=0‬‬
‫اگر از ‪ i‬به ‪ j‬یال نداشته باشیم‬
‫اگر از ‪ i‬به ‪ j‬یال نداشته باشیم‬
‫‪A[i][j]=1‬‬
‫‪0‬‬
‫‪0‬‬
‫‪0‬‬
‫‪1‬‬
‫‪1‬‬
‫‪0‬‬
‫‪1‬‬
‫‪0‬‬
‫‪0‬‬
‫‪0‬‬
‫‪1‬‬
‫‪0‬‬
‫توجه ‪ :‬ماتریس مجاورتي گراف هاي بدون جهت روي قطر اصلي متقارن است اما در گراف هاي‬
‫جهت دار ممكن است متقارن نباشد ‪.‬هر سلول از ماتریس مجاورتي مي تواند یك بیت از حافظه را‬
‫اشغال كند در نتیجه براي یك گراف جهت دار ‪ n^2‬بیت الزم است‪.‬‬
‫‪ )2‬لیست مجاورتي ‪:‬‬
‫درا ین روش ‪ n‬سطر ماتریس مجاورتي را به وسیله ي ‪n‬لیست پیوندي نشان مي دهند در واقع‬
‫براي هر راس از گراف ‪G‬یك لیست پیوندي وجود دارد‪.‬‬
‫یال هاي وزن دار‪:‬‬
‫در بسیاري از كاربردها به هر یال عددي نسبت داده مي شود كه وزن هر یال جهت دار نشان دهنده ي‬
‫فاصله ي هر دو راس بوده باشد ‪.‬در چنین گراف هایي ماتریس مجاورتي مي تواند حاوي وزن یال ها‬
‫باشد به عنوان مثال در گراف زیر ماتریس مجاورتي به شكل زیر خواهد بود‪.‬‬
‫∞‬
‫‪15‬‬
‫‪12‬‬
‫‪0‬‬
‫‪14‬‬
‫‪13‬‬
‫‪0‬‬
‫‪12‬‬
‫‪17‬‬
‫‪0‬‬
‫‪13‬‬
‫‪15‬‬
‫‪0‬‬
‫‪17‬‬
‫‪14‬‬
‫∞‬
‫لیست مجاورتي مي تواند براي نمایش گراف هاي وزن دار به كار گرفته شود كافي است به هر گره‬
‫در لیست پیوندي فیلدي جهت وزن آن اضافه كنیم‪.‬‬
‫شبكه ‪ :‬گرافي است كه یال هاي آن وزن داشته باشد‪.‬‬
‫نكته‪ :‬درجه هر رأس در یك گراف بدون جهت برابر است با تعداد گره هاي مربوط به آن رأس در لیست‬
‫مجاورتي مربوط به آن‪ .‬واضح است كه تعداد گره هاي موجود در كل لیست مجاورتي برابر است با‬
‫‪ 2‬برابر تعداد یال ها ‪.‬‬
‫نكته‪ :‬در یك گراف جهت دار تعداد كل گره هاي لیست مجاورتي برابر با تعداد یال هاي گراف مي باشد‪.‬‬
‫نكته‪ :‬در گراف هاي جهت داري كه بررسي كردیم لیست مجاورتي گره هایي را نشان مي داد كه مجاور‬
‫از گره موردنظر ما بودند‪.‬‬
‫‪5‬‬
‫‪1‬‬
‫‪2‬‬
‫‪3‬‬
‫‪4‬‬
‫لیست مجاورتي معكوس‪:‬‬
‫در برخي از موارد مي خواهیم رئوس مجاور به رأس موردنظرمان را مشخص كنیم ‪ .‬درچنین مواردي‬
‫از لیست مجاورتي معكوس استفاده مي شود ‪ .‬در لیست مجاورتي معكوس همانطور كه گفته شد به‬
‫ازاي هر رأس رئوس مجاور به آن در لیست پیوندي قرار مي گیرد‪.‬‬
‫با توجه به گراف فوق ‪ ،‬لیست مجاورتي معكوس را ایجاد كرده ایم‪:‬‬
‫پیمایش گراف ‪:‬‬
‫همانند درخت ها مي توان گراف ها را نیز پیمایش كرد‪ .‬پیمایش یك درخت به ‪ 2‬شكل انجام پذیراست ‪.‬‬
‫این ‪ 2‬روش عبارتند از ‪:‬‬
‫‪ -1‬روش جستجوي عمقي )‪(DFS‬‬
‫‪ -2‬روش جستجوي سطحي )‪(BFS‬‬
‫در هر ‪ 2‬روش با یك رأس كار را آغاز مي كنیم و به ترتیبي كه خواهیم گفت پیشروي خواهیم كرد‪.‬‬
‫توجه ‪ :‬اگرچه این ‪ 2‬روش درگراف هاي جهت دار امكانپذیر است ما آن را در گراف هاي بدون جهت‬
‫شرح مي دهیم ‪.‬‬
‫روش جستجوي عمقي )‪: (DFS‬‬
‫در این روش با رأس ‪ B‬كا را آغاز مي كنیم یعني رأس ‪ B‬را مالقات مي كنیم سپس رأسي مانند ‪ W‬را‬
‫پیدا مي كنیم كه با رأس ‪ B‬مجاور است و قبالً مشاهده نشده ‪ .‬این كار براي رأس ‪ W‬نیز تكرار مي‬
‫شود و آنقدر اعمال فوق را تكرار مي كنیم كه تمام رئوس مجاور به دورترین گره از ‪ B‬مالقات شده‬
‫باشد‪ .‬اگر رأسي براي مالقات مانده باشد به عقب برگشته واین عمل را براي آن نیز تكرار مي كنیم‪.‬‬
‫به مثال زیر توجه كنید‪:‬‬
‫‪0‬‬
‫‪2‬‬
‫‪6‬‬
‫‪1‬‬
‫‪4‬‬
‫‪5‬‬
‫‪3‬‬
‫‪7‬‬
‫فرض كنید مي خواهیم پیمایش ‪ DFS‬را از گره صفر آغاز كنیم‪.‬‬
‫‪0,1,3,7,4,5,2,6‬‬
‫براي این كار اگر رأس )‪ (u,v‬را درنظر بگیرید یكي از پیمایش ها را روي رأس ‪ u‬انجام دهید اگر رأس‬
‫‪ v‬نیز در آن پیمایش موجود باشد این ‪ 2‬رأس در یك مؤلفه همبند قرار دارند وگرنه خیر‪.‬‬
‫‪1‬‬
‫‪2‬‬
‫‪4‬‬
‫‪3‬‬
‫‪5‬‬
‫‪7‬‬
‫‪6‬‬
‫درخت پوشا‪:‬‬
‫یك گراف را درنظر بگیرید ‪ .‬فرض كنید این گراف بدون جهت بوده و همبند است‪ .‬درخت پوشا در یك‬
‫گراف درختي است كه تمام رئوس را پوشانده باشد‪(.‬توجه داشته باشید كه درخت خود یك گراف‬
‫همبند است با این شرط كه سیكل یا دوره نداشته باشد‪).‬‬
‫اگر یك گراف شامل ‪ n‬رأس باشد درخت پوشا آن دقیقا ً )‪ (n-1‬یال خواهد داشت‪.‬‬
‫نكته‪ :‬با استفاده از جستجوي عمقي یا سطحي مي توان درخت پوشا را بدست آورد‪.‬‬
‫‪0‬‬
‫‪2‬‬
‫‪ : 0 , 1 , 3 , 7 , 4 , 5 , 2 , 6‬پیمایش ‪DFS‬‬
‫‪ : 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7‬پیمایش ‪BFS‬‬
‫‪6‬‬
‫‪1‬‬
‫‪4‬‬
‫‪5‬‬
‫‪3‬‬
‫‪7‬‬
‫با توجه به شكل فوق كافي است یال مرتبط با هر رأس جدیدي كه از طرف قبلي مشاهده مي شود را به‬
‫درخت اضافه كنید‪.‬‬
‫مولفه های دو اتصالی)دو طرفه(‪:‬‬
‫به رئوسی از گراف که با حذف آنها و یالهای منتهی به آنها دو زیر گراف مجزا )یا بیشتر( پدید می‬
‫آید رأس محوری گویند ‪ .‬به عنوان مثال گراف زیر را در نظر بگیرید‪:‬‬
‫‪0‬‬
‫‪8‬‬
‫‪9‬‬
‫‪1‬‬
‫‪7‬‬
‫‪5‬‬
‫‪6‬‬
‫‪2‬‬
‫‪3‬‬
‫‪4‬‬
‫در گراف فوق رئوس شماره ‪ 7,5,3,1‬رئوس محوری‬
‫می باشد‪.‬‬
‫گراف دو اتصالی ‪،‬گراف همبندی است که نقطه محوری نداشته باشد‪.‬‬
‫درخت پوشای کمینه یا با کمترین هزینه )‪:(minimum spaning tree‬‬
‫یک گراف بدون جهت وزن دار را در نظر بگیرید از بین درختان پوشایی که می توان برای چنین‬
‫گرافی در نظر گرفت می توان درخت یا درختانی را پیدا کرد که مجموع وزن یالهای آن‬
‫درختان پوشا ‪ minimum‬باشد‪.‬‬
‫برای پیدا کردن درخت پوشای کمینه سه الگوریتم مختلف وجود دارد ‪:‬‬
‫‪-1‬الگوریتم راشال(کروسکال ‪:)kruskal‬‬
‫در این الگوریتم ابتدا تمامی رئوس گراف را جدای از هم در نظر می گیریم (در واقع اگر گراف شامل‬
‫‪n‬رأس باشد ‪n‬مجموعه تک عنصری خواهیم داشت‪ ).‬سپس یالها را به ترتیب صعودی مرتب می‬
‫کنیم‪.‬حال تا زمانی که )‪ (n-1‬یال از بین مجموعه یالها انتخاب نشده است (و در درخت قرار‬
‫نگرفته) اعمال زیر را تکرار کنید ‪:‬‬
‫‪: 10 12 14 16 18 22 24 25 28‬مجموع وزن یالها‬
‫})‪ (n-1): E(T)={(0,5),(2,3),(1,6),(1,2),(4,3),(4,5‬یال‬
‫‪T‬‬
‫یال با وزن کمینه را از مجموعه یالها بردارید بررسی کنید که آیا اضافه شدن این یال به درخت‬
‫پوشا مجاز است یا نه ‪(.‬در صورتی که سیکل ایجاد کند مجاز نخواهد بود‪).‬‬
‫در صورت مجاز بودن یال ‪،‬آن را به درخت اضافه کنید وگرنه آن را کنار بگذارید‪.‬‬
‫‪-2‬الگوریتم پرچم‪:‬‬
‫در این الگوریتم یکی از رئوس گراف را به عنوان رأس شروع در نظر میگیرد نزدیک ترین رأس‬
‫به آن را پیدا می کند ‪.‬آن رأس به همراه یالی که آن را به رأس شروع وصل می کندبه ساختار‬
‫درخت اضافه می گردد (در این حالت درخت به وجود آمده شامل ‪2‬رأس خواهد بود‪ ).‬سپس‬
‫نزدیک ترین رأس به درخت حاصل را پیدا می کندآن را به همراه یال مربوطه به درخت اضافه‬
‫می کند‪.‬اعمال فوق آنقدر تکرار می شود تا اینکه تمام رئوس دیگر نیز به درخت اضافه شده‬
‫باشد‪(.‬در شکل ‪ 1‬رأس شروع گره ‪ 6‬می باشد)‬
‫‪2‬‬
‫‪1‬‬
‫نکته‪ :‬یک گراف ممکن است بیش از یک درخت پوشای کمینه داشته باشد ‪ .‬اگر گرافی چند درخت‬
‫پوشای کمینه داشته باشد می بایست وزن مجموع یالها در تمام درختان پوشای کمینه برابر بوده‬
‫باشد‪.‬‬
‫نکته‪ :‬الگوریتم راشال و پرچم تضمین می کند که در هر گراف دلخواه (بدون جهت ‪،‬همبند) درخت‬
‫پوشای کمینه را به دست می آورد ‪.‬‬
‫‪-3‬الگوریتم سولین‪:‬‬
‫در این الگوریتم ابتدا گره ها به شکل مجزای از هم در نظر گرفته می شود سپس به هر گره یال با‬
‫کمترین وزن متالقی روی آن انتخاب می شود در این صورت چند درخت در گراف پدید می آید ‪.‬‬
‫بین هر دو درخت مجزا یالی انتخاب می شود که وزن آن کمینه بوده وبتواند دو درخت را به هم‬
‫وصل کند این کار تا رسیدن به یک درخت واحد تکرار می شود ‪(.‬در شکل ‪1‬رأس شروع گره‬
‫‪0‬میباشد)‬
‫‪2‬‬
‫‪1‬‬
‫نکته‪ :‬الگوریتم فوق نیز تضمین می کند که درخت پوشای کمینه را تولید کند‪.‬‬
‫نکته‪:‬اگر گراف بیش از یک درخت پوشای کمینه داشته باشد ممکن است هر الگوریتم به شیوه‬
‫خود به یکی از آنها برسد ‪.‬‬
‫نکته های فراموش شده‪:‬‬
‫پیمایش ترتیب سطحی درختان دودویی(پیمایش سطح – ترتیب)‪:‬‬
‫یکی از ساده ترین پیمایش ها ‪ ،‬پیمایش ترتیب سطحی است ‪.‬کافی است از ریشه (سطح اول)‬
‫شروع کنید آن را مالقات کنید و سپس فرزندان ریشه را (سطح بعدی) از چپ به راست‬
‫مالقات کنید سپس در سطح بعدی و همین طور تا آخر‪.‬‬
‫برای انجام چنین پیمایشی میتوان از یک صف کمک گرفت ‪.‬بدین منظور ریشه را در ابتدای صف‬
‫قرار دهیدسپس آن را از صف حذف کرده(چاپ کنید) فرزندان آن را به ترتیب از چپ به راست‬
‫در صف قرار دهید به ازای هر فرزند می بایست ابتدا آن را حذف کرده (چاپ کنید ) و‬
‫فرزندان آن را از چپ به راست به انتهای صف اضافه کنید این کار تا اضافه شدن تمام گره ها‬
‫‪A‬‬
‫به صف و حذف تمام آن ها از صف تکرار می شود‪.‬‬
‫‪C‬‬
‫‪A B C D E F G H‬‬
‫‪B‬‬
‫‪F‬‬
‫‪E‬‬
‫‪H‬‬
‫‪D‬‬
‫‪G‬‬
‫پایان‬