470 likes | 702 Views
فصل دوم : آرايه ها و ساختارها. اهداف. در اين فصل دانشجو با کاربرد موارد زير آشنا خواهد شد:. آرايه ليست چند جملهاي ماتريس خلوت رشته. بازيابي. ذخيره سازي مقادير. آرايه. در رابطه با آرايه به دو عمل اساسي نياز است :.
E N D
فصل دوم : آرايه ها و ساختارها اهداف در اين فصل دانشجو با کاربرد موارد زير آشنا خواهد شد: • آرايه • ليست • چند جملهاي • ماتريس خلوت • رشته
بازيابي • ذخيره سازي مقادير آرايه در رابطه با آرايه به دو عمل اساسي نياز است : آرايه مجموعه اي از زوج ها ، شامل انديس و مقدار است (<index>,<value>) . به ازاي هر انديس يک مقدار مربوط به آن انديس وجود دارد که به زبان رياضي آنرا تناظر يا انگاشت مينامند.
آرايه (Array) آرايه نوعي ساختمان داده است كه عناصر آن هم نوع بوده و هر يك از عناصر با يك انديس و بصورت مستقيم قابل دستيابي ميباشد. آرايه ميتواند يك بعدي و يا چند بعدي باشد آرايه هاي دو بعدي را با نام ماتريس ميشناسيم
1-2 آرايه ها آرايه در زبان C به صورت مثال در زير آمده است : int list [5] نکته در زبان C تمام آرايه ها از انديس 0 شروع مي شوند. آرايه اي با n عنصر با انديسهاي 0 تا n-1 ميتوان به درايههاي آن دسترسي پيدا كرد
ليست ها شامل اقلام داده به صورت مي باشند. ليست ليست • مثال : • روزهاي هفته ( شنبه ... جمعه ) ساده ترين و متداول ترين نوع ساختمان داده ها ، ليست هاي مرتب شده يا خطي هستند.
اعمال صورت گرفته بر روي ليست ها • پيدا کردن طول يک ليست • خواندن اقلام داده يک ليست از چپ به راست يا بر عکس • بازيابي i امين عنصر از يک ليست (0≤ i < n) • تعويض يک قلم اطلاعاتي در i امين موقعيت يک ليست (0≤ i ≤ n) • درج يک قلم داده جديد در i امين موقعيت يک ليست (0≤ i < n). • ( اقلام داده اي که قبلا به صورت i ، i+1 ،…،n-1 شماره گذاري شده اند به صورت i+1،i+2،…،n در مي آيند) • حذف يک قلم اطلاعاتي از i امين موقعيت يک ليست (0≤ i < n) . اقلام داده i+1،…،n-1به اقلام داده با شماره I،i+1،…،n-2تبديل مي شود.
نگاشت ترتيبي نگاشت ترتيبي متداول ترين پياده سازي ، نمايش يک ليست مرتب شده به صورت يک آرايه مي باشد به نحوي که عنصر iام ليست با انديس i آرايه متناظر باشد. اين مطلب يک نگاشت ترتيبي ناميده مي شود.
انديس لينك مقدار 0 1 2 n-1 ليست پيوندي ليست پيوندي راه حل ديگر براي پياده سازي ليست، ذخيره در يك ليست پيوندي ميباشد كه هر گره از ليست حاوي دو عنصر انديس و مقدار ميباشد.
نوع داده اي چند جملهاي (Polynomial) ما نيازمند ساخت يك نوع داده اي تجريدي براي نمايش و پردازش چندجملهاي نمادين هستيم. منظور از نمادين ليستي از ضرايب و توانهاست كه با هم چند جمله اي را تشكيل ميدهند.
بزرگترين توان x در چند جمله اي را درجه چند جمله اي ميگويند. PAدرجه چند جمله اي A(x) چند جملهاي ها (ادامه...)
0 1 2 3 12 8 0 7 پياده سازي چند جمله ايها • استفاده از آرايه • در اين روش انديس آرايه معرف توان x و مقدار ذخيره شده معرف ضريب ميباشد. • مثال:
كلاس مربوط به چند جملهاي class Polynomial { private: int degree; float Coef[MaxDegree+1]; }; ///////////////////////////////////////////////////////////////////// پياده سازي 1 class Polynomial { public: Polynomial(int deg) {degree = deg; Coef = new float[deg];} private: int degree; float *Coef; }; پياده سازي 2 بطور كلي اگر به صورت كلاس بنويسيم كلاس چند جمله اي به شكل زير خواهد بود.
0 300 8 7 چند جمله اي هاي تنك (خلوت) در اين چندجملهاي ها ضرايب صفر زياد هستند مثلاً x1000 + 1 داراي 999 صفر است. براي ذخيره چند جملهاي هاي خلوت از ساختار زير استفاده ميكنيم عناصر بر اساس قواي صعودي و يا نزولي مرتب ميشوند
كلاس مربوط به چند جملهايهاي خلوت class Polynomial; class Term { friendclass Polynomial; private: float coef; //Coefficient int exp; //Exponent }; class Polynomial { private: int terms; Term termArr[MaxTerms]; public: Polynomial() { terms = 0; termArr[0]=0; } };
Polynomial Polynomial::Add(const Polynomial& B) { Polynomial c; int a=0 , b=0; float temp; while(a<terms && b<B.terms) { switch (compare(termArr[a].exp,B.termArr[b].exp)) { case ‘=‘: temp = termArr[a].coef+B.termArr[b].coef; if(temp) c.NewTerm(temp, termArr[a].exp); a++; b++; break; case ‘<‘: c.NewTerm(B.termArr[b].coef, B.termArr[b].exp); b++; break; case ‘>‘: c.NewTerm(termArr[a].coef, termArr[a].exp); a++; break; } } for( ; a<terms; a++) c.NewTerm(termArr[a].coef, termArr[a].exp); for( ; b<B.terms; b++) c.NewTerm(B.termArr[b].coef, B.termArr[b].exp); return c; } جمع دو چند جمله اي خلوت
void Polynomial::NewTerm(float c , int e) { if(terms >= MaxTerms) { cerr<<“Too many terms in polynomial\n”; return; } termArr[terms].coef = c; termArr[terms].exp = e; terms++; }
تمرين 1 (زمان تحويل جلسه آينده) • برنامه اي بنويسيد كه دو چند جمله اي خلوت را در هم ضرب نمايد. • براي پياده سازي تابع ضرب در صورت نياز توابع ديگري كه كار شما را ساده تر سازد را نيز ميتوانيد تعريف نماييد
col1 col2 col3 row 0 row 1 row 2 row 3 row 4 27- 3 4 6 82 2- 109 64- 11 12 8 9 48 27 47 ADT ماتريس به طور کلي در رياضيات ، يک ماتريس شامل mسطر و nستون بوده و مي تواند مانند شکل زير نمايش داده شود.
ADT ماتريس اسپارس (ماتريس خلوت) ماتريس اسپارس در علوم کامپيوتر متداول ترين نمايش براي ماتريس آرايه دوبعدي است که به صورت a[MAX_ROW][MAX_COLS] نمايش داده مي شود. هر عنصر ماتريس به صورت a[i][j] نمايش داده مي شود. ماتريسي که عناصر صفر آن زياد باشد ماتريس اسپارس ناميده مي شود. حداقل اعمال ممکن شامل ايجاد، جمع ، ضرب و ترانهاده ماتريس ميباشد.
ADT ماتريس خلوت با توجه به ويژگيهاي اين ماتريس هر عضو را مي توان بصورت منحصر بفردي با سه تايي <row,col,value> مشخص نمود. سه تايي هاي بدست آمده بر اساس سطرها مرتب هستند و سپس عناصري كه در يك سطر قرار دارند به ترتيب شماره ستون مرتب ميشوند.
كلاس مربوط ماتريسهاي خلوت class SpMtx; //Sparse Matrix class class MTerm { friendclass SpMtx; private: int row,col,value; }; class SpMtx { private: int Rows,Cols,Terms; MTerm smArr[MaxTerms]; };
ترانهاده يک ماتريس براي پيدا نمودن ترانهاده يک ماتريس بايد جاي سطرها و ستون ها را عوض کرد بدين مفهوم که هر عنصر a[i][j]در ماتريس اوليه به عنصرb[j][i]در ماتريس ترانهاده تبديل مي شود. • الگوريتم زير براي پيدا کردن ترانهاده يک ماتريس ، الگوريتم مناسبي است : for all element in column j place element < i ، j ،value> in element < j ، i ،value>
SpMtx SpMtx::Transpose() • { • SpMtx b; • b.Rows = Cols; • b.Cols = Rows; • b.Terms = Terms; • if(Terms<=0) • return b; • int CurB=0; • for(int c=0 ; c<Cols ; c++) • for(int i=0 ; i<Terms ; i++) • if(smArr[i].Col == c) • { • b.smArr[CurB].row=c; • b.smArr[CurB].col=smArr[i].row; • b.smArr[CurB].value=smArr[i].value; • CurB++; • } • return b; • }
ترانهاده يک ماتريس الگوريتم بيان شده نشان مي دهد که بايد تمام عناصر در ستون 0 را پيدا و آنها را در سطر 0 ذخيره کرد همچنين تمام عناصر ستون 1 را پيدا و در سطر 1 قرار داد و همين فرآيند را ادامه داد. از آنجا که ماتريس اوليه سطري بوده لذا ستون هاي داخل هر سطر از ماتريس ترانهاده نيز به صورت صعودي مرتب مي شود.
تحليل ترانهاده تعيين زمان اجراي اين الگوريتم از آنجا که حلقه هاي تودرتوي for عامل تعيين کننده مي باشد ، آسان است. حلقه for خارجي Colsمرتبه تکرار مي شود که Cols حاوي تعداد ستون هاي ماتريس اوليه است. به ازاي هر بار تكرار حلقه خارجي حلقه داخلي Terms بار تكرار ميشود كه Terms تعداد عناصر غيرصفر ماتريس اوليه ميباشد بنابراين زمان کلي براي حلقه هاي تودرتوي for برابر با حاصل ضرب ستون ها در عناصر (Cols.Terms) مي باشد. بنابراين زمان اجرا به صورت O(Cols.Terms) خواهد بود.
تمرين 2 • با مراجعه به كتاب الگوريتم محاسبه سريع ترانهاده را به همراه الگوريتم بيان شده پياده سازي نماييد. (زمان تحويل هفته آينده) آيا ميتوان سرعت الگوريتم يافتن ترانهاده را افزايش داد.
آرايه هاي چند بعدي در c++ آرايه هاي چند بعدي به شكل زير تعريف ميشوند. DataType ArrayName[D1][D2]…[Dn] كه Di تعداد عناصر بعد iام ميباشد. در زبانهاي برنامه نويسي ديگر مانند Pascal ميتوان براي انديسهاي آرايه بازه تعريف نمود: DataType ArrayName[P1..Q1][P2..Q2]…[Pn..Qn]
با توجه به تعريفي كه ارائه شد تعداد خانههاي آرايه n بعدي به شكل زير محاسبه ميشود:
آدرس عنصر در آرايه در آرايه يك بعدي: آدرس A[i] = + i در آرايه دو بعدي: آدرس A[i][j] = + iD2 + j در آرايه سه بعدي: آدرس A[i][j][k] = + i.D2.D3 + j.D3 + k در آرايه n بعدي: آدرس A[i1][i2]…[in] = + i1.D2.D3…Dn + i2.D3.D4…Dn+…+ in
از ديدگاه ADTيک رشته به صورت تعريف مي گردد به نحوي که کاراکترهاي اخذ شده از مجموعه کاراکترهاي زبان برنامه نويسي مي باشد. اگر n=0باشد،S يک رشته تهي مي باشد. نوع داده مجرد رشته اي(STRING ADT) در زبان C ، رشته ها به صورت آرايه هاي کاراکتري که به کاراکترتهي ‘\0’ ختم مي شوند ،آرايه مي گردد.
نوع داده مجرد رشته اي(STRING ADT) مختص ADT جديد عملکردهاي مناسب و مفيدي وجود دارد که مي توان براي رشته ها تعريف کرد مانند : ايجاد يک رشته تهي جديد خواندن يا نوشتن يک رشته ضميمه کردن دو رشته به يکديگر (concatenation) کپي کردن يک رشته مقايسه رشته ها درج کردن يک زير رشته به داخل رشته برداشتن يک زير رشته از يک رشته مشخص پيدا کردن يک الگو(pattern) يا عبارت در يک رشته
نوع داده مجرد رشته اي(STRING ADT) نحوه ذخيره سازي در حافظه : char s[] = "dog”; s[0] s[1] s[2] s[3] نمايش رشته در زبان C
مثال : درج رشته مي خواهيم رشته t را در موقعيت i=1 رشته s جاي دهيم : s t temp initially temp (a) After strncpy(temp،s،i) temp (b) After strcat(temp،t) temp
تطابق الگو(Pattern Matching) فرض کنيد که دو رشته داريم ، string وpat، به نحوي pat يک الگو يا pattern بوده و بايد در string پيدا شود. ساده ترين راه براي تعيين اينکه آيا pat در رشته وجود دارد يا خير، استفاده از تابع کتابخانه اي strstr مي باشد. • با وجود اينکه strstr براي تطابق عبارت مناسب به نظر مي رسد ، دو دليل عمده براي نوشتن تابع تطابق الگو وجود دارد : • تابع strstr براي ANSI C. جديد بوده و ممکن است که در کامپايلر موجود نباشد. • چندين روش براي پياده سازي تابع تطابق الگو وجود دارد.
تطابق الگو نکته غير موثرترين روش ، تست متوالي هر کاراکتر رشته تا زمان پيدا شدن الگو و يا رسيدن به انتهاي رشته ، مي باشد. اگر pat در string نباشد، اين روش داراي زمان محاسباتي 0(n.m) خواهد بود که در آن n طول patوm طول string مي باشد.
class CMyString { public: char *str; CMyString(char *init,int len); CMyString(CMyString &s); int Getlength(); int Find(CMyString &pat); }; CMyString::CMyString(char *init,int le) { str=new char[le]; strcpy(str,init); } CMyString::CMyString(CMyString &s) { str=new char[s.Getlength()+1]; strcpy(str,s.str); } int CMyString::Getlength() { return strlen(str); } كلاس رشته به همراه سازنده ها و تعريف توابع عضو
روش اول پياده سازي جستجوي يك زير رشته int CMyString::Find(CMyString &pat) { char *p=pat.str,*s=str; int srcL = Getlength() , patLen = pat.Getlength(); int i,j; for(i=0;i<= srcL - patLen ; i++) { for(j=0;j< patLen ; j++) if(s[i+j]!=p[j]) break; if(j== patLen ) return i; } return -1; }
روش دوم پياده سازي جستجوي يك زير رشتهالگوريتم كنوث-موريس-پرات • تابع شكست: براي هر يك از عناصر تعيين ميكنيم در صورت شكست از چه عنصري بررسي مجدد آغاز شود. و به ازاي هر كاراكتر در موقعيت j در رشته pat يك مقدار بدست ميآيد.
k بزرگترين مقدار k كه k<j بصورتي كه p0p1…pk= pj-kpj-k+1…pjاگر چنين k≥j اي وجود داشته باشد f(j)= در غير اينصورت -1
class CMyString { public: char *str; char *f; CMyString(char *init,int len); CMyString(CMyString &s); int Getlength(); int Find(CMyString &pat); void Fastfind(CString &pat); void Fail(); }; CMyString::CMyString(char *init,int le) { str=new char[le]; f=new char[le]; strcpy(str,init); } CMyString::CMyString(CMyString &s) { str=new char[s.Getlength()+1]; f=new char[s.Getlength()+1]; strcpy(str,s.str); } افزودن متغير عضو f جهت نگهداري مقادير شكست و تغييرات اعمال شده در سازندهها و
int CMyString::Fail() { int lengthp=Getlength(); f[0]=-1; for(int j=1 ; j<lengthp ; j++) { int pf = f[j-1]; while(str[j]!=str[pf+1] && pf>=0) i=f[pf]; if(str[j]==str[pf+1]) f[j]=pf+1; else f[j]=-1; } }
int CMyString::Fastfind(CMyString &pat) { pat.Fail(); int posp=0,poss=0; int lengthp=pat.Getlength(),lengths=Getlength(); while(posp<lengthp && poss<lengths) { if(pat.str[posp]==str[poss]) { posp++; poss++; } else { if(posp==0) poss++; else posp=pat.f[posp-1]+1; } } if(posp<lengthp) return -1; return poss-lengthp; }
تمرين 3 (زمان تحويل هفته بعد) كلاس رشته را با دو تابع find و fastfind پياده سازي نموده و سرعت جستجوي يك زير رشته را در متن مقايسه نماييد.