Data Structure in C
Data Structure in C
توجه داريم كلمه Queueمجموعه تمام صف هاي است كه در اين فروشگاه وجود دارد و queueيك
صف به خصوص مثالً صف لوازم التحرير است .
ً
همين طور Itemمجموعه تمام مشتريان صف است و itemيك فرد به خصوص مثال آقاي احمدي است.
قوانين
قوانيني كه بر ساختمان داده صف حكمفرماست عبارتند Vاز:
.1از صف خالي نمي توان فردي حذف كرد.
.2به صفي كه پرشده نمي توان فردي اضافه كرد.
.3همواره اولين نفر از صف خارج مي شود.
.4همواره فرد جديد به انتهاي صف اضافه مي شود.
تذكر :ممكن است توابع ديگري نيز به اين ساختمان داده اضافه كنيم مثالً تابع Mergeبراي ادغVVام دو صVVف
در يكديگر يا تابع Splitبراي شكاف يك صف به دو صف كوتاهتر و براي اين توابVVع نVVيز مي تVVوانيم قVVانون
تعيين كنيم .
مقايسه الگوريتمها:
اما نكته مهمتر :هنگام مقايسه الگوريتم ها بررسي سرعت آنهاست ،بديهي است هرچه تعداد دستور العمل ها
در يك الگوريتم كمتر باشد آن الگوريتم سريع تVVر اسVVت . .بنVVابراين ابVVزاري نيVVازي داريم تVVا شVVمار يVVا تعVVداد
دستور العمل ها را تعيين كند که به اين ابزار اصطالحا ً تابع Oاطالق مي کنيم .
1
تعريف دقيق و رياضي تابع Oبه صورت زير است :
n
K miL
K n
np
نمادي كه براي مرتبه به كار مي رود به شکل زير است :
n O n p
4n 3 5
را تعيين VكنيدV. n {
n 3
مثال :مرتبه دنباله
4n 3 5
n n 3 4n 3 5
miL n
miL
n
miL n p 1
n p n p
n 3n p
P+1=3 P=2
4n 3 _ 5
O (n 2,) K 4
n 3
مثال كنكور
زمان اجرا يا شمار قطعه برنامه زير را تعيين كنيدV.
; X=0
) For ( i=1 ; i <= n ; i++
) For ( j=1 ; j <= n ; j++
{
;X= X +1
;Y = Z*X
;Z=Y-X
}
2
n n 1 2n 1
n
1
i1
i2
6
O n3 K
,
3
n
n (n 1 )
2 2
1
i1 i 3 4 O (n 4 ) K, 4
.
.
n
1
i1
im O n m 1 K,
m 1
مثال سوال امتحان
For ( i=1 ; i <= n ; i++ )
For ( j=1 ; j <= i ; j++ )
For ( k=1 ; k <= i * j ; k++)
X++;
3
ساختمان دادة آرايه ها Structure Array is
مجموعه اي از زوج ها كه براي هر مقدار انديس يك مقدار از مجموعه عناصر( ) itemدر نظVVر گرفتVVه :
Objectsمي شود .انديس مجموعه متناهي مرتب از يك بعVVد يVVا بيشVتر مثالً يVVك مجموعVVه انVVديس يVك بعVVدي
است {}n,…,1,2و يك مجموعه انديس دو بعدي است)2,2(,)2,1(,)1,2(,)1,1({{.
Functionsتوابع
تابع Createخروجي آرايه
يك آرايه jبعدي اعالن مي كند برد بعد iتوسط عنصر iام ليست داده شVVده اسVVت ضVVمنا ً عناصVVر آرايVVه از
جنس يا نوع itemهستند j .و listو itemمهماند.
; ] int a [ 10
تابع Retrieve
اگر iيك انديس از مجموعه Aباشد در اين صورت عنصVر متنVVاظر بVا آن انVديس iدر آرايVVه AبرگردانVده
مي شود درغير اين صورت خطا.
ورودي (يك آرايه Aو انديس iو ) item x تابع Store
= store (A , i , x) : Array: :
اگر iدر مجموعه انديس هاي Aباشد در اين صورت آرايه Aزوج جديد(( i , xاضافه مي گردد يا درج
مي شود و حاصل كه يك آرايه جديد است برگردانده مي شود ،در غير اين صورت Errorمي دهدV.
يك چند جمله اي درجه nداراي شكل كلي زير است:
n
A(X)= 3x 5 x 2 x 4
7 3
) A(Xيك چند جمله اي درجه 7مي باشد ،در واقع چند جمله اي ) A(xرا مي توان به صورت زير نمايش
داد:
) 3 x 7 0 x 60 x 5 0 x 4 ( 5 )x 3 0 x 2 2 x ( 4
يك راه مناسب
يك راه مناسب براي نمايش اين چند جمله اي استفاده از آرايه است ،مي توانيم آرايه 8عنصري تعريف
كنيم و ضرايب چند جمله اي ) A(xرا در آن آرايه قرار دهيم .با اين حساب چند جملVVه اي ) A(xدر آرايVVه a
به صورت زير ذخيره مي شود:
a
0 0 3 0 0 0 5- 0 2 4-
براي
يافتن مجموع
اگر بخواهيم ) A(xرا با يك چند جمله اي ديگر مانند )B(xجمع كنيم بايد ) B(xرا در يك آرايه 10عنصري
به نام bبه صورت =B(x) X 9 2X 7 5X 3 X 2زير ذخيره كنيم :
1 0 2- 0 0 0 5 1 0 0
b
سپس براي يافتن مجموع ) A(x)+ B(xبايد ابتدا دو خانه صفر در سمت چپ آرايه aقVرار دهيم تVا دو چنVVد
جمله اي هم درجه شود .سپس با استفاده از قطعه برنامه زير مي توانيم حاصل دو چند جمله اي زير را داخل
آرايه قرار دهيم:
)FOR ( i = 0 ; i <= 9 ; i++
4
;]C[i] = a[i] + b[i
تذكر:
در حVVالت كلي اگVVر ) A(xدرجVVه mو ) B(xدرجVVه nباشVVد ،زمVVان اجVVراي الگVVوريتم فVVوق بVVه صVVورت
)) O (max(m,nخواهد بود.
روش قبل اولين روشي است كه به ذهن مي رسد اما كارايي چنداني ندارد ،مثالً فرض كنيVVد بخVVواهيم دو چنVVد
=P(x)20001و =Q(x) x 2 3را با هم جمع كنيم .x جمله اي 5
اوالً براي ذخيره سازي ) P(xبه آرايه اي به طول 1001نياز داريم كه 999خانه آن صVVفر اسVVت ضVVمنا ً
براي جمع ) Q(xو ) P(xبايد سمت چپ Q(x) 998صفر قVرار دهيم تVا هم درجVVه شVود ،بVVا توجVه بVه اين
مشكالت اين روش نه از لحاظ حافظه مطلوب است و نه از لحاظ سرعت اجرا ،زيرا عمالً بايVVد از حلقVVه اي
به طول 1001جهت جمع چند جمله اي استفاده كنيم ،به همين خاطر همVVانطور كVVه در رياضVVيات از نوشVVتن
جمالت با ضريب صفر خودداري مي كنيم ،در جبر چند جمله اي ها نVVيز جمالت صVVفر را ذخVVيره نمي كVVنيم.
اگر بخواهيم تنها جمالت غير صفر را ذخيره كنيم همراه با ضريب( ، )Coeficientبايد حتما ً توان يا نمVVا [
]Exponetرا نيز ذخيره كنيم.
Coef
Exp
به همين خاطر هر جمله يك چند جمله اي يك ساختار دو عنصري خواهد بود چنين سVVاختاري را در زبVVان C
مي توانيم هنگام تعريف نوع داده ( )Typedefتعريف كنيم ،در واقع هر جملVVه ( )TermيVVك چنVVد جملVVه اي
ساختار زير را دارد:
{ Typedef struct
; float coef
; int expon
; } term
براي تعريف يك چند جمله اي مي توانيم در قسVمت متغيرهVا ( )VARچنVد جملVه اي termsرا بVه صVورت
زير تعريف كنيم:
; ]VAR term terms [1000
براي ذخيره ساختن مقدار در اين ساختمان داده (همان تابع ) StoreبVا اسVVتفاده از عملگVVر( )dotتوسVVط
نقطه ( )0مقداردهي را انجام مي دهيم .مثالً اگر بخواهيم جمله اول termsرا مقVدار دهيم در قسVمت coet
عدد 2و در قسمت expعدد 1000را قرار مي دهيم.
Start A finishA start B finish B free
0 1 2 3 4 999
Coef 2 5 1 3-
exp 1000 0 2 0
;Term[1].Coef = 2
;Term[1].exp=1000
تمام جمالت چند جمله اي هاي ) A(xو ) B(xرا مي توانيم به صورت زير در آرايه عمومي terms
قرار دهيم .براي اين منظور بايد خانه شروع چند جمله اي ( a) Start Aو پايان چند جمله اي ()finishA
،aهمچنين شروع و پايان چند جمله اي ) B(xتعيين شود ضمنا ً اولين خانه خالي چند جمله اي termsبايVVد
با يك متغير سراسري به نام Freeمشخص باشد.
5
مي توان جمله اي را كه aبه آن اشاره ميكند با قسمت توان جمله اي را كه bبVVه آن اشVVاره مي كنVVد مقايسVVه
ميكنيم ( اين مقايسه توسط دستور )Compare (terms(a) . exp ) , terms (b) . expانجام
ميشود).
سه حالت ممكن است رخ دهد:
الف) terms (a) . exp > terms (b) . exp
در اين حالت جمله چند جملVVه اي ) A(xتVVواني بزرگVVتر از چنVVد جملVVه اي ) B(xدارد پس بايVVد عينVا ً آن جملVVه
) A(xرا در چند جمله اي حاصل جمع كه آن را ) C(xمي ناميم بنويسVVيم (عمVVل نوشVVتن جملVVه جديVVد در چنVVد
جمله اي ) C(xتوسط زير برنامه Next TermانجVVام مي شVVود) در نهVVايت پس از نوشVVتن جملVVه ) A(xدر
) C(xيك واحد به aاضافه مي كنيم زيرا تكليف آن جمله مشخص شود.
ب)
حالت مساوي terms(s) . exp = terms(b) . exp
در اين حالت جمله هVاي ) A(xو ) B(xتVوان مسVاوي دارنVد سVپس بايVد ضVرايب آنهVا بVا هم جمVع شVود اگVر
مجموع ضرايب مخالف صفر بودآنگاه حاصل جمع را به همراه يكي از توان ها در چنVVد جملVVه اي ) C(xمي
نويسيم ،اما اگر مجموع ضرايب صفر شد در ) C(xچيزي نمي نويسيم ،در نهايت چه مجموع ضرايب صVVفر
باشد و چه غير صفر يك واحد به aاضافه مي كنيم و يك واحد هم به .b
ج) terms(a) . exp < terms(b) . exp
در اين حالت چون كه توان جمله چند جمله اي ) B(xبزرگتر است آن جمله ) B(xرا در ) C(xمي نويسيم و
سپس bرا يك واحد پيش مي بريم.
عمليات فوق را آنقدر ادامه مي دهيم تا يكي از چنVVد جملVVه اي هVVاي ) A(xتمVVام شVVود A(x) ،زمVVاني تمVVام مي
شود كه a>finish Aباشد به همين ترتيب ) B(xزماني تمام مي شود كه b> finish Bشود هنگامي كVVه
يكي از چند جمله اي ها تمام شد عينا ً جمالت چند جملVVه اي ديگVVر را در ) C(xمي نويسVVيم .در نهVVايت بVVراي
آنكه پايان چند جمله اي ) C(xمشخص شود Finish C = free- 1قرار مي دهيم .
6
For (; starta <= finisha ; starta++)
Attach (terms [starta] .coef , terms [starta] . expon) ;
/* add in remaining terms of B (x) */
For ( ; startb <= finishb ; startb++)
Attach (terms [startb] . coef , terms [startb] . expon) ;
*finishd = avail-1 ;
}
. را بدست مي آوردC را جمع مي كند وb وa )2
.) متغيرها را معرفي مي كند3
)خط مقداردهي آغازين5
. تمام نشدهB(x) وA(x) ) هنوز6
. مي گذاريمt ) مجموع ضرايب در9
. صدا زده مي شودAttach ) پروسيجر10
efoc
pxe / C دو متغير ورودي مي گيردNew term
term طول آرايهMax term
. را بنويسA(x) ) جمالت باقيمانده از22
finish A را مي نويسد تا زماني كه برسد بهa جمالت27 ) تا23
. برسدfinish B را مي نويسد تا زماني كه بهb جمالت33 ) تا29
V. را مشخص مي كندC ) پايان34
تابعي براي اضافه نمودن يک جمله جديد
void attach (float coefficient , int exponent )
{
/* add a new term to the polynomial */
if (avail >= MAX_TERMS)
{
fprintf (stderr , "too many terms in the polynomial \n") ;
exit (1) ;
}
Terms [avail] . coef = coefficient ;
Terms [avail++] .expon = exponent ;
}
Start finish start finish free f f f finish free
A A B B C
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
16
ضريب2 4 6- 2 1 1- 4- 1 1 1 1 6- 2
Term
توان7 5 1 0 9 7 5 3 9 7 3 1 0
x 9 x 7 x 3 6 x 2
A(x)= 2x 7 4 x 5 6 x 2
c (x ) x 9 x 7 x 3 6 x 2
B(x)= x 9 x 7 4 x 5 x 3
: Bubble Sort روش مرتب سازي حبابي
سپس، بزرگترين عنصر را به سمت انتهاي آرايه هل مي دهيمn در اين روش ابتدا در آرايه اي به طول
)n-2( ولVVه طVVه اي بVV در آرايVدV رار بعVV در تك، نيمVVرار مي كVVار را تكVV) همين كn-1( ولVVه طVVدر آرايهاي ب
هVVمت خانVVه سVVتر را بVVر بزرگVV عنص2 ولVVاين كار را مي كنيم و مرتبا ً آن را تكرار كرده تا در آرايه اي به ط
7
دوم هل مي دهيم ،سپس يك حلقه با متغير iنياز داريم كه از nتVا ، 2يكي يكي كم مي شVود و يVك حلقVه بVا
متغير Jنياز داريم كه از 1تا ( )i-1يكي يكي اضافه ميشود.
قطعه برنامه زير عمل مرتب سازي حبابي را انجام مي دهد:
) For ( i = 1 ; i < n ; i++
) For ( j = 1 ; j < n - i ; j++ an
]if a [ j] > a [ j+1 an-1
{ a3
;]Temp = a [ j a2
;]a [ j] = a [ j+1
; a [ j+1 ] = temp a1
}
همانطور كه مشاهده مي شود در اين ماتريس نزديك به 80درصد عناصر ص44فر هس44تند بن44ابراين ب44ه نظ44ر مي
رسد كه عناصر صفر را ذخيره نكنيم و تنها عناصر غير صفر را ذخيره كنيم ،سپس باي44د عالوه ب44ر مق44دار ي44ك
عنصر صفر حتما ً محل آن يعني سطر و ستون را نيز ذخيره كنيم پس براي هر عنصر غير صفر باي44د ي44ك س44ه
تايي به صورت زير در نظر بگيريم .
Row column Value
8
با اين حساب ماتريس اسپارس Aدر مثال قبل مي تواند به سطر ستون مقدار
صورت زير ذخيره شود:
براي آن كه اين ساختار سه قسVVمتي را در زبVVان CتعريVVف كVVنيم بايVVد در قسVVمت نVVوع داده( ) TypedefبVVا
استفاده از دستور العمل ركورد StructنVوع داده يVك ركVورد Matrix termرا بVه صVورت زيVر تعريVف
كنيم:
و در نهVVايت در قسVVمت متغيرهVVا( )varمي تVVوانيم مVVاتريس اسVVپارس CAرا يVVك آرايVVه از جنس مVVاتريس
Termتعريف كنيم:
Var ; ] Matrixterm ca [ max-terms
تذكر :براي آنكه ابعاد ماتريس Aدر نظر گرفته شود خانه صفرم Caرا براي اين منظور در نظر گرفتيم ،
در خانه صفرم Caبه ترتيب تعداد سطرها .تعداد ستون ها و تعداد عناصر غVVير صVVفر مVVاتريس Aرا قVVرار
مي دهيم ،پس عمالً Caبه صورت زير در نظر گرفته مي شود:
تعداد Vعناصرغير صفر تعداد ستون تعداد Vسطر
تذكر مهم :همانطور كVVه در تعريVVف CaمشVVخص شVVده آرايVVه CaيVVك بعVVدي اسVVت يعVVني بVVه صVVورت زيVVر
ميباشد:
9
خانه صفرم خانه يكم خانه دوم خانه هشتم
6 7 8 1 5 3 2 1 2 6 4 2
براي ماتريس هاي معمولي قطعه برنامه ساده زير عمل ترانهاده را انجام ميدهد:
زمان اجراي اين الگوريتم ) O(mnاست (به تعداد Vدرايه هاي ماتريس ) A
حال ببينيم براي پيدا كردن ترانهاده يك ماتريس اسVVپارس كVVه بVVه صVVورت فشVVرده ذخVVيره شVVده اسVVت
چگونه مي توان عمل كرد:
ماتريس مثال قبل را در نظرمي گيريم :
0 0 0 0 3 0 0 6 7 8
2 0 0 0 0 0 0 CA: 1 5 3
0 0 0 0 0 0 0 2 1 -
A فشرده 2
4 0 0 0 1 0 0
0 0 0 0 2 7 0 4 1 4
4 5 -
0 3 0 2 0 0 0
1
5 2 3
5 5 2
5 6 7
6 4 6
به نظر ميرسد براي پيدا كردن ترانهاده Aاز روي شكل فشرده آن يعني CAسVVاده تVVرين راه آن اسVVت كVVه
جاي ستونهاي اول و دوم CAرا عوض كنيم با اين كار عمالً جاي س4طر و س4تون عناص4ر غيرص4فر ع4وض
مي شود و داريم:
6 7 8 0 2 0 4 0 0
)(CA 0 3 0
5 1 3 0 0 0
T
: 1 2 2- 0 0 0 0 0 0
1 4 4A 0 0 0 0 0 2
T
5 4 1- 3 0 0 1 2 0
2 5 3
0 0 0 0 7 0
5 5 2 0
0 0 0 0 0 7 6
6 5 7
4 6 2
AشVVكل فشVVرده آن را بنويسVVيم در T
اما اگر ابتدا ماتريس Aرا ترانهاده كنيم ،سپس از روي مVVاتريس ترانهVVاده يعVVني
نهايت CAبه صورت زير بدست مي آيد:T
10
6 7 8
CAT: 1 2 2-
1 4 4
2 5 3
4 6 2
5 1 3
5 4 1-
5 5 2
همانطور كه مشاهده مي شود شكل هاي ( T)CAو CATباهم يكي نيسVVتند ، Vدر شVVكل فشVVرده مVVاتريس اسVVپارس عناصVVر
غير صفر به ترتيب شماره سطر مرتب شده اند ،ضمنا ً در آن هايي كه شماره سطر يكسان دارند براساس شماره ستون
مرتب شده اند ،مي بيVنيم ( T)CAچVVنين خاصVVيتي نVVدارد ،اولين ايVده اي كVه بVه ذهن مي رسVVد آن اسVت كVه در ( A ) t
C
عناصر را مرتب كنيم ،اگر ماتريس Aو tعنصر غير صفر داشته باشد ،زمان مورد نياز بVVراي تعVVويض سVVتون اول
O ( tخواهد بود سپس براي مرتب كردن اگر از يك روش مرتب سازي معمVVولي ماننVVد و دوم ماتريس فشردة ) C A
2
مرتب سازي حبابي استفاده كنيم زمان مورد نياز براي آن نيز ) O ( tخواهد بود و در نهايت زمان اين روش :
) O t t 2 O ( t 2
O t t 2
: tبراي جابجايي ستون هاي اول و دوم CA
: t2براي مرتب كردن
اگر ماتريس Aيك ماتريس m×nباشد در بدترين Vحالت mn = tعنصر غير صفر دارد و در اينجا زمان مورد نياز
O mخواهد بود كه بسيار بدتر از الگوريتم ترانهاده معمولي است كه زمان آن
Onmبود. الگوريتم ) ( 2n 2
11
; b [currentb] . row = a[ j] .col
; b [cuurentb] .col = a [ j] . row
; b [currentb] . value = a[ j] .value
;cuurentb++
}
}
}
b )2برابر با ترانهاده aقرار داده مي شود .
terms )3همVVان تعVVداد عناصVVر غVVير صVVفر C ،تعVVداد سVVتون هVVاي مVVاتريس A ، iيVVك متغVVير و شVVمارنده ،
روي خانههاي Bحركت كند . BtnerruCجاري ،در جريان B
5تا )8مقدار دهي آغازين Initial
terms= b[0] . value)6
)9شرط :اگر ماتريس ،ماتريس صفر باشد terms = 0 :برنامه كارش تمام شده است
زمان اجراي الگوريتم ترانهاده معمولي برابر ) O(ntاست كه در آن nتعداد ستون هاي ماتريسي Aاست و t
تعداد عناصر غير صفر Aمي باشد.
(
O nt ) Onmبدترين حالت 2
7 6 8
1 2 -2
1 4 4
2 5 3
4 6 2
5 1 3
5 4 -1
5 5 2
6 5 7
12
نقش كليدي را در الگوريتم ترانهاده سريع آرايه Row startبرعهده دارد زيرا در واقع مكان شروع را در
ماتريس ترانهاده مشخص مي كند ،بVVا اسVVتفاده از اين آرايVVه مي تVVوانيم تمVVام عناصVVر غVVير صVفر Aرا بVVه B
منتقل كنيم .
ترانهاده سريع يک ماتريس اسپارس
) ] [ Void fast_transpose (term a [ ] , term b
{
/* the transpose of a is placed in b */
; ]int row_terms [MAX_COL] , starting_pos [MAX_COL
; int i , j , num_cols = a[0] . col , num_terms = a [0] . value
; b [0] . row = num_cols ; b[0] . col = a[0] . row
; b [0] .value = num_terms
if (num_terms > 0 ) { /* nonzero matrix */
)for (i = 0 ; i < num_cols ; i++
; row_terms [i] = 0
)for ( i = 1 ; i <= num_terms ; i++
; row_terms [a [i] .col ] ++
; starting_pos [0] = 1
)for (i = 1 ; i< num_cols ; i++
; ]starting_pos [i] = starting_pos [ i-1] + row_terms [ i-1
)for (i = 1 ; i <= num_terms ; i++
{
; j = starting_pos [ a [i] .col ] ++
; b [ j] . row = a [i] .col ; b[ j] . col = a [i] .row
; b [ j] .value = a[i] . value
}
}
}
)1يك متغير aاز جنس اسپارس و bهم همين طور.
)2ترانهاده aدر bقرار داده مي شود ضمنا ً زمان اجرا( (Ot nاست كه tتعداد عناصر غير صفر
و nتعداد Vستون ها مي باشد.
)3تعريف دو آرايه
6و )7مقداردهي آغازين
terms )8كار تمام
)10مقدار ) Rowsiza ( iرا كه برابر تعداد عناصر در سطر iام bمي باشد محاسبه مي كند .
)11همه را صفر قرار مي دهد و مقدار دهي آغازين
)12محاسبات انجام مي دهدV.
) Row size (a [ i] . Col
عدد 2
خانه2
)13توضيح) Row start ( iرا كه مكان شروع سطر iام در ماتريس ترانهاده مي باشد مشخص
مي كند (خط 14و )15
16تا )23انتقال از ماتريس اصلي aبه ماتريس ترانهاده b
)22حتما ً يكي افزايش پيدا مي كند چون اعداد بعدي را روي اين ننويسدV.
زمان اجرا ) O (n +t ) O ( n + t + n + t
زمان الزم براي اجراي الگوريتم ترانهاده سريع برابر ) O (n + tمي باشد زيرا :
O nبراي انتقال از aبه t n t b
13
CA 6 7 8 Rowsize 0 0 0 0 0 0 0 2 1 0 1 3 1 0
(1 1 5 3 1 1 1 1 1
) 2 1 2- ()2 2 2
(
)3
نمايش آرايهها:
همان طور كه قبالً اشاره شده كه هر آرايه به تعدادي خانه هم جنس و متوالي در حافظه است كه همگي
يك اسم داشته باشند در زبانهاي سطح باال نظير پاسكال يVVا CبVVراي رسVVيدن بVVه يVVك خانVVه بVVه خصVVوص در
آرايهها كافي است از انديس آن خانه استفاده كنيم اما در زبان سطح پايين نظير اسمبلي از آرايه ها فقط آدرس
اولين خانه را داريم و براي آنكه به يك خانه به خصوص دسترسي پيدا كنيم بايد حتما ً در خانه هاي حافظVVه بVVا
استفاده از آدرس خانه اول پيش برويم تا به خانه مورد نظر برسيم يVVك آرايVVه nبعVVدي در زبVVان Cدر حVVالت
n
in
كلي به شكل زير مي باشد .تعداد عناصر چنين آرايه اي برابر است با ( iL 1 ) :
i1
] a [ L1 . . . n1 , L2 . . . n2 , . . . , Ln . . . nn
در حالت خاص اگر محدوده پايين تمام ابعاد را( ) Liبرابر يك در نظر بگيريم ))Li = 1در اين صورت
تعداد عناصر آرايVVه حاصلضVVرب n nتVVا n 1خواهVVد بVVود در ادامVVه سVVعي ميكVVنيم آدرس يVVك خانVVه بVVه
خصوص از آرايه را در مورد آرايه هاي يك بعدي و دو بعدي و سه بعدي تعيين كنيم.
14
شكل كلي اين آرايه ها به صورت] a [ iمي باشد ،اگر آدرس اولين خانه آرايه برابر باشد ،براي
پيداكردن آدرس خانه iام بايد( )i –1خانه پيش برويم و اگر فرض كنيم هرخانه آرايه بVVه طVVول dبVVايت
باشد آنگاه آدرس aiبه صورت زير به دست مي آيد :
= diآدرس
ai
در سطر iام براي رسيدن به عنصر jام مشابه آرايه هاي يك بعدي بايد از ( ) j – 1عنصر عبور كنيم ،پس
آدرس ajiبه صورت زير به دست مي آيد :
= +j + 2 * iآدرس aji n
تذكر:
عناصر آرايه دو بعدي aبه صورت سطري در حافظه ذخيره مي شود يعني ابتدا تمام عناصVVر سVVطر اول
ذخيره مي شود سپس عناصر سطر دوم و الي آخر يعني در حافظه ماتريس يا آرايه دو بعدي aبه شVكل زيVر
ذخيره ميگردد :
a00 a10 a 1n2 a12 a 2 n2 a n11 n 21
15
a111 a211 a311 a112 a212 a312
a a221 a321 a a222 a322
i 1 121 i 2 122
a131 a231 a331 a132 a232 a332
a141 a241 qa 341 a142 a242 a342
در اين گونه آرايه ها ابتدا تمامي عناصر صفحه(ماتريس اول) ذخيره مي شود سVپس عناصVVر صVفحه و همين
طور در نهايت عناصر صفحه n1ام براي آنكه آدرس aijkرا به دست آوريم ابتدا بايد از عناصر i -1صفحه
يا ماتريس عبور كنيم و چون در هر صفحه به اندازه n2n3عنصر وجود دارد آدرس ابتداي صفحه iام برابVر
است با :
= آدرس ابتداي صفحه iام ni n
2 3
از اينجا به بعد مانند Vآرايه هاي دو بعدي عمل مي كنيم در صفحه iام براي رسيدن به سVVطر jام بايVVد از j-1
سطر عبور كنيم و هر سطر n3عنصر دارد .
= آدرس ابتداي سطر jام در صفحه (ماتريس ) ni 2n 3 nj 3
iام
به طور كلي براي بازيابي داده هاي ترتيبي از دو شيوه مي توانيم استفاده كنيم :
16
Create an empty stack whose maximum size is
max_stack_size
Boolean isfull (stack , max_stack_size) :: =
If (number of elements in stack = = max_stack_size)
Return true
Else return false
Stack add (stack ,item) :: =
If (isfull(stack)) stack_full
Else insert item into top of stack and return
Boolean isempty (stack) :: =
If (stack = = creates (max_stack_size))
Return true
Else return false
Element delete (stack) :: =
If (isempty(stack)) return
Else remove and return item on the top of the stack
نوع داده مجرد صف
Structure queue is
Objects : a finite ordered list with zero or more elements .
Functions :
For all queue Queue , item elements , max_ queue _size
positive integer
queue creates (max_ queue _size) :: =
Create an empty queue whose maximum size is max_ queue
_size
Boolean isfullq (queue , max_ queue _size) :: =
If (number of elements in queue = = max_ queue _size)
Return true
Else return false
queue addq (queue ,item) :: =
If (isfull(queue)) queue _full
Else insert item at rear of queue and return queue
Boolean isemptyq (queue) :: =
If (queue = = createq (max_ queue _size))
Return true
Else return false
Element deleteq (queue) :: =
If (isemptyq(queue)) return
Else remove and return item on at front of queue
تعدادي متناهي ليست مرتب با صفر عنصر يا بيشتر: عناصرObject
Functionتوابع
Add تابع
. درج مي كند و صف جديد در اختيار قرار ميدهدqueue را در انتهاي صفitem عنصرelse
17
قانون :هر صف بايد انتهاي آن مشخص باشد و انتها يك متغير براي rear
هر موقع نفر خواست اضافه مي شود به ته صف اضافه مي شود.
تابع Is Emptyصفي خالي مي باشد كه تعداد عناصرش صفر باشد و در غير اين صورت پر است و (
)Maxsize = 0است.
تابع Deleteاسم صف مي خواهد و خروجي از جنس Itemو چك شود كه صف خالي نباشد.
قانون عنصر ابتداي صف را از صف خارج مي كند و آن را ارجاع مي دهد return =( .ارجاع )
Frontجلو
هيچ وقت از نفر سوم صف كسي خارج نمي شود.
ساختار پشته
نكات مربوط به ساختمان داده پشته
1ـ اولين نكته :در ساختار پشته فقط يك پVVارامتر داريم و آن TopاسVت كVه همVواره بVه عنصVر بVاالي پشVVته
اشاره مي كند.
2ـ هنگامي پشته خالي است كه Topمساوي ( ) -1باشد ( ) Top = 1-
3ـ هنگامي پشته پر است كه Topمساوي Maxsize -1باشد)Top = maxsize - 1 ( .
top
C
18
B
A
{Top Delete:
B ;]Item=stack[top
A ;Top=top-1
جايگذاري در صف
)Void addq (int *rear , element item
{
/* add an item to the queue */
{ )if (*rear = = max_queue_size -1
; ) ( queue_full
; return
}
; queue [++*rear] = item
}
حذف عنصري از يک صف
)Element deleteq (int *front , int rear
{
/* remove element at the front of the queue */
)if (*front = = rear
return queue_empty ( ) ; /* return an error key */
; ]return queue [++*front
}
عمل اضافه كردن عنصر به پشته Pushو كم كردن عنصر Popاست .
ارزشيابي عبارات
عباراتي نظير 7*6+5از نظر محاسباتي عبVVارات مبهم هسVVتند ، VزيVVرا اگVVر ابتVVدا 5و 6را جمVVع كVVرده سVVپس
حاصل را در 7ضرب كنيم نتيجه 77خواهد بود ،اما اگر ابتدا عمل ضرب را انجام دهيم سVVپس عمVVل جمVVع
حاصل 47مي شود .
يك راه سppاده براي رفVVع ابهVVام اين گونVVه عبVVارات پرانVVتز گVVذاري اسVVت ،در پرانتزگVVذاري مي تVVوان اولVVويت
عملگرها را تعيين كرد اما اين كار در رياضيات موسوم نيست در رياضيات عمل ضرب نسبت به جمع مقVVدم
است بنابراين عبارت a+bcهيچ گونه ابهامي ندارد ،در كVVامپيوتر يVVا ماشVVين حسVVاب نVVيز مي تVVوانيم بVVراي
عملگرهاي مختلف اولويت تعيين Vكنيم مثالً آنجا نيز بگوييم ضرب نسبت به جمع مقدم است .
اما كامپيوتر يا ماشين حساب چگونه مي تواند اولويت عملگرها را اعمال كند؟
براي جواب دادن به اين سئوال بايVد بVا سVاختار عبVارات بيشVتر آشVنا شVويم ،اعمVال رياضVي معمVوالً اعمVال
دوتايي هستند يعني هر عملگري روي دو عملوند ( ) Operandاثر ميكند مثالً بVVراي جمVVع دو مقVVدار Aو
( Bمي نويسيم A+Bدر اين شكل نوشتاري كه عملگر درميVVان دو عملونVVد آمVVده اسVVت شVVكل ميانونVVدي
) Infixداريم ،اگر عملگر را پيش از دو عملونVد بنويسVيم يعVني AB+شVكل پيشVوندي ( ) PrefixخVواهيم
داشت ،و اگر عملگر را پس از دو عملوند بنويسيم شكل پسوندي ( ) Postfixداريم در اين حالت مينويسVVيم
19
،+ABدر عمل براي رفع ابهام عبارات رياضي در كامپيوتر يا ماشين حساب آن ها را به صVVورت پسVVوندي
تبديل مي كنيم سپس حاصل عبارت را با استفاده از يك پشته محاسبه مي كنيم .
براي آنكه يك عبارت را از حالت ميانوندي به حالت پسوندي تبديل كنيم دو راه وجود دارد:
يكي به صورت مستقيم وديگري با استفاده ا زپشته
در روش مستقيم با توجه به جVدول اولVويت عملگرهVا كVه در پVايين آمVده اسVت ابتVدا تVرتيب انجVام اعمVال را
مشخص ميكنيم سپس هر عمل را به صورت PostfixتبVVديل Vمي كVVنيم و در نهVVايت بVVا كنVVار هم قVVرار دادن
تمام عباراتي كه به پسوندي تبديل Vشده اند شكل پسوندي كل عبارت را تعيين Vمي كنيم .
= unarxتفريق يكتايي (منفي ) U or 0 1 *دربيسيك توان هم رده notاست
5-3 U 7 0 0 1
دوتايي 1 1 1
نكته :
در بين عملگرهاي هم اولويت آن عملگري كه سمت چپ باشد مقدم است.
عملگر
اولويت
1 ( پرانتز )
تفريق يكتايي (منفي) U
2
3 not
4 * , / , % , and
5 + , - , or , xor
6 ><,<=,=,<>,>=,
20
يكي آنكه عبارت بايد دو بار پيمايش شود بار اول عملگرهاي موجود در آن تعVيين Vمي شVوند و اولVويت آنهVVا
مشخص مي شود باردوم عبارت تبديل به پسوندي مي شود اين عمليات ضمن آنكه زمVان گVVير ميباشVد گVاهي
اوقات حتي انجام پذير نيست .مثالً در ماشين حساب كل عبارت در دست نيسVVت تVا تمVام عملگرهVاي موجVVود
در آن اولويت بندي شوند.
براي رفع اين مشكل
ً
از روشي استفاده مي كنيم كه عمال در ماشين حساب و كVامپيوتر انجVام مي شVود دراين روش از يVVك پشVVته(
) Stackبراي تبديل عبارات ميانوندي به پسوندي استفاده مي كنيم به دو نكته اساسي توجه داريم:
اول اينكه در عبارت پسوندي هيچ پرانتزي نداريم.
دوم آنكه عملوندها از شكل ميانوندي به پسوندي تغيير نمي كند يعني تنها جاي عملگرها عوض ميشود
قوانين زير را رعايت مي كنيم
قانون : 1تنها عملگر ها داخل پشته قرار مي گيرند و هيچ عملوندي را در پشVVته نمي نويسVVيم بVVه محض
رسيدن به يك عملوند آن را مستقيما ً در خروجي مي نويسيم .
قانون p: 2تنها عملگري مي تواند در پشته باالي عملگر ديگر قرار بگيرد كه اولويتي بيش از آن داشته
باشد اگر عملگر جديد اولويتي كمتر يا مساوي عملگر باالي پشته داشته باشد ابتVدا آن عملگVر از پشVته خVارج
مي شود سپس عملگر جديد در پشته قرار مي گيرد .
قانون : 3عملگر ) باالترين اولويت را داراست اين عملگر مي تواند در پشته باالي هVر عملگVVر ديگVري
حتي باالي يك) ديگر قرار بگيرد .
تذكر :عملگر ) دو نوع اولويت دارد .
يكي اولويت جاري ( ) ICPو ديگري اولويت در پشته اولويت در پشته () ISP
اولويت جاري عملگر ) از همه باالتر است اما بVVه محض اينكVVه در پشVVته قرارگVVرفت پVVايين تVVرين اولVVويت را
خواهد داشت يعني اگر عملگر ) داخل پشته بود هر عملگر ديگري مي تواند باالي آن قرار بگيرد .
قانون p: 4به محض رسيدن به عملگر (كليه عملگرهاي موجود در پشته را از پشته خارج مي كنيم تا به
اولين عملگر پرانتز باز برسيم آن عملگر ها را در خروجي مي نويسيم عملگVVر ) را نVVيز ازپشVVته خVVارج مي
كنيم ولي در خروجي نمي نويسيم .
قانون : 5هنگام رسيدن به انتهاي عبارت كه با نماد ) number sign( #نشان داده مي شود پشته را
خالي ميكنيم يعني تمام عملگرها موجود را در آن را خارج مي سازيم و در خروجي مي نويسيم .
مثال :عبارت قبل را با استفاده از پشته به postfixتبديل كنيد .
post1 Tokenizeجزبندي
A + B * ( C + D / E ) / F #
21
) *+# +/ABCDE
/ /+# *+/ABCDE
F /+# ABCDE/+*F
# خالي +/ABCDE/+*F
22
postfix تابع ارزشيابي يک عبارت
int eval (void)
{
/* evaluate a postfix expression , expr , maintained as a global variable . '\0' is
the end of the expression . the stack and top of the stack are global variables .
get_token is used to return the tokentype and the character symbol .
operands are assumed to be single character digits */
precedence token ;
char symbol ;
int op1 , op2 ;
int n = 0 ; /* counter for the expression string */
int top = -1 ;
token = get_token (&symbol , &n) ;
while (token != eos) {
if (token = = operand)
add (&top , symbol –'0') ; /* stack insert */
else {
/* remove two operands , perform operation , and return result to
the stack*/
op2 = delete (&top) ; /* stack delete */
op1 = delete (&top) ;
switch (token) {
case plus : add (&top , op1 + op2) ;
breake ;
case minus : add (&top , op1 - op2) ;
breake;
case times : add (&top , op1 * op2) ;
breake;
case divide : add (&top , op1 / op2) ;
breake;
case mod : add (&top , op1 % op2) ;
}
}
token = get_token (&symbol , &n) ;
}
return delete (&top) ; /* return result */
}
مقدار دهي كردنproc
چه طور مي توان ارزشيابي كرد؟، شده راpostfix بهVيك عبارتي تبديل
عملوندها را. با استفاده از پشته مي توان عبارتي را كه به صورت پسوندي تبديل شده ارزشيابي نمود: تذكر
در پشته قرار مي دهيم و به محض رسيدن به يك عملگر از باالي پشته به اندازه مورد نياز عملوند خارج مي
ه ميVVار را ادامVV اين ك،يمVVكنيم و پس از آنكه آن عمل روي عملوندها انجام شد حاصل را باالي پشته مي نويس
.دهيم تا به انتهاي عبارت پسوندي برسيم
23
مثال:
عبارت مثال قبل را به ازاي مقادير زير بدست آوريد.
At 4 ABCD E / +*F/+
A= 5 , B= -3 , C= 1 , D=6 , E= 2 , F=4
5 -3 1 6 2 / + * 4 / + /
5 5 3- 1 6 2 4 12
3- 5 3- 1 6 3 3- 5
1 5 3- 1 1 5 4
6 5 3- 3- *
2 5 5
4 / +
-12 -3
5 5 2
/ +
صف حلقوي
در صف هاي عادي ممكن است واقعا صف پر نباشد اما با پيغام پVVر بVVودن صVVف مواجVVه شVويم كVVه يVVك پيغVVام
كاذب است مثالً صفي به طول 5را در نظر بگيريد كه بخواهيم عمليات زير را روي آن انجام دهيم:
F r
A B C 1ـ Aو Bو Cوارد مي شوند
F r
A B C 2ـ Aو Bخارج مي شوند
F r
A B C D 3ـ Dوارد مي شود
F r
A B C D 4ـ Cخارج مي شود
F r
A B C D E 5ـ Eو Fوارد مي شوند
در واقع در اين صف تنها دو نفر داخل صف هستند ( )E,Dاما چون كه rearمساوي max sizeشده
است پيغام پربودن صف صادر مي شود ،اولين راهي كه براي رفVع اين مشVVكل بVه ذهن مي رسVد آنسVت كVVه
فرد جديد يعني Fرا به جاي Aقرار دهيم يعني به صورت منطقي فكر كنيم خانه بعد از خانه پنجم ،خانه اول
است به عبارت ديگر صف را به صورت حلقوي يا دايره اي در نظر مي گيريم .
E
D
A
F
C B
24
در رياضيات براي آنكه بگوييم عددي مقدار بيش از nنداشته باشد يعني از nبه يك برسيم مي توانيم
از modاستفاده كنيم يعني رابطه زير را قرار دهيم :
محدوده از 1تا n
rear = ( rear + 1) % n
تذكر مهم:
در صف هاي حلقوي يك شكل بوجود مي آيد و آن اين است كه پر و خالي بودن صVف قابVل تشVخيص
نيست در اين صف ها اگر frontمساوي rearباشد ممكن است صف كامالً پر يا كامالً خالي باشد و بVVراي
رفع اين مشكل يك راه آن است كه :
بين rearو frontيك خانه خالي بگذاريم يعني اجازه ندهيم rearبه frontبرسد در اين حVVالت بVVه جVVاي n
خانه صف از ( )n-1خانه استفاده مي كنيم.
25
ليست هاي پيوندي
در فصل هاي قبل با ساختار آرايه ها آشنا شديم آرايه ها تعدادي خانه همنام متوالي و هم جنس در حافظVVه مي
باشند مهم ترين مزيت آنها همين ترتيب مشخص آنهاسVVت ولي گVVاهي اوقVVات اين مVVزيت بVVه ضVVعف تبVVديل مي
شود .
مثالً فرض كنيد در آرايه اي به طول 1000بخواهيم عنصر دهم را حذف كنيم .
بVVVراي اين كVVVار بايVVVد عنصVVVر يVVVازدهم را بVVVه جVVVاي عنصVVVر دهم بنويسVVVيم سVVVپس دوازدهم را بVVVه جVVVاي
يازدهم بنويسيم و همين طور عنصر هزارم را به جاي 999بنويسيم .در اين صورت عمالً بايVVد 990خانVVه
آرايه هر كدام يكي به سمت چپ منتقل شود (شيفت بVVه چپ) .در همين آرايVVه اگVVر بخVVواهيم بين خانVVه پنجم و
ششم يك خانه جديد اضافه كنيم عمالً بايد 995خانه به سمت راست منتقل شوند تا جا براي خانVVه جديVVد ايجVVاد
شود ،عمالً در ساختارهايي كه عمليات حذف و اضافه در آن هVا زيVاد باشVVد اسVVتفاده از آرايVه هVا مقVرون بVه
صرفه نيست ،به همين منظور بهتر آنست كه :
ترتيب خانه ها را به شكل منطقي در نظر بگيريم يعني خانVVه هVVاي اول تVVا هVVزارم بVVه صVVورت فVVيزيكي پشVVت
سرهم نباشند چنين ساختاري را ليست پيوندي ( ) Linked Listمي ناميم .
هر ليسVت پيونVVدي يVا زنجVVير( )chainاز تعVدادي گVره ( )nodeتشVVكيل شVVده كVVه در آن هVر گVVره حVVداقل
دوقسمت دارد :
يكي قسمت dataو ديگري ربط يا پيوند( )Linkكه به گره بعدي اشاره مي كند. V
node
data Link
مثالً
head زنجير زير به نام headشامل 1000گره است :
a0 a1 a2 a3 a999 ^
ساختار node
در زبVVان Cمي تVVوانيم سVVاختار nodeرا بVVه صVVورت زيVVر معVVرفي كVVنيم اين سVVاختار در قسVVمت نVVوع داده
Structبا استفاده از دستور Structبه صورت زير تعريف مي شود:
ساختار node
{ Struct node
int ; data
; struct node *link
;}
Pointerدر واقع اشاره گري به يك ساختار از نوع nodeمي باشد بنابراين بايد ساختار اشاره گر را نVVيز
در قسمت typedefقبل از معرفي ساختار nodeتعريف كنيم ،عالمت اشاره گرهVا در زبVان * ، Cمي
باشد .
مثال :برنامه زير يك ليست پيوندي با سه گره به نامهاي firstو secondو thirdبه شVVكل زيVVر ايجVVاد
ميگردد(.تذكر :دربرنامه كلمات كليدي حروف بزرگتر و متغيرها حروف كوچك)
First second third
10 20 30 Null
>#include <stdio.h
{ Struct node
int data
struct node
;}
; Typedef struct node chain
; Typedef chain *ptrnode
26
; ) ( Main
{
;Chain first,second,third,ptrnode,p
;First.data = 10
; First.link = &second
; Second.data = 20
;Second.link = &third
; Third.data = 30
; Third.link = ( ptrnode ) null
}
برنامه اوليه هيچ خروجي ندارد ،لذا در پايين برنامه را طوري نوشته ايم تا داراي خروجي باشد :
; P = &first
) While ( p!= ( ptrnode ) null
{
Printf ( "%d\n", p ; )data
p=p ; link
}
P
data Link
در زبان Cتوسط تابع mallocمي توانيم حافظه تخصيص دهيم p = malloc(sizeof(chain)) .باعث
مي شود که در حافظه به اندازه ))sizeساختار ، chainحافظه در نظر گرفته مي شود و ضمنا ً Pيک
اشاره گر به آن حافظه مي باشد .با اين خاصيت مي توانيم هرگاه که يک گره الزم بود آن را ايجاد کنيم.
تذكر :قسمت اول برنامه مثال قبل هيچ خروجي روي صفحه نمايش نVدارد امVا زنجVير رادر حافظVه ايجVاد مي
كند .
تذكر :عمالً مهمترين كاربرد ليست هاي پيوندي پويايي آنهاست يعني اينكه بتوانيم هر زمان كه به يك گره نياز
داشتيم آنرا ايجاد كنيم ،در برنامه زير اين پويايي به كار گرفته مي شود .در برنامه زير تعدادي عVVدد حقيقي
نامنفي از ورودي خوانده مي شود و توسط آنهايك ليست پيوندي ايجاد مي شود كه اولين گره آن با اشVVاره گVVر
headمشخص شده است ،سپس زنجير پيمايش شVVده و مجمVVوع مقVVاديري كVVه در گVVره هVVاي آن وجVVود دارد
تعيين مي شود ،همچنين فرض مي كنيم اولين عدد حتما ً نامنفي باشد .
در اين برنامه Pointerرا به اختصار Ptr، dataرا dو linkرا Lقرار مي دهيم .
برنامه زير تعدادي عدد حقيقي نا منفي از ورودي مي خواند و آن را در يک ليست به نام Headقرار مي
دهد .سپس ليست را پيمايش کرده و مجموع مقادير عناصري که در گره ها وجود دارد را محاسبه و چاپ
مي کند ( .زماني که استفاده کننده عدد منفي وارد کند از برنامه خارج مي شود ) .
>#include <alloc.h
>#include <stdio.h
{ Struct node
; Float d
; Struct node *L
;}
; Typedef struct nodes
; Typedef nodes *ptrnode
) ( Main
{
; Ptrnode head,p1,p2
; Float x, sum = 0
27
Scanf ("%f",&x) ;
P1 = ( ptrnode ) malloc ( sizeof ( nodes)) ;
P1 d=x;
Head = p1 ;
Scanf ( "%f", &x ) ;
While ( x >= 0 )
{
p2 = ( ptrnode ) malloc ( sizeof ( nodes )) ;
p2 d=x;
p1 L = p2 ;
p1 = p2 ;
scanf ( "%f" , &x) ;
}
P2 L = ( ptrnode ) null ;
P1 = head ;
While ( p1 != ( ptrnode ) null) ;
{
Sum = sum + p1 d;
P1 = p1 L;
}
Printf ( "sum = %f\n" , sum ) ;
}
Head q q q
13.5 11 8.5 13
×P× P× P× P
Head q
13.5 11 8.5 13 ^
×P P× P× P× P× P
: تمرين
برنامهاي بنويسيد كه يك ليست پيوندي از تعدادي عدد حقيقي نامنفي ايجاد كند سپس ليست را پيمايش كرده و
ت راVل ليسVداد داخVVانگين اعVV موجود در ليست را به همراه كوچكترين عدد ليست و همچنين ميVبزرگترين عدد
. در خروجي چاپ كند
28
رشتهها
Concatالحاق دو رشته
SubStr ( S , i , j): string
از كاركتر iام رشته Sبه طول jجدا مي كند مثالً در اين مثال اگر بگوييم :
) sub str ( s,4,2و dمي دهد . b
يافتن يك الگو در يك رشته
Pos S
S : C b a b C a b C a d a a a b C a b C a C a b d d
برابر
نابرابر نابرابر
P:a b C a b C a C a b
Pos P
يك abcپيدا كرديم به اندازه abcبرمي گرديم عقب .اين عقب و جلو رفتن ها در اين رشته هاي زمان گير
مي باشد .
) O ( lengh p , lengh Sزمان اجرا
فقط روي Pبرگشت به عقب و در Sبه اين صورت نيست و برگشت به عقب ندارد و جلو مي رود .
مثال :در رشته مقابل A B C D E F G H I J
اينجا براي پيداكردن GH Vمشكلي نيست چون يكي بيشتر نيست .
29
تابع شكست
تابع شكست در واقع يك بردار يك آرايه است.
اگر در كاراكتر اول شكست بخوريم بايد به خانه اول برگرديم بنابراين خانه اول صفر است.
محاسبه تابع شکست
) void fail ( char *pat
{
/* compute the pattern s failure function */
; )int n = strlen (pat
; failure [0] = -1
{ )for ( j = 1 ; j < n ; j ++
; ]i = failure [ j-1
))while (( pat [ j] != pat [ i+1] && (i >= 0
; ]i =if failure [i
)]if (pat [ j] = = pat [ i+1
; failure [ j] = i+1
; else failure [ j] = -1
}
}
j: 0 1 2 3 4 5 6 7 8
9
:F 0 0 0 1 2 3 4 0 1 2
P: a b c a b c a c
با توجه به pو از اينجا برمي گرديم ابتدا
s
i
j
0
2
1
3
Failureشكست 2
4
P 5 3 محاسبه مي كند تابع شكست را براي الگوي 2 :خط
4
6
1
7
0
8
9
10
اگر در كاراكتر چهارم شكست خوردي بيايد كاراكتر اول چون يكسانند.
تطابق الگو توسط تست انديس ها در ابتدا
) int nfind (char *string , char *pat
30
{
/* match the last character of pattern first , and then match from the beginning
*/
; int i , j , start = 0
; int lasts = strlen ( string) -1
; int lastp = strlen ( pat) -1
; int endmatch = lastp
{ )for (I = 0 ; endmatch <= lasts ; endmatch++ , start++
)]if (string [endmatch] = = pat [lastp
)for ( j = 0 ; I = start ; j < lastp && string[i] = = pat [ j] ; i++ , j++
;
)if ( j = = lastp
return start ; /* successful */
}
; return -1
}
( match makerمعرف ) Matchمنطبق بودن (يكسان بودن)
زير رشته Patو رشته Sو تابع F
1 2 3 4 5 6 7 8 9 10
P: a b c a b c a c a b
Pos s
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
S: C b a b C A b C a b A a A b C a B C Acab
حلقه را تا زماني ادامه مي دهيم كه يكي از pos pيا pos sتمام شود.
Pos S Pos P
1 1
2 )مساوي نيستند سراغ كاراكتر سوم مي رويم( 2
3 3
4 4
5 5
6 )وقتي مساويند هردو يكي جلو مي روند( 6
7 7
8 ) مساوي نيست ( 8
9 9 روي كاراكتر پنجم
مي آييم
10 6 Pos P : = F ( Pos P – 1
)+1=5
11 3
12 1
13 2
1 2
صف و پشته پيوندي
در فصل قبل ديديم كه با استفاده از آرايه چگونه مي تVVوان سVVاختار صVVف را شVVبيه سVVازي كVVرد بVVا اسVVتفاده از
ليست پيوندي نيز چنين كاري امكان پذير است در يك صف پيوندي دو اشاره گر الزم داريم كه يكي به ابتداي
صف اشاره كند ( ) Frontو ديگري به انتهاي صف ( rearيا ) tail
Front rear
n
به راحتي مي توان يك گره جديد به انتهاي صف اضافه كرد .
31
اضافه کردن يک گره به انتهاي يک ليست
void attach (float coefficient , int exponent , poly_pointer *ptr)
{
/* create a new node with coef = coefficient and expon = exponent , attach it
to the node pointed to by ptr . ptr is updated to point to this new node */
poly_pointer node ;
temp = (poly_pointer) malloc (sizeof (poly_node)) ;
if (IS_FULL(temp)) {
fprintf (stderr , "the memory is full \n" ) ;
exit ( l ) ;
}
temp -> coef = coefficient ;
temp -> expon = exponent ;
(*ptr) -> link = temp ;
*ptr = temp ;
}
. به پروسيجر ارسال مي شودy وi مي گيرد و دو پارامترX يك گره جديد به نام
}{ توضيح
V. ام اضافه مي كندi را به صفy گره
درغير اين صورت اگر صف خالي نبودfront جديدX شرط براي اين است كه اگر صف خالي بود گره
X . شودrear بايد
Front
Delete
حافظه را آزاد مي كندDispose
F rear
32
X
^
در مورد پشته پيوندي نيز عمليات به سادگي امكان پذير است زيربرنامههاي ADD Stackو Delete
Stackکه عمليات اضافه و حذف را انجام مي دهند در باال آمده است.
nullاست بنابراين چك نمي كنيم پشته خالي است يا نه . چون هنگام ايجاد پشته top
X
Top ^
بعد
Top
چند جملهايهاي پيوندي :
در فصل هاي قبل با استفاده از آرايه ها توانستيم چند جمله اي ها را ذخيره كنيم و عمليات ساده رياضppي را
روي آن ها انجام دهيم ،با استفاده از ليست هاي پيوندي نيز به راحتي مي توان چند جملppه اي هpا را شpبيه
سازي كرد براي اين منظور هر جمله يك چند جمله اي را يك گره از ليست پيوندي مي گيريم كه سppه قسppمت
دارد يكي قسمت ضريب كه عدد حقيقي است ،ديگري قسمت توان كه عدد صحيح است و سومي اشppاره گppر
( گره چند جمله اي)node poly به گره بعدي (جمله بعدي )
Coef exp Link
33
case -1 : /* a -> expon < b->expon */
attach (b -> coef , b -> expon , &rear) ;
b = b -> link ;
breake;
case 0 : /* a ->expon = b ->expon */
sum = a -> coef + b -> coef ;
if (sum) attach (sum , a -> expon , &rear) ;
a= a -> link ; b = b -> link ;break ;
case 1 : /* a ->expon > b ->expon */
attach (a -> coef , a -> expon , &rear) ;
a = a -> link ;
}
/* copy rest of list a and then list b */
for ( ; a ; a = a -> link ) attach ( a -> coef , a -> expon , &rear ) ;
for ( ; b ; b = b -> link ) attach (b -> coef , b -> expon , &rear) ;
rear -> link = NULL ;
/* delete extra initial node /*
temp = front ; front = front -> link ; free (temp) ;
return front ;
}
V. ضميمه مي كند، = ملحق كردنattack
. را انجام ميدهدNew term كار همانattack
: نمونه سوال
1.
For ( i = 1 ; i =< n ; i++)
{
j = 2*i ; K=n-i ;
While ( j <= k )
j=2*j;
}
4.
F(q):= IF isemptr (q) Thenq;
F(ADD Q [ i,q]) : : = IF Isempty (q) Then ADD Q (i,q);
Else ADD Q (Delete Q, F (Delete Q));
34
گراف ها و درخت ها
هر گراف Gاز دو مجموعه تشكيل شده است يكي Vو ديگري . E
Vيك مجموعه غير تهي و متناهي است كVVه آن را مجموعVVه رئVVوس يVVا گVVره هVVا يVVا نقVVاط گVVراف مي نVVاميم و
Eنيز تعدادي از زيرمجموعه هاي دو عضوي Vاست E ،را مجموعة يالها يVا لبVVه هVا يVا خطVوط گVراف مي
ناميم .در هر گراف اگر بين دو راس يال وجود داشته باشد آنها را مجاور مي ناميم و تعداد رئوسي را كVVه بVVا
يك راس دلخواه مجاور هستند درجه رأس مي ناميم .
مثالً در گراف زير راس bدرجه 2است و رأس dدرجه 3مي باشد V ) .رئوس و Eيالها)
)G=(V,E C
a
b
e d }V={a,b,c,d,e,f,p,q
p
f
q
G
اگر بتوانيم از يك راس گراف شروع كرده و با گذشتن از يالها و رئوس گراف بVه يVك راس ديگVر برسVVيم بVVه
شرط آنكه هيچ راس و يالي تكراري نباشد مي گوييم بين دو راس مسير وجود دارد.
اگر بين هر دو راس دلخواه گراف حداقل يك مسير وجود داشته باشد آن گراف را همبند يا مرتبط مي ناميم.
مثال قبل مثالي از يك گراف همبند مرتبط نبود زيرا بين bو eهيچ مسيري وجود ندارد .
اگر از يك راس شروع كرده و با گذشتن از يال ها و رئوس بتوانيم مجدداً به همان رأس بازگرديم بVدون آنكVه
راس و يال تكراري وجود داشته باشد ،آنگاه يك دوره خواهيم داشت .
Cيك دوره به طول 3است زيرا سه يال دارد . d e مثالً درگراف قبل C
dيك دوره به طول 4است . F e c d
تعريف درخت
هر گراف همبند بدون دوره را درخت مي ناميم .
مثال:
درخت مقابل 11راس و 10يال دارد .
نقطه يك درخت مي باشد که تنها يك راس دارد و بدون يال مي باشد .
35
در كامپيوتر درخت ها را به صورت بازگشتي تعريف مي كنند به صورت زير:
تعريف :
درخت مجموعهاي از چندگره به صورت زير ميباشد :
الف ـ گره خاصي به نام ريشه دارد .
T 1 ,T,...,افراز شده اند ،به طوري كVه هVر كVدام از
2 T N هاي مجموعه ب ـ بقيه گرهها به جز ريشه به
ها را يك زير درخت ريشه ميناميم. T i
مثال:
T3
T2
T1
B
E
C D
F K L
G H I J
Q
نمايش درخت:
دو ابزار اساسي براي نمايش درخت ها وجود دارد يكي آرايVVه هVVا و ديگVVري ليسVVت هVVاي پيونVVدي ،معمVVوالً
براي نمايش درخت از آرايه استفاده نمي شود ،براي استفاده از ليست پيوندي بايد گره هايي تعريف كVVنيم كVVه
يك قسمت Dataو چند قسمت پيوند Link Vداشته باشVVد ،تعVVداد Link VهVVا در واقVVع برابVVر بVVا بيشVVترين درجVVة
رئوس درخت است .
در مثال قبل بيشترين فرزندان را Aدارد كه 4فرزند است پس بايد گره هايي 5قسمتي تعريف كنيم كه يVVك
قسمت Dataدارد و 4اشاره گر به نامهاي ch1 , ch4كه به فرزندان گره اشاره مي كنيم.
36
data Child 1 Child n
اشاره گرها
با اين حساب درخت مثال قبل را مي توان به شكل زير نشان داد :
A
B ^ ^ ^ C ^ D ^ ^ ^ E ^ ^
P ^ ^ ^ ^ O ^ ^ ^ ^ N ^ ^ ^ M ^ ^ ^ ^
همانطور كه مشاهده مي شود و تعداد Vاشاره گرهاي NULLدر روش قبل بسVVيار زيVاد اسVت بVVه همين
خاطر از روش ديگري استفاده مي كنيم كه در آن تعداد اشVVاره گرهVVاي NULLكVVاهش يابVVد ،اين روش جديVVد
روش فرزند چپ ـ هم نياي راست ناميده مي شVود .در اين روش هVVر گVVره حVVداكثر بVا دو گVVره در سVطح بعVVد
مجاور است كه اين گره ها يكي فرزند چپ گره است و ديگري هم نياي راست گره است .
عمق درخت افزايش يافته و برابر 7است و تعداد Vاشاره گرهاي NULLكاهش يافته .
1 A
37
2 B
3 F
C
4
G D
5 P H J E
6 O
I N K
7 Q
M L
تمرين :چگونه مي توان از گرافي كه به صورت فرزند چپ ـ هم نياي راست نمايش داده شده است به گراف
اصلي رسيد ؟
1
2
3
4
كامل يا پر
2 2 1 2 2 2 d 1 2 d 1
38
با استفاده از اين خواص براي نمايش يك درخت دودويي به عمق dاز آرايه اي به طول 2d -1اسVVتفاده مي
كنيم ،ريشه را در خانه اول آرايه قرار مي دهيم و به صورت بازگشVVتي فرزنVVد چپ خانVVه iام را در خانVVه (
)2iقرار مي دهيم و فرزند راست خانه iام را در خانه 2i+1قرار مي دهيم .
B
C
D
F E
G
I
J H
i
[ است . نكته پدر گره خانه iام در خانه ]
2
1 2 3 4 5 6 7 8 9 10 `1 `2 `3 `4 `5 `6 `7 `8 `9
A B C D E F G H
`20 ``1 ``2 ``3 ``4 ``5 ``6 ``7 ``8 ``9 ``30 ```1
I J
L R
اين سه گره را به ( !3سه فاكتوريل) حالت پيمايش (بازيابي) كرد ،اما قرارداد مي كنيم كه فرزند چپ
در اين صورت مقدم بر فرزند راست باشد ،دراين صورت 3حالت پيمVVايش خVVواهيم داشVVت :در حVVالت اول
ابتدا گره بازيابي مي شود سپس فرزندان چپ و راست( )NLRاين حالت پيمايش را حVVالت پيش ترتيVVبي ((
Preorderمي ناميم .
اگر گره nدر ميان فرزندان چپ و راست پيمايش شود( )LNRآن گاه پيمVVايش ميVVان ترتيVVبي( )In order
( خواهيم داشت و در صورتي كه گره nپس از فرزندانش بازيابي شVود( )LRNپيمVايش پس ترتيVبي
)order PostخVVواهيم داشVVت ،در اين حVVالت هيچ گVVره اي بازيVVابي نمي شVVود مگVVر آنكVVه تمVVام فرزنVVدانش
بازيابي شده باشند به همين جهت ريشه آخرين گره اي است كه بازيابي مي شود .
(در بعضي كتابها به جاي N ، Dمي باشد)
B
C
39
D
F E
G
I
J H
LNR: B,I,F,D,G,J,A,E,H,C
LRN: I,F,J,G,D,B,H,E,C,A
كاربرد درخت هاي دودويي
همانطور كه گفتVه شVد درخت هVاي دودويي بسVيار پركاربردنVد ، Vيكي از كاربردهVاي آنهVا در تبVديل عبVارات
رياضي است ،اغلب اعمال رياضي ،اعمال دوتايي هستند يعني يVVك عملگVVر روي دو عملونVVد اثVVر مي كنVVد ،
يكي عملوند چپ و ديگري عملوند راست .بنابراين متناظر هر عبارت رياضي مي توانيم يك درخت دودويي
داشته باشيم .مثالً درخت متناظر با عبارت A+Bبه صورت زير نمايش داده مي شود :
+
A B
40
}
}
41
روشهاي مرتب سازي :
2
4 62
1 2
8 5 5
8
1 2
6 5 39
42
1
نكته :زمان اجراي مرتب سازي جبابي ) O ( n 2
2
n = 2 20اگر :مرتب سازي حبابي = 500×9 10زمان اجرا
n = 2 20اگر :مرتب سازي كومه اي = O(220 × )20زمان اجرا
براي درج عنصر در يک درخت جستجوي دودويي به راحتي مي توانيم جاي گره جديد را تعيين کنيم .براي
اين منظور از ريشه شروع مي کنيم و اگر گره جديد داراي مقداري از ريشه کمتر بود ،در سمت چپ و در
غير اين صورت به سمت راست مي رويم .اين کار را به شکل بازگشتي تکرار مي کنيم تا محل گره جديد
مشخص شود .
براي حذف يک گره از درخت ، BSTاگر آن گره برگ باشد ( فرزند نداشته باشد ) کافيست اشاره گر والد
آن را برابر Nullقرار دهيم .اما اگر گره اي که مي خواهيم حذف شود ،داراي فرزند باشد دو حالت پيش
رو داريم .اگر گره اي که مي خواهيم حذف کنيم فقط يک فرزند داشته باشد عمالً فرزند را به جاي والد مي
نشانيم ،اما اگر گره اي که مي خواهد حذف شود ،دو فرزند داشته باشد مي توانيم بزرگترين عنصر
( بزرگترين در زيردرخت چپ آن يا کوچکترين عنصر زيردرخت راست آن را جايگزين کنيم .
سمت چپ – کوچکترين در سمت راست )
مثال :در درخت BSTزير مثالً اگر بخواهيم 72را حذف کنيم مي توانيم ( 44بزرگترين در زير درخت
سمت چپ ) يا ( 80کوچکترين در زيردرخت سمت راست ) را به جاي 72قرار دهيم .
32
25 72
تذکر مهم :هنگام حذف گره از BSTتوجه داريم که اگر گره جايگزين گره حذف شده فرزند داشته باشد بايد
فرزندان گره جايگزين را به والد قبلي گره جايگزين مرتبط کنيم .
مثال :در درخت زير اگر بخواهيم 72را حذف کنيم 44 ،جايگزين آن مي شود و 41فرزند راست وي
خواهد شد .
32
25 72
41
درخت حاصل را در شکل زير مي توانيد مشاهده فرماييد :
32
25 44
43
اساس كار اين روش ادغام آرايه هاي مرتب در يكديگر است بدين صورت كه در تكرار اول هر دو عدد
كنار هم را به ترتيب صعودي مرتب مي كنيم تا در واقع آرايه هاي مرتب به طول 2بدست آيد در تكVVراردوم
آرايه هاي مرتب به طول 2را كه كنار هم هستند در هم ادغام مي كنيم تا آرايه هاي مرتب به طول 4بدسVVت
آيد ،در تكرارسوم آرايه هاي چهارتايي را ادغام مي كنيم تVVا مVVرتب 8تVVايي بدسVVت آيVVد اين كVVار را ادامVVه مي
دهيم تا كل آرايه مرتب شود .
مثال :
41 , 29 , 53 , 16 , 19 , 32 , 17 , 43 , 65 , 14 , 18 , 32 , 19
29 , 41 , 16 , 53 , 19 , 32 , 17 , 43 , 14 , 65 , 18 , 32 , 19
14 , 16 , 17 , 18 , 19 , 19 , 29 , 32 , 32 , 41 , 43 , 53 , 65
44
نکته :اگر dataبه شکل مرتب شده ذخVVيره شVVده باشVVند ،مVVرتب سVVازي درجي از دو روش Selectionو
Bubbleبهتر است .
کومه است
کومه نيست
در اينجا دو مفهوم Max Heapو Min Heapمطرح مي باشند که در پايين به آنها اشاره شده است.
: Min Heapکومه اي را که در آن هيچ گره اي از فرزندانش بزرگتر نباشد را Min Heapمي ناميم .
: Max Heapيک درخت دودويي شبه کامل است که در آن هيچ گره اي از فرزندانش کوچکتر نباشد .
3
0
2 1
5 4
2 1
3 9
درج عنصر در : Max Heapاگر بخواهيم يک عنصر جديد را به يک Max Heapاضافه کنيم ،اوالً آنرا
به موقعيت مجاز اضافه مي کنيم تا کومه بودن از دست نرود .
مثالً اگر بخواهيم عدد 22را به Max Heapباال اضافه کنيم به صورت زير عمل مي کنيم :
3
0
2 1
5 4
2
سپس با ريشه خود يعني 14 19جابجا مي 23شود .
2 ابتدا 22از سمت چپ ،به پايين ترين سطح اضافه شده و
3
0
45
2 2
5 2
2 2
5 2
2 1
3 9
2
5
1 2
4 2
2 1
3 9 2
5
2 2
3 2
1 1
4 9
از آنجVVا کVVه در Max HeapهمVVواره بزرگVVترين عنصVVر در ريشVVه قVVرار دارد ،اگVVر تمVVام عناصVVر Max
Heapرا متواليا ً از ريشه خارج کنيم ،در نهايت اعداد به صورت مرتب شده باقي مي مانند .
7 8 8 8 8
9 4 اي Sortکنيد . دهيد سپس به صورت کومه 4 4
مثال :کومه اعداد زير را تشکيل
4
45 – 32 7– 15 - 25 - 84 - 79
8 7 2 7 2 7 2
4 9 9 5 9 9 5
5
1 1 3
5 5 2
8 8
4 4
7 2 7 4
9 5 9 5
1 3 4 1 3 2
5 2 5 5 2 5
46
حذف 45 حذف 32
3 2 3 2 1 2
2 7 8 5 4 2 7 5 4 5 5
8 7 8
1 9 4 5 9 4 5 9 4
5
2حذ 1
5 5 ف 25
1 3 2 3
5 2 5 2
7 8 4 7 8
4 9 4 5 9 4
5
47
16 18 24 25 25 37 58 39 62 m ntovip
39 58 7 9 85
مثال :
25 , 16 , 19 , 32 , 14 , 27 , 15
پروژه
هدف پروژه:
برنامه اي بنويسيد Vکه يک عبارت infixشامل عملگرهاي زير که در آن هر عملوندي فقط يک کVVاراکتر از
حروف انگليسي مي باشد و حداکثر تا 3سطح پرانتز تو در تVو از ورودي بگVيرد و آن را بVه PrefixتبVديل
کند .
براي جمع ** توان
+
براي تفريق پرانتز بسته (
-
براي ضرب پرانتز باز )
*
براي تقسيم ( )~ =shift + 1منفي يكتايي ~
/
48