အ ၀တ္ အ စား က န္႕ သ တ္ ခ် က္ မ ရွိ ၊ ႏွ စ္ သ က္ ရာ ကုိ ၀ တ္ စား ဆ င္ ယ င္ ႏုိ င္ ပါ သ ည္ ။
ေရႊပြဲလာတုိ႕၏ အားေပးမႈ
Tuesday, June 12, 2012
၀င္းဒုိးပဲ သံုးတာရွင့္
Tuesday, October 26, 2010
SQL Statement Level တြင္ Optimize လုပ္၍ Query Execution ကုိ ျမန္ဆန္ေစျခင္း
မေန႕က စာေရးသူ အိမ္ကုိ ျပန္ေနတုန္း အစ္မေတာ္က ခ်က္ခ်င္းပဲ G-talk ေပၚကုိ ၾကြပါလုိ႕ Message ပုိ႕လာပါတယ္။ ဒါနဲ႕ပဲ ဖုန္းကေန G-talk ကုိ ဖြင့္လုိက္ေတာ့ Query တစ္ခုကုိ run ထားတာ ၃ နာရီ နီးပါးရွိၿပီ၊ အေျဖမထြက္ေသးလုိ႕ ဘယ့္ႏွယ္လုပ္ရပါ့လုိ႕ ေမးပါေတာ့တယ္။ ဒီ စာတမ္းငယ္မွာ အလားတူ ျပႆနာတစ္ရပ္ (အေရးႀကီး အခ်က္အလက္မ်ား ပါ၀င္ေနသျဖင့္ မူလျပႆနာကုိ မေဖာ္ျပႏုိင္ပါ) ကုိ SQL Statement Level မွာ Optimize လုပ္ပံုကုိ ေရးသားေဖာ္ျပမွာ ျဖစ္ပါတယ္။
ပရိေဘာဂနဲ႕ မီးဖုိေခ်ာင္သံုး ပစၥည္း ေရာင္းတဲ့ကုမၸဏီတစ္ခုမွာ ေဖာက္သည္ေတြရဲ႕ အမည္၊ ေမြးေန႕၊ လိပ္စာ၊ ဖုန္းနံပါတ္၊ အခ်က္အလက္ေတြကုိ Table တစ္ခုနဲ႕ သိမ္းထားပါတယ္ (Customer Table ဆုိပါစုိ႕)။ ေဖာက္သည္ေတြ ပစၥည္း မွာယူတုိင္းမွာ အမွာလက္ခံတဲ့ Table တစ္ခုလဲ ရွိပါတယ္ (Order Table ဆုိပါစုိ႕)။ Order Table ဟာ ကုမၸဏီ သက္တမ္းၾကာတာနဲ႕အမွ် အရမ္းႀကီး လာတတ္လုိ႕ Production run ေနတဲ့ server မွာ ၃ - ၄ ႏွစ္စာပဲ ထားၿပီး က်န္တာကုိ သပ္သပ္ သိမ္းထားေလ့ ရွိပါတယ္။
ျဖစ္ပံုက ပရိေဘာဂ မ၀ယ္ဖူးေသးတဲ့ (မီးဖုိေခ်ာင္သံုး ပစၥည္းပဲ ၀ယ္ဖူးတဲ့) ေဖာက္သည္ေတြကုိ အထူး အေရာင္းျမွင့္တင္ေရး အစီအစဥ္နဲ႕ ပရိေဘာဂေတြ ေစ်းခ်ေရာင္းမဲ့ အေၾကာင္း ေၾကာ္ျငာစာ ပုိ႕ခ်င္တာပါပဲ။ အဲဒါနဲ႕ ေအာက္ပါ Query ကုိ ေရးပါတယ္။
SELECT cust_id, cust_name, cust_add
FROM customer_table
WHERE cust_id NOT IN (SELECT cust_id FROM order_table WHERE ord_type = ‘furniture’);
အဲဒီလုိ ေရးလုိက္တဲ့ Query ဟာ ၃ နာရီနီးပါး ၾကာတဲ့အထိ မၿပီးႏုိင္လုိ႕ စာေရးသူကို အပူကပ္ျခင္း ျဖစ္၏။ ဘာျဖစ္သနည္း အေျဖရွာေသာ္ ...
ကုမၸဏီသည္ ပရိေဘာဂ အမွာစာ အမ်ားအျပား လက္ခံရရွိခဲ့ရာ Sub-query မွ Row အေျမာက္အမ်ားကုိ ထုတ္ေပးေလသည္။ Row ၃ ေသာင္းေက်ာ္တဲ့။ Customer Table တြင္လဲ Row အမ်ားအျပား ရွိေပလိမ့္မည္။ ယခု ေဆြးေႏြးခ်က္တြင္ Customer Table ၏ Size မွာ အေရးမႀကီးပါ။ Query Optimizer သည္ Sub-query မွ constant results ကုိ ထုတ္ေပးေၾကာင္း သိသျဖင့္ Sub-query ကုိ တစ္ႀကိမ္သာ Run မည္ပဲထား၊ Customer Table မွ Row တစ္ေၾကာင္းစီ (cust_id တစ္ခုစီ) အား Sub-query မွ ေပးေသာ Row ၃ ေသာင္းေက်ာ္တြင္ ပါ၊ မပါကုိ စိစစ္ရန္မွာ လြယ္ကူေသာ အလုပ္ မဟုတ္ေခ်။ အဘယ္ေၾကာင့္ဆုိေသာ္ တၿပိဳင္နက္ အသံုးျပဳသူ အေျမာက္အမ်ားရွိတတ္ေသာ Database Server တြင္ အသံုးျပဳသူတစ္ေယာက္ (Query တစ္ခု) အတြက္ ခြဲေ၀ေပးေသာ ပင္မ မွတ္ဥာဏ္ (Primary Memory or RAM) ပမာဏသည္ အကန္႕အသတ္ ရွိသည့္အျပင္ Order Table တြင္ cust_id ျဖင့္ index တစ္ခု မရွိႏုိင္ျခင္းေၾကာင့္ ျဖစ္သည္။
မွတ္ခ်က္ ။ ။ စာျပန္ဖတ္ၾကည့္ရာ NOT IN ျဖင့္ေရးလွ်င္ Sub-query ကုိ အႀကိမ္ႀကိမ္ run လိမ့္မည္ျဖစ္ၿပီး cust_id ျဖင့္ index ရွိလဲ မသံုးဟု ဆုိသည္။ NOT EXISTS ျဖင့္ ေျပာင္းေရးလွ်င္ေတာ့ အဆုိပါ Index ကုိ သံုးေကာင္း သံုးႏုိင္သည္။ အကယ္၍ Order Table အတြက္ cust_id ျဖင့္ index တစ္ခု၊ ord_type အတြက္ Index တစ္ခုရွိပါက NOT EXISTS ကုိ သံုးျခင္းျဖင့္ အေျဖ ျမန္ျမန္ ရႏုိင္သည္ ဆုိသည္။ သုိ႕ရာတြင္ Transaction Table ျဖစ္ေသာ Order Table ၏ Primary Key မွာ Composite ေသာ္လည္းေကာင္း၊ Order Number ေသာ္လည္းေကာင္း ျဖစ္မည္ ျဖစ္ၿပီး မည္သည့္ စိတ္မွန္ေသာ Database Administrator မွ် ၂ ႏွစ္ေနလုိ႕ တစ္ခါ မလုပ္ေသာ အေရာင္းျမွင့္တင္ေရးအတြက္ အဆုိပါ index မ်ားကုိ ေဆာက္ထားမည္ မဟုတ္။ Index ေဆာက္ျခင္းသည္ Insert ႏွင့္ Update Query မ်ားအတြက္ စြမ္းေဆာင္ရည္ကုိ က်ဆင္းေစသည္။
သုိ႕ျဖစ္၍ Customer Table မွ cust_id တစ္ခုစီအား Sub-query မွ ေပးေသာ Row ၃ ေသာင္းေက်ာ္အတြင္း ပါ၊ မပါကုိ စိစစ္ရန္ cust_id တစ္ခုစီအတြက္ Sub-query အေျဖ ၃ ေသာင္းေက်ာ္ကုိ တစ္ႀကိမ္စီ ဖတ္ရမည္ ျဖစ္သည္။ Sub-query အေျဖ ၃ ေသာင္းေက်ာ္သည္ ပင္မ မွတ္ဥာဏ္အတြင္း မဆန္႕ျပန္ရာ ၄င္းတုိ႕ကုိ အစိတ္စိတ္ပုိင္း၍ အရန္ မွတ္ဥာဏ္ (Auxiliary Memory or Disk) သုိ႕ ေရးကာ ျပန္ျပန္ဖတ္ရမည္။ အရန္ မွတ္ဥာဏ္သို႕ ေရး/ဖတ္ ရသည့္ အလုပ္သည္ ေႏွးေကြးေသာ အလုပ္ျဖစ္သျဖင့္ Customer Table မွ cust_id တစ္ခုအတြက္ CPU Cycle အမ်ားအျပား ၾကာျမင့္မည္။ ထုိၾကာေသာ အလုပ္ကုိ Customer Table အတြင္းမွ ေျမာက္မ်ားစြာေသာ Row မ်ားအတြက္ အခါခါ လုပ္ရရာ ၃ နာရီ နီးပါး ၾကာေသာ္လည္း မၿပီးသည္မွာ မဆန္း။
နည္းလမ္းစဥ္ သရုပ္ခြဲခ်က္ (Algorithm Analysis) အရ Customer Table တြင္ Row n ခု၊ Order Table တြင္ Row m ခု၊ ပင္မ မွတ္ဥာဏ္တြင္ cust_id ေပါင္း p ခု သိမ္းဆည္းထားႏုိင္၍ cust_id ေပါင္း p ခုကုိ ပင္မ မွတ္ဥာဏ္အတြင္းသို႕ ကူးယူရန္ အခ်ိန္ c ၾကာသည္ဆုိပါက ပင္မ မွတ္ဥာဏ္သို႕ ေရးသည့္ လုပ္ငန္းခ်ည္း သက္သက္ အတြက္ O(nmc/p) ၾကာျမင့္မည္။ Sub-query မွ Row ၃ ေသာင္း အေျဖရ၍ Customer Table တြင္ Row ၄ ေသာင္း၊ p သည္ ၄၀၀၀၊ c သည္ ၀.၀၅ စကၠန္႕ ျဖစ္ပါက ပင္မ မွတ္ဥာဏ္ေပၚသို႕ ကူးတင္သည့္ ကိစၥအတြက္ပင္ ၄၀ ၀၀၀ x ၃၀ ၀၀၀၀ x ၀.၀၅ စကၠန္႕ / ၄၀၀၀ = ၁၅၀၀၀ စကၠန္႕ = ၄ နာရီ ၁၀ မိနစ္ (ညတ္ခၽြာျဖား !!!) ၾကာျမင့္မည္။
အဲဒါနဲ႕ ေအာက္ပါ Query နဲ႕ စမ္းၾကည့္ဖုိ႕ စာေရးသူက ေျပာလုိက္ရပါတယ္။
SELECT cust_id, cust_name, cust_add
FROM customer_table
WHERE cust_id IN (SELECT cust_id FROM customer_table
MINUS
SELECT cust_id FROM order_table WHERE ord_type = ‘furniture’);
ခဏနဲ႕ အေျဖရသြားပါသတဲ့။ ဘာမ်ားကြာသြားသလဲ စဥ္းစားၾကည့္ရေအာင္ေနာ္။
ပထမဆံုးအခ်က္က Sub-query ရဲ႕ Results ေသးသြားပါတယ္၊ ဒုတိယအခ်က္ကေတာ့ IN က Customer Table ထဲက cust_id တစ္ခုခ်င္းစီအတြက္ Sub-query Results ထဲမွာ တူတာ တစ္ခုေတြ႕တာနဲ႕ တြက္ခ်က္တာကုိ ရပ္လုိက္လုိ႕ရၿပီး (Short-circuiting လုိ႕ ေခၚပါတယ္) မူလ NOT IN ကေတာ့ Sub-query Results ကုန္ေတာ့မွ ရပ္လုိ႕ရပါတယ္၊ တတိယနဲ႕ ေနာက္ဆံုး အခ်က္ကေတာ့ MINUS က စီၿပီးမွ အလုပ္လုပ္ပါတယ္။ အေသးစိတ္ ရွင္းျပမယ္ေနာ္။
အေပၚက ဥပမာအတုိင္းဆုိလွ်င္ Sub-query မွ ပထမ SELECT Statement ရဲ႕ အေျဖဟာ Row ၄ ေသာင္းရွိၿပီး ဒုတိယ SELECT Statement ရဲ႕ အေျဖဟာ Row ၃ ေသာင္း ရွိပါတယ္။ Referential Integrity Enforcement အရ Order Table ထဲက cust_id ေတြရဲ႕ အစုဟာ Customer Table ထဲက cust_id ေတြရဲ႕ အစုရဲ႕ အစုပုိင္း ျဖစ္တာမုိ႕ Sub-query ရဲ႕ အေျဖက Row ၁ ေသာင္းသာ ရွိေတာ့မွာေပါ့။ ဒါေၾကာင့္ ပင္မ မွတ္ဥာဏ္ထဲကုိ ေရးရသည့္ အခ်ိန္ဟာလဲ ၄၀ ၀၀၀ x ၁၀ ၀၀၀ x ၀.၀၅ စကၠန္႕ / ၄၀၀၀ = ၅၀၀၀ စကၠန္႕ = ၁ နာရီ ၂၄ မိနစ္ေအာက္သာ ရွိေတာ့မွာေပါ့။ အစ္မေတာ္ရဲ႕ ျပႆနာကေတာ့ အေရအတြက္ ကြာတာမုိ႕ မိနစ္ပုိင္းနဲ႕ အေျဖရပါသတဲ့၊ ေကာင္းေလစြ။
Customer Table ထဲက cust_id တစ္ခုခ်င္းစီအတြက္ ပင္မ မွတ္ဥာဏ္ထဲကုိ Sub-query Results ေရးထည့္ၿပီး တူတာရွိ၊ မရွိ တုိက္ၾကည့္ရပါတယ္။ IN ရဲ႕ သေဘာ၊ သဘာ၀က တူတာ တစ္ခု ေတြ႕တာနဲ႕ စစ္တာကုိ ရပ္လုိက္လုိ႕ရပါတယ္။ ပင္မ မွတ္ဥာဏ္ထဲ Sub-query Results အားလံုးကုိ တခ်ိန္ထဲ ထည့္ထားလုိ႕ မရတဲ့အတြက္ p ခုစီ အခါခါထည့္ၿပီး စစ္ေနရာမွာ (p က ၄၀၀၀ ဆုိရင္ Sub-query Results ၁ ေသာင္းကုိ Disk ထဲကေန RAM ေပၚကုိ ၃ ခါခြဲၿပီး ကူးတင္ရပါမယ္။) ရွာေတြ႕သြားရင္ အဲဒီ cust_id အတြက္ ဆက္ထည့္ေပးဖုိ႕ မလုိေတာ့ပါဘူး (ဥပမာ ပထမ ၄၀၀၀ ထဲမွာ ရွာေတြ႕သြားရင္ က်န္တဲ့ ၆၀၀၀ ကုိ RAM ေပၚကုိ ကူးတင္ေပးစရာ မလုိေတာ့ပါဘူး၊ ၂ ခါသက္သာသြားၿပီ)။ ဒါ့အျပင္ ေနာက္ cust_id တစ္ခုအတြက္လဲ လက္ရွိ ထည့္ထားတဲ့ ၄၀၀၀ နဲ႕ ဆက္အလုပ္လုပ္ႏုိင္ပါေသးတယ္ (၃ ခါ သက္သာသြားၿပီ၊ တခါကုိ ၀.၀၅ စကၠန္႕ဆုိေတာ့ ၀.၁၅ စကၠန္႕သက္သာသြားၿပီ)။ NOT IN မွာကေတာ့ အစအဆံုး တုိက္ရတဲ့အတြက္ ဒီလုိလုပ္လုိ႕ မရပါဘူး။
A MINUS B ကုိ တြက္တဲ့အခါမွာ Oracle Database Server က A ကုိ စီ၊ B ကုိ စီၿပီးမွ Sorted File Merging နဲ႕တူတဲ့ နည္းလမ္းစဥ္ကုိ အသံုးျပဳ တြက္ခ်က္တာမုိ႕ စာေရးသူတင္ျပတဲ့ Sub-query ရဲ႕ အခ်ိန္အားျဖင့္ ခက္ခဲမႈ (Time Complexity) ဟာ O(nlog(n) + mlog(m) + m + n) ပဲ ရွိပါတယ္။ (m ႏွင့္ n သည္ Customer Table ရဲ႕ Size ႏွင့္ Order Table မွ မတူညီေသာ cust_id အေရအတြက္တုိ႕ အသီးသီး ျဖစ္သည္။) ဒါေပမဲ့ Customer Table မွာ cust_id ဟာ primary key ျဖစ္လုိ႕ သူ႕ Index ကုိ သံုးမယ္ဆုိရင္ O(mlog(m) + m + n) ပဲ က်န္ပါလိမ့္မယ္။ Cache ရွိမယ္ဆုိရင္ေတာ့ Sub-query ရဲ႕ ကုန္က်စရိတ္ဟာ မရွိသေလာက္ နည္းသြားမွာ ျဖစ္ပါတယ္။
မွတ္ခ်က္ ။ ။ NOT EXISTS ကုိ အသံုးျပဳေရးသားလွ်င္ကား Customer Table မွ cust_id တစ္ခုစီအတြက္ Sub-query တစ္မ်ိဳးစီ တြက္ထုတ္မည္ ျဖစ္သည္။ သုိ႕ရာတြင္ Order Table တြင္ cust_id ျဖင့္ index မရွိႏုိင္ရာ Short-circuiting သံုးႏုိင္ေသာ္လည္း Order Table ကုိ full table scan လုပ္ရမွာပဲ ျဖစ္သည္။ ထုိသုိ႕ဆုိလွ်င္ စာေရးသူ တင္ျပေသာ နည္းလမ္းႏွင့္ ၾကာခ်ိန္တူတူေလာက္ပဲ ျဖစ္မည္။ သုိ႕ရာတြင္ Database Server မ်ားတြင္ Query Results မ်ားကုိ Cache လုပ္ထားတတ္ရာ cust_id တစ္ခုစီအတြက္ Sub-query တစ္မ်ိဳးစီ တြက္ထုတ္ေနသာ နည္းလမ္းသည္ အၿမဲ Cache Miss ျဖစ္ေနၿပီး Sub-query တစ္မ်ိဳးတည္းသာရွိေသာ စာေရးသူ တင္ျပသည့္ နည္းလမ္းမွာကား Cache ကို အက်ိဳးရွိစြာ အသံုးခ်ႏုိင္သျဖင့္ စာေရးသူ တင္ျပေသာ နည္းလမ္းက ပုိမုိေကာင္းမြန္သည္ဟု ဆုိႏုိင္သည္။
Database နည္းပညာဟာ အလုပ္လုပ္ပံု အေသးစိတ္ကို သံုးစြဲသူ ေခါင္းမရႈပ္ရေအာင္ ၀ွက္ထားေပးတယ္ဆုိေပမဲ့ တခါတေလမွာ သူ႕ရဲ႕ Statistics နဲ႕ Query Optimizer Algorithm ဟာ သံုးစြဲသူရဲ႕ Knowledge ကုိ မယွဥ္ႏုိင္တာကုိ ေတြ႕ရပါတယ္။ ဒါေၾကာင့္ သင့္ရဲ႕ Query ကုိ Execute ရာမွာ လိုတာထက္ ပုိၾကာေနၿပီဆုိရင္ သင့္အေနနဲ႕ ၀င္ပါရေတာ့မွာ ျဖစ္ပါတယ္။ System Level Optimization, DBA Level Optimization စတာေတြကို အသံုးျပဳသူတုိင္း ေဆာင္ရြက္ခြင့္ မရၾကပါဘူး။ အဲဒီအခါမ်ိဳးမွာ Query Optimizer ရဲ႕ Query Plan Formulation Logic နဲ႕ အေျခခံ နည္းလမ္းစဥ္ သရုပ္ခြဲပညာတုိ႕နဲ႕ ယဥ္ပါးတဲ့ သံုးစြဲသူမ်ားအေနနဲ႕ အထက္ေဖာ္ျပပါကဲ့သုိ႕ SQL Statement Level Optimization မ်ားကို ေဆာင္ရြက္ႏုိင္ေၾကာင္း တင္ျပလုိက္ရပါသည္။
http://download.oracle.com/docs/html/A86647_01/vmqtune.htm#1004143 ကုိမွီျငမ္းပါသည္။
Sunday, October 11, 2009
ဥာဏ္စမ္းပေဟဠိမ်ားကုိ ကြန္ပ်ဴတာ အသံုးျပဳ ေျဖရွင္းျခင္း
သခ်ၤာဥာဏ္အေပၚတြင္ အေျခခံေသာ ဥာဏ္စမ္းပေဟဠိ၊ စကားအသြားအလာႏွင့္ ဘာသာစကားလွည့္ကြက္အေပၚတြင္ အေျခခံေသာ ဥာဏ္စမ္းပေဟဠိႏွင့္ အၾကားအျမင္ ဗဟုသုတ အေပၚတြင္ အေျခခံသည့္ ဥာဏ္စမ္းပေဟဠိစသည္ျဖင့္ ဥာဏ္စမ္းပေဟဠိ အမ်ိဳးမ်ိဳး ရွိရာ အခ်ိဳ႕ေသာ ပေဟဠိမ်ားသည္ ထည့္သြင္း စဥ္းစားရမည့္ ျဖစ္ႏုိင္ေသာ အေျဖ အေရအတြက္ အတုိင္းအဆမရွိ မ်ားျပားမႈအေပၚတြင္ အေျခခံေလသည္။ ေရွးက လူအားျဖင့္သာ ဥာဏ္စမ္းပေဟဠိမ်ားကို အေျဖထုတ္ခဲ့ၾကရာတြင္ ျဖစ္ႏုိင္ေသာ အေျဖ အလြန္မ်ားျပားေသာ ပေဟဠိမ်ားမွာ အေျဖကုိ ႀကိဳတင္ မသိသူ ေျဖဆုိသူတုိ႕ လက္ေျမွာက္အရႈံးေပးရသည္သာ မ်ားေသာ္လည္း ယေန႕ကြန္ပ်ဴတာေခတ္တြင္မူ ၄င္းတုိ႕ကုိ အလြယ္တကူ အေျဖထုတ္ႏုိင္ၿပီ ျဖစ္သည္။ ယခုေဆာင္းပါးတြင္ ၄င္းပေဟဠိ ၂ ပုဒ္ကုိ ကြန္ပ်ဴတာ အသံုးျပဳ ေျဖရွင္းပံုကို ေဖာ္ျပမည္ျဖစ္သည္။
ပထမ ပုစၧာမွာ ဤသုိ႕ျဖစ္သည္။ လယ္သမားတစ္ေယာက္သည္ သူ၏ၿခံတြင္ ေမြးျမဴရန္အတြက္ ႏြား၊ ၀က္ႏွင့္ ၾကက္ စုစုေပါင္း အေကာင္ ၁၀၀ ၀ယ္လုိသည္။ ပုိက္ဆံလဲ ၁၀၀ က်ပ္သာရွိသည္။ ၃ မ်ိဳးလံုးလဲ ေမြးလုိေသးသည္။ ႏြားတစ္ေကာင္ ၁၀ က်ပ္၊ ၀က္တစ္ေကာင္ ၃ က်ပ္ႏွင့္ ၾကက္တစ္ေကာင္ ၅ မူး (၀.၅၀ က်ပ္) ျဖစ္ေသာ္ အေကာင္ ၁၀၀ ရေအာင္ ေငြ ၁၀၀ ႏွင့္ ဘယ္လုိ ၀ယ္မည္နည္း။ တနည္းအားျဖင့္ မသိကိန္း ၃ လံုးပါ၊ တၿပိဳင္နက္ ညီမွ်ျခင္း ၂ ေၾကာင္း ပုစၧာျဖစ္သည္။ သီ၀ရီအရ အေျဖ မရွိ၊ တစ္ခုတည္းသာ၊ အမ်ားအျပား ရွိႏုိင္ေသာ ပုစၧာအမ်ိဳးအစားလဲ ျဖစ္သည္။ တၿပိဳင္နက္ ညီမွ်ျခင္း အမ်ားအျပားပါ တၿပိဳင္နက္ ညီမွ်ျခင္း စနစ္ (System of Linear Equations) တစ္ခုကုိ မက္ထရစ္ ညီမွ်ျခင္း တစ္ေၾကာင္းျဖင့္ ေဖၚျပႏုိင္ရာ လွန္မက္ထရစ္ေယာင္ (Pseudo Inverse) ကုိအသံုးျပဳၿပီး ျဖစ္ႏုိင္သည့္ အေျဖမ်ားကုိ အလြယ္တကူ တြက္ထုတ္ႏုိင္ပါသည္။
၄င္း သခ်ၤာနည္း၏ အားနည္းခ်က္မွာ ၄င္းနည္းစနစ္သည္ ကိန္းစစ္ ေျမွာက္ေဖာ္ကိန္း (Real Number Coefficients) မ်ားအတြက္ နည္းစနစ္ ျဖစ္ေနသျဖင့္ ကိန္းစစ္ အေျဖတြဲ အမ်ားအျပား ထြက္လာႏုိင္ျခင္းပင္ ျဖစ္သည္။ (Matlab မရွိသျဖင့္ စာေရးသူ မစမ္းၾကည့္ပါ။) ေမြးရန္ ၀ယ္ေသာ ႏြား၊ ၀က္၊ ၾကက္တုိ႕ကုိ တ၀က္၊ တစိတ္ စသျဖင့္ ၀ယ္မရႏိုင္ပါ (တ၀က္၀က္ရင္ ေသကုန္မွာေပါ့)။ တနည္းအားျဖင့္ အေျဖသည္ အေပါင္း ကိန္းျပည့္ ၃ ခု ျဖစ္ရမည္။ ေပါင္းလွ်င္ ၁၀၀ ရေသာ အေပါင္းကိန္းျပည့္ မ်ားစြာရွိရာ ကြန္ပ်ဴတာ အကူအညီမယူေသာ သခ်ၤာသီးသန္႕သမားတုိ႕အတြက္ ခက္ခဲေသာ ပုစၧာျဖစ္သည္။ ကြန္ပ်ဴတာ ပညာရွင္ တစ္ဦးသည္ ဤပုစၧာကို မ်က္ကန္းနည္း (Brute Force Method) အသံုးျပဳျခင္းျဖင့္ အလြယ္တကူ ေျဖရွင္းႏုိင္သည္။ ႏြား အေရအတြက္ အမ်ိဳးမ်ိဳး၊ ၀က္အေရအတြက္ အမ်ိဳးမ်ိဳးႏွင့္ ၾကက္အေရအတြက္ အမ်ိဳးမ်ိဳးတုိ႕အတြက္ အစီအစဥ္ငယ္တစ္ခုကုိ လွ်င္ျမန္စြာေရးသားၿပီး ၄င္းတို႕ ေပါင္းလဒ္၊ ၄င္းတုိ႕၏ က်သင့္ေငြ တုိ႕ကို တြက္ခ်က္ကာ ႏွစ္ခုလံုး ၁၀၀ ျဖစ္ေသာ အေျဖကုိ ထုတ္ေပးရံုသာျဖစ္သည္။ (အေျဖမွာ ႏြား ၅၊ ၀က္ ၁၊ ၾကက္ ၉၄ ျဖစ္သည္။)
မွတ္ခ်က္ ။ ။ ယခု ပုစၧာသာလွ်င္ လြယ္ကူျခင္း ျဖစ္သည္။ ကိန္းျပည့္ မသိကိန္း အမ်ားအျပားႏွင့္ ညီမွ်ျခင္း အေရအတြက္ အနည္းငယ္ (ညီမွ်ျခင္း အေရအတြက္က မသိကိန္းအေရအတြက္ထက္ ပိုနည္းေနေသာ) ပုစၧာပံုစံကြဲတစ္ခုကုိ စစ္ဆင္ေရး သုေတသန (Operation Research) ဘာသာရပ္တြင္ Integer Linear Programming (ILP) အမည္ႏွင့္ေတြ႕ရၿပီး ခက္ခဲေသာ ပုစၧာျဖစ္သည္။
ဒုတိယ ပုစၧာတြင္မူကား မ်က္ကန္းနည္း အသံုးျပဳရန္ အဆင္မေျပေတာ့ေပ။ ပုစၧာမွာ ဤသို႕ျဖစ္သည္။ ၁ မွ ၉ အထိ ဂဏန္း ၉ လံုး (တစ္လံုးကုိ တစ္ႀကိမ္စီသာပါ၀င္ေသာ) သန္းရာဂဏန္းရွိ ကိန္းတစ္လံုးသည္ ၉ ႏွင့္ စားလုိ႕ ျပတ္သည္။ အဆုိပါ ကိန္းမွ ခုဂဏန္းကုိ ဖယ္ထုတ္လုိက္ေသာ ဂဏန္း ၈ လံုးပါ ကိန္း (၁၀ ႏွင့္စားလွ်င္ ရေသာ ရလဒ္) သည္ ၈ ႏွင့္ စားလုိ႕ ျပတ္သည္။ တဖန္ ထုိကိန္းမွ ခုဂဏန္းကုိ ဖယ္ထုတ္ပါက က်န္ေသာ ကိန္းသည္ ၇ ႏွင့္ စားလုိ႕ ျပတ္သည္။ ေနာက္ဆံုး ၁ လံုးသာ က်န္သည္အထိ ဤနည္းအတုိင္း တစ္လံုးဖယ္တုိင္း က်န္ေသာ ဂဏန္းအေရအတြက္ႏွင့္ စားလုိ႕ ျပတ္ရသည္။ တနည္းအားျဖင့္ ဘယ္ဘက္ဆံုး x လံုးကုိ x ႏွင့္စား၍ ျပတ္သည္။ ထုိကိန္းကို ရွာပါ။ မ်က္ကန္းနည္းႏွင့္ တြက္လွ်င္ သန္းတစ္ရာ (၁၀၀ ၀၀၀ ၀၀၀) မွ ကုိးရာ ကုိးဆယ့္ ကုိးသန္း ကုိးသိန္း ကုိးေသာင္း ကုိးေထာင္ ကုိးရာ ကုိးဆယ့္ ကုိး (၉၉၉ ၉၉၉ ၉၉၉) အထိ ကိန္းေပါင္း သန္း ၉၀၀ နီးပါးကုိ ၁ မွ ၉ အထိ ကိန္းမ်ားျဖင့္ စားလုိ႕ ျပတ္မျပတ္ တြက္ထုတ္ (ဂဏန္းမ်ား ထပ္ေနမေန စစ္) ရမည္ ျဖစ္သျဖင့္ သိပ္အဆင္မေျပေသာ နည္းျဖစ္သည္။ (၁ မွ ၉ အထိ စားျပတ္မျပတ္ တစ္ခါတြက္လွ်င္ ၁ စကၠန္႕၏ တစ္သန္းပံု တစ္ပံုသာ ၾကာသည္ထား … အနည္းဆံုး စကၠန္႕ ၉၀၀ = ၁၅ မိနစ္မွ် ၾကာသြားႏုိင္သည္။ မစမ္းၾကည့္ပါ။)
အမွန္မွာ ၄င္းသည္ ၁ မွ ၉ အထိ ဂဏန္း ၉ လံုးကို ၉ ေနရာတြင္ စီခုိင္းေသာ (စီၿပီးလွ်င္ စစ္ခုိင္းေသာ) အစီ ပုစၧာ (Permutation Problem) သာျဖစ္သည္။ အစီ ပံုေသနည္းအရ ျဖစ္ႏုိင္သည့္ ကိန္းေပါင္း ၉ x ၈ x … x ၁ = ၃၆၂၈၈၀ သာ ရွိသည္။ အကယ္၍ ကုန္က်စရိတ္နည္းေသာ အစီ နည္းလမ္းစဥ္သာ ရွိခဲ့လွ်င္ ပြဲျပတ္ၿပီ ျဖစ္သည္။ (ကံဆုိးသည္မွာ အထူးတည္ေဆာက္ထားေသာ ကြန္ပ်ဴတာမ်ားမွ အပ မရွိ။) သုိ႕ရာတြင္ ၁၅ မိနစ္ထက္ေတာ့ ျမန္မည္မွာ ေသခ်ာပါသည္။ (မစမ္းၾကည့္ပါ။) ၂ နည္းစလံုးသည္ လူအားျဖင့္ တြက္ထုတ္ရန္ မျဖစ္ႏုိင္သည္မွာကား ေသခ်ာေပသည္။
အဆုိပါ ပုစၧာကုိ ျပင္ပ သခ်ၤာဗဟုသုတမ်ားျဖင့္ အားျဖည့္ကာ ပုိမုိေကာင္းမြန္ေသာ အစီအစဥ္ တစ္ရပ္ကုိ ဆြဲသားႏုိင္ပါသည္။ အသံုးျပဳေသာ သခ်ၤာနည္းစနစ္မွာ ကိန္းတစ္လံုးကုိ ၁ မွ ၉ အထိ ဂဏန္းမ်ားႏွင့္ စားလွ်င္ ရမည့္ စားၾကြင္းကုိ ရွာေသာ နည္းလမ္းမ်ားျဖစ္သည္။ အစီအစဥ္ မဆြဲမီ ျဖစ္ႏုိင္ေသာ ကိန္းမ်ားကို ေအာက္ပါအတုိင္း ဆင္ျခင္သည္။ (x ေနရာ = အေျဖကိန္းကုိ ဘယ္ဘက္မွ ေရတြက္လွ်င္ x ေနရာ)
- ကိန္းတစ္လံုးကုိ ၉ ႏွင့္ စားျပတ္၊ မျပတ္ သိရန္အတြက္ အဆုိပါကိန္းတြင္ ပါ၀င္ေသာ ဂဏန္းမ်ား၏ မူလတန္ဖုိးမ်ားေပါင္းလဒ္ကုိ ၉ ျဖင့္ စားၾကည့္ႏုိင္သည္ (သုိ႕မဟုတ္ ေပါင္းေနရင္း ၉ ျပည့္လွ်င္ ဖယ္ဖယ္ထားခဲ့ႏုိင္သည္။) ပါ၀င္ရမည့္ ဂဏန္းမ်ားမွာ ၁ မွ ၉ အထိ ဂဏန္း ၉ လံုးျဖစ္သည္။ ၁ + ၈ = ၂ + ၇ = ၃ + ၆ = ၄+ ၅ = ၉ ျဖစ္ရာ … ၁ မွ ၉ အထိ ဂဏန္းအားလံုး (တစ္လံုးကုိ တစ္ႀကိမ္စီသာ ပါ၀င္ေသာ) ကိန္းသည္ ၉ ႏွင့္ အလိုအေလ်ာက္ စားလုိ႕ ျပတ္သည္။ ထည့္သြင္းစဥ္းစားရန္မလုိ။ ၁ မွ ၉ အထိ ဂဏန္း ၉ လံုးကုိ ေရွ႕ ၈ ေနရာတြင္သာ ေနရာခ် စမ္းသပ္ၾကည့္ၿပီး ေျပလည္ပါက က်န္ခဲ့ေသာ တစ္လံုးျဖင့္ ၉ ေနရာကို အလြယ္တကူ ျဖည့္ႏုိင္သည္။
- ကိန္းတစ္လံုးကုိ ၂ (၄ ႏွင့္ ၈) တုိ႕ႏွင့္ စားျပတ္၊ မျပတ္ သိႏုိင္ရန္အတြက္ ညာဘက္ဆံုး ၁ လံုး (၂ လံုးႏွင့္ ၃ လံုး) သည္ ၂ (၄ ႏွင့္ ၈) ျဖင့္ စား၍ ျပတ္ရသည္။ ထုိ႕ေၾကာင့္ ၂ ေနရာတြင္ စံုကိန္းတစ္လံုး (၃၄ ေနရာတြင္ ၄ ႏွင့္စားျပတ္ေသာ ဆယ္ဂဏန္း တစ္လံုး၊ ၆၇၈ ေနရာတြင္ ၈ ႏွင့္ စားျပတ္ေသာ ရာဂဏန္း တစ္လံုး) ကုိ ျဖည့္သြင္းရမည္။
- ကိန္းတစ္လံုးကုိ ၃ ႏွင့္ စားျပတ္၊ မျပတ္ သိႏုိင္ရန္အတြက္ အဆုိပါကိန္းတြင္ ပါ၀င္ေသာ ဂဏန္းမ်ား၏ မူလတန္ဖုိးမ်ား ေပါင္းလဒ္ကုိ ၃ ျဖင့္ စားၾကည့္ႏိုင္သည္။ ၄င္းကုိ အေျခခံ၍ ၂ ေနရာရွိ ဂဏန္းႏွင့္ ၃ ေနရာရွိဂဏန္းတုိ႕ကို အေျခခံ၍ ၁ ေနရာရွိ ဂဏန္းကို တြက္ခ်က္ႏုိင္သည္။၂ ေနရာတြင္ စံုကိန္းတစ္လံုး ေသခ်ာေပါက္ရွိၿပီး ၃၄ ေနရာတြင္ ၄ ႏွင့္ စားျပတ္ေသာ ဆယ္ဂဏန္း တစ္လံုး ေသခ်ာေပါက္ ရွိမည္ျဖစ္သျဖင့္ ၁၂၃၄ ေနရာရွိ ဂဏန္းမ်ား ျဖစ္ႏုိင္ေျခသည္ ၉ x ၈ x ၇ x ၆ = ၃၀၂၄ မွ ၃ × သုညမဟုတ္ေသာ ၁၀ ေအာက္ စံုကိန္း (၂၊ ၄၊ ၆၊ ၈) အေရအတြက္ x ၄ ႏွင့္စားျပတ္ေသာ ဆယ္ဂဏန္း အေရအတြက္ (၃ × ၄ x ၂၂ = ၂၆၄) သုိ႕က်ဆင္းသြားမည္။ (စာေရးသူ စမ္းသပ္ရာတြင္ ဤနည္းကို မသံုးပဲ ကိန္း ၉၉၀ လံုးကို ၃ ႏွင့္စားျပတ္၊ မျပတ္ စစ္ထားပါသည္။)
- ကိန္းတစ္လံုးကုိ ၅ ႏွင့္ စားျပတ္ရန္ အဆုိပါကိန္းသည္ ၀ (သုည) သုိ႕မဟုတ္ ၅ ႏွင့္ ဆံုးရမည္ျဖစ္သည္။ ၀ (သုည) ကုိ ပုစၧာအရ သံုးခြင့္မရွိသျဖင့္ ၅ ေနရာတြင္ ရွိမည့္ ဂဏန္းမွာ ၅ သာလွ်င္ ျဖစ္သည္။
အထက္ေဖာ္ျပပါ ထုိးထြင္းသိမ်ားျဖင့္ အစီအစဥ္တစ္ရပ္ကုိ အျမန္ ဆြဲသား တြက္ခ်က္ခဲ့ရာ ဂဏန္းတြဲ အေရအတြက္ ၂၄၁၉၂၀ ကုိသာ စိစစ္ခဲ့ၿပီး (၃၆၂၈၈၀ ႏွင့္ႏိႈင္းစာလွ်င္ ၃ ပံု ၂ ပံုခန္႕) ၆ ေနရာ၊ ၇ ေနရာတုိ႕တြင္ ၀ (သုည) ပါ၀င္ႏုိင္ၿပီး ဂဏန္း တစ္မ်ိဳးစီကုိ တစ္ႀကိမ္ထက္ ပိုမုိပါ၀င္ႏုိင္ေသာ္လည္း ဘယ္ဘက္ဆံုး x လံုးကုိ x ႏွင့္စား၍ ျပတ္ေသာ ကိန္း ၄၆၃ လံုးကုိ ရရွိခဲ့သည္။ ၄င္းတုိ႕ကုိ ပါ၀င္ေသာ ဂဏန္းမ်ား ၀ (သုည) ျဖစ္၊ မျဖစ္ႏွင့္ ထပ္၊ မထပ္ စစ္ေဆး စစ္ထုတ္ျခင္းျဖင့္ အေျဖကို ရေလေတာ့သည္။ (အေျဖမွာ ၃၈၁ ၆၅၄ ၇၂၉ ျဖစ္သည္။)
ေရႊပြဲလာအေပါင္း ျဖစ္ႏုိင္ေျခ ေထာင္ေသာင္းခ်ီသည့္ ပုစၧာမ်ားကို အလြယ္တကူ အေျဖထုတ္ႏုိင္ၾကပါေစ။
Sunday, August 9, 2009
Quick Sort ကုိ အသံုးျပဳၿပီး Sorting စီျခင္း
ေလာကအလွ အြန္လုိင္းမဂၢဇင္းတြင္ ေဖာ္ျပခဲ့ဖူးေသာ ေဆာင္းပါးကုိ ျပန္လည္ေဖာ္ျပျခင္း ျဖစ္ပါသည္။
ကြန္ပ်ဴတာ သိပၸံ (Computer Science) ေလ့လာသူေတြနဲ႕ သတင္းနည္းပညာ (IT) ေလ့လာသူေတြအတြက္ အစီအစဥ္ဆြဲနည္း (Programming) သင္ခန္းစာေတြမွာ မပါမျဖစ္ကေတာ့ အခ်က္အလက္မ်ားကုိ စီျခင္း (Sorting) အစီအစဥ္ပါပဲ။ Sorting စီတဲ့ နည္းလမ္းစဥ္ (Algorithm) အမ်ိဳးေပါင္း ေျမာက္မ်ားစြာ ရွိတဲ့အထဲက Bubble Sort, Counting Sort, Insertion Sort, Selection Sort နဲ႕ Quick Sort တုိ႕ဟာ ထင္ရွားပါတယ္။ (စာေရးသူ အႀကိဳက္ဆံုးကေတာ့ Selection Sort ျဖစ္ၿပီး အေၾကာင္းရင္းကေတာ့ နားလည္ရလြယ္လြန္းလုိ႕ ျဖစ္ပါတယ္။) ဒါေပမဲ့ လက္ေတြ႕ဘ၀မွာ အသံုး၀င္တာကေတာ့ နားလည္ရခက္၊ ေရးရတာ လက္၀င္တဲ့ Quick Sort ေလ။ ေရးလုိက္ၾကတဲ့ အစီအစဥ္ေတြတုိင္းမွာ စီစရာ (object, data type) တစ္မ်ိဳး ေပၚလာတုိင္း Quick Sort ကုိ တစ္ခါ ထထ ေရးရမယ္ ဆုိတာကေတာ့ လြန္လြန္းပါတယ္။ ဒါေၾကာင့္ C/C++ စံသတ္မွတ္ခ်က္မွာ Array အားလံုးကို စီႏုိင္ဖုိ႕ qsort ဆုိတဲ့ function ပါေနတာ ျဖစ္ပါတယ္။ ဒီေဆာင္းပါးမွာ အဲဒီ qsort ကုိ အသံုးျပဳနည္းကို ေရးသားေပးမွာ ျဖစ္ပါတယ္။
qsort ရဲ႕ သတ္မွတ္ခ်က္မွာ အစီအစဥ္ေရးသားသူ (programmer) ဒါမွမဟုတ္ ကုဒ္ဒါကို ၿခိမ္းေျခာက္ေနတာကေတာ့ pointer ေတြပါပဲ။ ရုိးရုိး Data Pointer ေတြတင္မကပဲ Function Pointer ႀကီးပါ ပါေနေတာ့ Pointer ဆုိရင္ ေက်ာစိမ့္ေနၾကလူေတြ လန္႕ကုန္တာ မဆန္းပါဘူး။ ဒါေပမဲ့ အေက်ာသိရင္ လြယ္လြယ္ကေလးပါ။ qsort ရဲ႕ အဓိပၸါယ္ သတ္မွတ္ခ်က္ကို အရင္ၾကည့္ရေအာင္ေနာ္။
void qsort ( void * base, size_t num, size_t size, int ( * comparator ) ( const void *, const void * ) );
ပထမဆံုး return type ကေတာ့ ဒီ function ဟာ return မျပန္ပါဘူးလုိ႕ အဓိပၸါယ္ရပါတယ္။ ဆုိလုိတာက ေပးလိုက္တဲ့ array ကုိ စီပဲ စီေပးမယ္။ ဘာ ဂဏန္းမွ တြက္ၿပီး အေျဖမထုတ္ေပးပါဘူးေပါ့။
ပထမဆံုး parameter က စီရမဲ့ array ရဲ႕ ပထမဆံုးအကြက္ရဲ႕ လိပ္စာ (address) ပါ။ အမ်ားေၾကာက္တဲ့ pointer ေပါ့။ Array အားလံုးဟာ Fix Pointer ေတြ ျဖစ္တဲ့အတြက္ စိတ္ခ်လက္ခ်ပဲ array name ကုိ ျဖည့္လုိက္လုိ႕ရပါတယ္။
ဒုတိယ parameter ကေတာ့ Array ရဲ႕ အရြယ္အစား (size) ျဖစ္ပါတယ္။ C/C++ မွာ Array ရဲ႕ size ကုိ compile-time/run-time check မလုပ္ပဲ ကုဒ္ဒါကပဲ အၿမဲ ကုိင္တြယ္ ႀကီးၾကပ္ရတာမုိ႕ ဒါကို ထည့္ေပးရတာပါ။ ႏုိ႕မုိ႕ရင္ ဘယ္ႏွခု စီရမလဲ မသိပဲ ျဖစ္ေနမယ္ေလ။ ကုိယ့္ Array မွာ Element ၁၀ ခုပါရင္ 10 လုိ႕ထည့္ေပါ့။ Variable တစ္ခုခု ထည့္လုိ႕လဲ ရပါတယ္။
တတိယ parameter ကေတာ့ စီခ်င္တဲ့ Array Element တစ္ခုခ်င္းရဲ႕ အရြယ္အစားေပါ့။ အဲဒါမွ အဲဒီ မွတ္ဥာဏ္တံုးႀကီး (memory block) ေတြကို ေရႊ႕လုိ႕ရမယ္ေလ။ ဒါလဲ မခက္ပါဘူး။ sizeof(element) လုိ႕ ေပးလုိက္ရင္ရပါတယ္။
စတုတၳနဲ႕ ေနာက္ဆံုး parameter ကေတာ့ နည္းနည္း ရွင္းျပရ လက္၀င္ပါတယ္။ ဒါဟာ Function Pointer ႀကီးျဖစ္ပါတယ္။ ကုိယ့္ဘာသာကုိယ္ သတ္မွတ္ထားတဲ့ Element ေတြကို ႏိႈင္းယွဥ္ခ်င္ရင္ ဒီ Function နဲ႕ တြက္ဆုိၿပီး ေျပာရတဲ့ သေဘာပါ။ (ေနာက္တမ်ိဳးေျပာရရင္ အဲဒီ Function ႀကီးကုိ qsort ကေန လွမ္းေခၚမွာ ျဖစ္ပါတယ္။ အဲဒီ Function ႀကီးက qsort ဆီကုိ ေရွ႕ကေကာင္က ငယ္ရင္ အႏႈတ္ကိန္း၊ တူရင္ သုည၊ ႀကီးရင္ အေပါင္းကိန္း တစ္ခုခု return ျပန္ရပါမယ္။) အဲဒီ Function ႀကီးရဲ႕ ပံုစံကလဲ
int function_name(const void* a, const void* b);
ပဲျဖစ္ရပါမယ္။ ပုိနားလည္လြယ္ေအာင္ ဥပမာေလးနဲ႕ ၾကည့္ရေအာင္ေနာ္။
ဥပမာ ၀န္ထမ္းေတြကို လစာ အမ်ားဆံုးကေန အနည္းဆံုးကို စီၿပီးသား အစီရင္ခံစာထုတ္ေပးတဲ့ အစီအစဥ္ကုိ လုိခ်င္တယ္။ တကယ္လုိ႕ လစာတူေနရင္ လုပ္သက္ရင့္တဲ့လူကုိ ေရွ႕မွာ ထားခ်င္တယ္ ဆုိပါစုိ႕။ ဒါဆုိရင္ ၀န္ထမ္းေတြရဲ႕ အခ်က္အလက္ေတြကုိ သိမ္းဖုိ႕ class တစ္ခု ေဆာက္ရပါမယ္။
class employee{
int experience; //in year
float salary; //in kyat
/* Blar Blar Blar */
public:
bool operator < (employee &e) {
If(this->salary == e.salary) return (this->experience < e.experience);
else return (this->salary < e.salary);
}
void my_emp_function(void) { }
/* More Blar Blar Blar */
};
ေပါ့။ အဲဒီ Class မွာ လစာရယ္၊ လုပ္သက္ရယ္က Private Member ေတြ ျဖစ္ၿပီးေတာ့ အျပင္ကေန ၀န္ထမ္းေတြကို ႏိႈင္းယွဥ္ႏုိင္ဖုိ႕ operator '<' ကုိ overload လုပ္ထားတဲ့ Function တစ္ခုပါပါတယ္။ ဒါေပမဲ့ qsort ထဲကုိ အဲဒီ function ကုိ ထည့္လုိက္လုိ႕မရတဲ့အတြက္ (qsort က လုိခ်င္တဲ့ ပံုစံနဲ႕ operator '<' ရဲ႕ ပံုစံ Syntax မတူတဲ့အတြက္) qsort အတြက္ Function ကုိ ဒီလိုေရးရပါမယ္။
int employee_comparer(const void* a, const void* b) {
employee *temp_e = (employee*) a; //type cast from void*
employee *temp_f = (employee*) b; //to employee*
if((*temp_e) < (*temp_f)) return -1;
else return 1;
}
ေရးထားတဲ့ Function ရဲ႕ ပထမ ၂ ေၾကာင္းကေတာ့ ဘာ type information မွမပါပဲ qsort က ရမ္းသန္းမွန္းသန္း ပုိ႕လႊြတ္လုိက္တဲ့ Pointer ၂ ခုကို employee Pointer ျဖစ္ေအာင္ ေျပာင္းယူတာပါ။ အဲဒီမွာ တခ်က္သတိထားဖုိ႕က အဲဒီလုိ ေျပာင္းယူၿပီးတာေတာင္ temp_e နဲ႕ temp_f က Pointer ပဲ ရွိပါေသးတယ္။ ဒါေၾကာင့္ သူတုိ႕ကုိ သံုးတဲ့အခါမွာ Data of လုိ႕ အဓိပၸါယ္ရတဲ့ '*' ေလးကို အၿမဲထည့္ရပါမယ္။ (တကယ္လုိ႕ သူတို႕ထဲက function ေတြ ေခၚမယ္ဆုိရင္လဲ operator '.' ကုိ မသံုးပဲ operator '->' ကုိ ဒီလုိေလး temp_e->my_emp_function() ဆုိၿပီးေတာ့ သံုးေပးရပါမယ္။) အဲဒီ '*' ေလးကို ထည့္ၿပီး operator '>' နဲ႕ ႏိႈင္းယွဥ္လုိ႕ရလာတဲ့ အေျဖေပၚမူတည္ၿပီး -1 သုိ႕မဟုတ္ +1 ကို qsort အတြက္ return ျပန္ေပးလုိက္ရပါမယ္။
ဒီ Function ေလးေရးလုိ႕ အခ်ိဳးေျပသြားၿပီဆုိရင္ေတာ့ qsort ကုိ စိတ္ေအးခ်မ္းသာ အသံုးျပဳႏုိင္ပါၿပီ။ (employee ရဲ႕ private member ေတြကို accessor method ေတြကေနတဆင့္ ေခၚထားတာ သတိျပဳပါ။ တကယ္တမ္း ေရးတဲ့အခါက်ေတာ့ သတိလက္လြတ္ ဒီတုိင္း ေရးမိတတ္ပါတယ္။ အဲဒီလုိေရးခ်င္ရင္ေတာ့လဲ friend လုပ္လုိက္ေပါ့ဗ်ာ၊ ေနာ။) ေအာက္မွာက main Function ပါ။
/* preprocessor Yada Yada Yada */
void main(void)
{
employee myEmployeeArray[NUM_OF_EMPLOYEE];
/* input data into myEmployeeArray */
qsort(myEmployeeArray, NUM_OF_EMPLOYEE, sizeof(employee), employee_comparer);
/* output sorted myEmployeeArray */
}
qsort ကုိ လြယ္လြယ္ေခၚၿပီး ကုဒ္ဒါအေပါင္း သက္သာၾကပါေစေၾကာင္း …
Wednesday, July 15, 2009
ျမန္မာစာစနစ္မ်ား၏ ေနာက္ခံကား
ယခုအခါ ကြန္ပ်ဴတာသံုး ျမန္မာစာ စနစ္အမ်ိဳးမ်ိဳး ေပၚထြန္းလွ်က္ ရွိသည္။ ၄င္းစနစ္အသီးသီး၏ ေပၚေပါက္လာရျခင္း အေၾကာင္းရင္းႏွင့္ သေဘာသဘာ၀မ်ားမွာ တခုႏွင့္ တခု မတူညီပဲ ကြဲျပားလွ်က္ရွိသည္။ Unicode 5.1 တြင္ ျမန္မာအကၡရာမ်ား၏ ေနရာသတ္မွတ္ခ်က္ တည္ၿငိမ္လာၿပီျဖစ္ရာ အခ်က္အလက္မ်ား မွ်ေ၀ႏုိင္ရန္၊ ျမန္မာဘာသာျဖင့္ ေရးသားထားေသာစာမ်ားကုိ အကၡရာ၀လိစီရန္ႏွင့္ ရွာေဖြႏုိင္ရန္ ၄င္းေနရာသတ္မွတ္ခ်က္မ်ားအတုိင္း ေျပာင္းလဲ သံုးစြဲသင့္ၿပီျဖစ္သည္။ လက္ရွိစနစ္မ်ား၏ ေနာက္ခံကားကုိ နားလည္သေဘာေပါက္မွ ၄င္းစနစ္မ်ားအား အသံုးျပဳလွ်က္ရွိသူတုိ႕ကုိ Unicode အဆင့္မီစနစ္မ်ားသုိ႕ ေခ်ာေခ်ာေမြ႕ေမြ႕ ေျပာင္းလဲႏုိင္ေစမည္ျဖစ္ရာ ဤစာတမ္းငယ္တြင္ လက္ရွိ ျမန္မာစာစနစ္မ်ား၏ သေဘာသဘာ၀ကုိ Information Systems Practitioner တစ္ဦး၏အျမင္မွ ေဆြးေႏြးတင္ျပမည္ ျဖစ္သည္။
နိဒါန္း
ယခုအခါ ကြန္ပ်ဴတာကုိ အသံုးျပဳရာတြင္ အဂၤလိပ္၊ ဂ်ာမန္၊ ျပင္သစ္စေသာ အေနာက္တုိင္း ဘာသာစကားမ်ားသာမကပဲ တရုတ္၊ ကုိရီးယား၊ ဂ်ပန္ စေသာ အေရွ႕တုိင္း ဘာသာစကားမ်ားျဖင့္လဲ လြယ္ကူစြာ အသံုးျပဳႏုိင္ၾကၿပီ ျဖစ္သည္။ ဤကဲ့သုိ႕ မိခင္ဘာသာစကားမ်ားျဖင့္ ကြန္ပ်ဴတာကုိ အသံုးျပဳႏုိင္ရျခင္းမွာ ဘာသာစကားအမ်ားအျပား၏ အကၡရာမ်ားကုိ code-range တစ္ခုအတြင္းတြင္ ေနရာခ်ထားေပးေသာ Unicode ေခၚ စံႏႈန္းတစ္ရပ္ကုိ အမ်ားသေဘာတူ သတ္မွတ္ႏုိင္ခဲ့ေသာေၾကာင့္ ျဖစ္သည္။ အဆုိပါ စံႏႈန္းအတြင္းတြင္ ျမန္မာအကၡရာမ်ားအတြက္ code-range ကုိ သတ္မွတ္ႏုိင္ခဲ့ေသာ္လည္း ႏွစ္ေပါင္းမ်ားစြာၾကာသည့္တုိင္ေအာင္ အေသးစိတ္ အေကာင္အထည္ေဖာ္မည့္ ပံုစံကုိ အတည္မျပဳႏုိင္ေသးပဲ ရွိခဲ့သည္။
ယခုအခါ ျမန္မာစာ Unicode စနစ္သည္ တည္ၿငိမ္စ ျပဳလာၿပီျဖစ္ၿပီး ေဇာ္ဂ်ီ ျမန္မာစာ စနစ္မွာ အျခားဘာသာစကားမ်ားႏွင့္ ယွဥ္တြဲ သံုးစြဲႏုိင္သည့္ Unicode အစစ္မဟုတ္ေသာ္လည္း အမ်ားသံုး (de facto) စံႏႈန္းတစ္ရပ္ အျဖစ္ ရပ္တည္လွ်က္ရွိသည္။ ယခင္က သံုးစြဲခဲ့ေသာ ASCII (truetype) font မ်ားႏွင့္ Burglish သံုးစြဲမႈမ်ားလဲ ယေန႕တုိင္ ရပ္တည္လွ်က္ရွိသည္ကို ေတြ႕ရွိရသည္။ ဤစာတမ္းတြင္ 8 bit font မ်ားႏွင့္ burglish အေၾကာင္းကို ေရွးဦးစြာတင္ျပၿပီး အမ်ားသံုးျဖစ္သည့္ ေဇာ္ဂ်ီစနစ္အေၾကာင္းကုိ ဆက္လက္ ေဆြးေႏြးမည္ ျဖစ္သည္။ ထုိ႕ေနာက္ Unicode 5.1 အဆင့္မီစနစ္မ်ားအေၾကာင္းႏွင့္ ၄င္းတုိ႕ကုိ အဘယ္ေၾကာင့္ ေရြးခ်ယ္သင့္သည္ကို ရွင္းလင္းေရးသားမည္ ျဖစ္ပါသည္။
8 Bit Systems
ယခင္က အဂၤလိပ္စာလံုးကဲ့သုိ႕ေသာ လက္တင္စာလံုးမ်ားျဖင့္ ေရးသားထားသည့္ contents မ်ားကုိ ကြန္ပ်ဴတာမ်ား ေ၀မွ်သံုးစြဲႏုိင္ေစရန္အတြက္ စံအျဖစ္ IBM မွ EBCDIC (8 bits) စနစ္ႏွင့္ ASCII (7 bits) စနစ္ဟူ၍ စတင္ ေပၚေပါက္ခဲ့သည္။ ေနာက္ပုိင္းတြင္ ASCII စနစ္ကုိ 8 bit သုိ႕ တုိးခ်ဲ႕ခဲ့သည္။ နာမည္ႀကီး Windows စနစ္မ်ားတြင္ ASCII စနစ္ကုိ အသံုးျပဳႏုိင္ရာ အဂၤလိပ္စာလံုးမ်ားကုိ ပံုျပင္ဆြဲ၍ ျမန္မာစာလံုးပံုစံ အမ်ားအျပား ေပၚထြက္ခဲ့သည္။ ၄င္းတုိ႕သည္ နည္းပညာရႈေထာင့္အရ အဂၤလိပ္စာကုိ ပံုေျပာင္းထားျခင္းမွ်သာျဖစ္ၿပီး ျမန္မာဘာသာျဖင့္ ေရးသားထားေသာ အခ်က္အလက္မ်ားကုိ ျမန္မာစာ အကၡရာစီထံုးျဖင့္ အလြယ္တကူ စီ၍မရေပ။ ယခုအခါ ၄င္းတုိ႕ကုိ ပံုႏွိပ္တုိက္မ်ားတြင္ က်ယ္ျပန္႕စြာ သံုးစြဲလွ်က္ရွိၿပီး CE ႏွင့္ Win-Myanmar ပံုစံတုိ႕မွာ ထင္ရွားသည္။
Burglish
ျမန္မာႏွင့္ အဂၤလိပ္စာ ေရာေထြးေရးသားရန္ 16 bit code မ်ား မေပၚေပါက္မီက Chat application သံုးစြဲသူအခ်ိဳ႕သည္ ေျပာလုိေသာ အေၾကာင္းအရာကုိ အသံဖလွယ္၍ အဂၤလိပ္ အကၡရာမ်ားျဖင့္ ေရးသားသံုးစြဲၾကသည္။ (ဥပမာအားျဖင့္ Sar Pee P Lar ? = စားၿပီးၿပီလား ျဖစ္သည္။) ယေန႕တုိင္ ျမန္မာစာ ေကာင္းစြာ မရိုက္တတ္သူ Chat application အသံုးျပဳသူအခ်ိဳ႕လဲ ရွိေနဆဲပင္ ျဖစ္သည္။ ၄င္းတုိ႕အတြက္ အလုိအေလ်ာက္ ဘာသာျပန္ေပးသည့္ စနစ္အမ်ိဳးမ်ိဳး ေပၚထြက္ခဲ့ရာ ၀ိဇၨာစနစ္မွာ ထင္ရွားေသာ ဥပမာ တစ္ခုျဖစ္ၿပီး ေဇာ္ဂ်ီႏွင့္ Myanmar – 3 သုိ႕ ဘာသာျပန္ေပးႏုိင္သည္။
ေဇာ္ဂ်ီ
ႏုိင္ငံတကာသံုး စံႏႈန္းျဖစ္သည့္ Unicode စံႏႈန္း (16 bit code) တြင္ ျမန္မာအကၡရာမ်ား၏ ေနရာ (ခြင္) ကို အတိအက် သတ္မွတ္ႏုိင္ခဲ့ၿပီး ျဖစ္ေသာ္လည္း စာလံုးမ်ား၏ ေနရာႏွင့္ ဘာသာစကား၏ ရႈပ္ေထြးမႈ ျပႆနာမ်ားကို ေျဖရွင္းႏုိင္ရန္ စံသတ္မွတ္ခ်က္ အတိအက် မရွိသည္မွာ အေတာ္ပင္ ၾကာျမင့္ခဲ့သည္။ ဥပမာအားျဖင့္ ျပ ႏွင့္ ၾက တြင္ ပါ၀င္ေသာ ရရစ္မွာ အတူတူပင္ျဖစ္ေသာ္လည္း ၄င္းတုိ႕ကုိ ပံုေဖာ္ရန္အတြက္ software support (rendering support) လုိသည္။ ၄င္းကုိ အလြယ္နည္းႏွင့္ ေျဖရွင္းရန္မွာ code-range ကို ခ်ဲ႕ပစ္ရန္ျဖစ္ရာ (ရရစ္ ၂ ခုသံုးမယ္၊ code ၂ ခုေပး ဆုိတာမ်ိဳး) ပညာရွင္အခ်ိဳ႕က စံႏႈန္းမတည္ၿငိမ္မီ ကာလအတြင္း ေဆးၿမီးတုိအျဖစ္ အျခားဘာသာစကားမ်ား၏ code မ်ားကုိ ေခ်းငွားသံုးစြဲကာ ေဇာ္ဂ်ီစာလံုးစနစ္ကုိ ဖန္တီးခဲ့ၾကသည္။
၄င္းသည္ ျပႆနာ ၂ ရပ္ကုိ ဖိတ္ေခၚလာသည္။ ေဇာ္ဂ်ီသည္ အဂၤလိပ္ အကၡရာမ်ား၏ code ကုိ မထိသျဖင့္ အဂၤလိပ္/ျမန္မာ တြဲဖက္ေရးသားရာတြင္ အဆင္ေျပေသာ္လည္း ၄င္းေခ်းငွားထားေသာ ဘာသာစကားမ်ားႏွင့္ ျမန္မာစာကုိ တြဲဖက္ေရးသားပါက ကြန္ပ်ဴတာအေနႏွင့္ ေခ်းသံုးထားေသာ code မ်ားကုိ မည္သည့္ အကၡရာ (ျမန္မာ အကၡရာ သို႕မဟုတ္ အျခား အကၡရာ) အျဖစ္ ေဖာ္ျပေပးရမည္ကုိ မသိႏုိင္ပဲ ျဖစ္လိမ့္မည္။ (ဥပမာ 1E29 သည္ 'ḩ' လား၊ Latin Small Letter H with Cedilla လား မသိႏုိင္ေတာ့ေပ။) ေနာက္ျပႆနာတစ္ရပ္မွာ တူညီေသာ စာလံုးမ်ား ကုိ code အမ်ားအျပားသုိ႕ assign လုပ္ထားသျဖင့္ အကၡရာစဥ္ စီရာ (ႏွင့္ searching ရွာရာ) တြင္ မလုိလားအပ္ေသာ ရႈပ္ေထြးမႈမ်ားကုိ ျဖစ္ေပၚေစပါသည္။ ဥပမာအားျဖင့္ ရရစ္သည္ ျပ ဟုေရးရာတြင္ တမ်ိဳး၊ ၾက ဟုေရးရာတြင္ တမ်ိဳး၊ လံုးႀကီးတင္ႏွင့္ တြဲရန္တမ်ိဳး (ၿပိ၊ ႀကိ) စသျဖင့္ code အမ်ိဳးမ်ိဳး ျဖစ္ေနသည္။ အမွန္မွာ အကၡရာ စဥ္ရာတြင္ ၾကသည္ ျပအေရွ႕ (ၾကိသည္ ျပိအေရွ႕) ဟူ၍ ရရစ္ ၂ မ်ိဳးကုိ အတူတူ သေဘာထားၿပီး စီရရာ ေဇာ္ဂ်ီစနစ္ျဖင့္ ေရးသားထားေသာ ျမန္မာစာမ်ားကုိ အကၡရာစီႏုိင္ရန္ ခက္ခဲပါသည္။
ေဇာ္ဂ်ီ၏ အဓိက အားနည္းခ်က္ တစ္ရပ္မွာ စာလံုးမ်ား၏ စံပံုစံ မရွိျခင္းပင္ ျဖစ္သည္။ တ + - ိ + - ု (တုိ) ႏွင့္ တ + - ု + - ိ (တုိ) တုိ႕မွာ ေဇာ္ဂ်ီတြင္ မတူညီၾကေပ။ သုိ႕ျဖစ္၍ ပထမ တုိ ကုိ ရွာေဖြရန္ ႀကိဳးစားရာတြင္ ဒုတိယ တုိ ကုိ ထည့္သြင္း ရွာေဖြခုိင္းပါက ရွာေတြ႕မည္ မဟုတ္ပါေခ်။ တူညီေသာစာလံုးမ်ားကုိ ရုိက္ထည့္ေသာ အစီအစဥ္ မတူညီျခင္းေၾကာင့္ ကြန္ပ်ဴတာက မတူညီဟု အေျဖထုတ္ေပးျခင္းမွာ လက္ခံႏုိင္ဖြယ္ အရည္အေသြးတစ္ရပ္ မဟုတ္ေပ။ ေဇာ္ဂ်ီျဖင့္ ေရးသားထားေသာ ျမန္မာစာတုိ႕မွာ တေန႕တျခား တုိးပြားလာေနရာ ေနာင္တခ်ိန္တြင္ ၄င္းတုိ႕သည္ ရွာရ၊ ေဖြရခက္သည့္ စာအုပ္ပံုႀကီးႏွင့္ အတူတူပင္ ျဖစ္လာေတာ့မည္ ျဖစ္သည္။ (အဆုိေတာ္ စုိင္းစုိင္းခမ္းလႈိင္၏ အေၾကာင္းကို ေရးသားသူ တ၀က္က စ + - ိ + - ု + င + - ္ + - း ဟု ေရးၿပီး က်န္တ၀က္က စ + - ု + - ိ + င + - ္ + -း ဟု ေရးပါက မည္သုိ႕ ျဖစ္မည္ကို မွန္းဆၾကည့္ပါ။) သုိ႕ရာတြင္ ေရွးယခင္ လက္ႏွိပ္စက္မ်ားကဲ့သုိ႕ပင္ သေ၀ထုိးႏွင့္ ရရစ္ကုိ ဗ်ည္းမရုိက္ခင္ ရိုက္ရျခင္း၊ ဗ်ည္းတြဲမ်ား (ရရစ္၀ဆြဲ၊ ယပင့္၀ဆြဲ စသည္တုိ႕)ကုိ ခလုတ္တစ္ခ်က္ႏွိပ္ရံုႏွင့္ ေရးသားႏုိင္ျခင္းတုိ႕မွာ သံုးစြဲသူတုိ႕ ႏွစ္သက္ဖြယ္ျဖစ္သည္။
Windows စနစ္အမ်ားစုတြင္ ေဇာ္ဂ်ီစနစ္ျဖင့္ ျမန္မာစာ ေရးသားရန္အတြက္ အခမဲ့ ရရွိႏုိင္ေသာ Zawgyi installer application ကုိ သြင္းလုိက္ရန္သာလုိအပ္ၿပီး ဖတ္ရႈရန္အတြက္မူ သာမာန္ font တစ္ခု သြင္းသကဲ့သုိ႕ ေဇာ္ဂ်ီ font ကုိ သြင္းလုိက္ရန္သာ လုိအပ္သည္။ ေရးသားရန္အတြက္ လက္ကြက္မွတပါး ေလ့က်င့္ရန္ မလုိအပ္ေပ။ အသံုးျပဳရလြယ္ကူျခင္းေၾကာင့္ ယေန႕တြင္ online ေပၚရွိ ျမန္မာစာအသံုးျပဳမႈ (blog, forum, chat application) အမ်ားစုသည္ ေဇာ္ဂ်ီ ျမန္မာစာ စနစ္ျဖင့္ ျဖစ္သည္။
Unicode 5.1 အဆင့္မီ ျမန္မာစာစနစ္မ်ား
Myanmar 3 အပါအ၀င္ Unicode 5.1 စနစ္သံုး ျမန္မာစာစနစ္မ်ားသည္လည္း အစုိးရက ေထာက္ခံေနလင့္ကစား အားနည္းခ်က္မ်ား ရွိဆဲပင္ျဖစ္သည္။ ဥပမာအားျဖင့္ ေမာက္ခ်ာ (- ါ) ႏွင့္ ေရးခ်ာ (- ာ) တုိ႕မွာ စာလံုး ၂ လံုးျဖစ္ေနသည္။ အကၡရာစဥ္ရာတြင္ ၄င္းတုိ႕ကုိ အတူတူဟု သေဘာထားၿပီး စီရသည္။ (ေဇာ္ဂ်ီ၏ ရရစ္ကဲ့သုိ႕ပင္ မလုိအပ္ပဲ code-range ကုိ ျဖဳန္းတီးသကဲ့သုိ႕ ျဖစ္ေနပါသည္။) အသတ္ (- ္)ႏွင့္ ပံုစံတူေသာ္လည္း အသတ္ႏွင့္ ဘာမွမဆုိင္ေသာ ေရွ႕ထုိး (ဥပမာ ေကာ္ မွ - ္) မွာ code မရွိပါ။ တနည္းအားျဖင့္ဆုိေသာ္ Unicode 5.1 သည္လည္း တုိးတက္ေျပာင္းလဲဦးမည့္ အရိပ္အေယာင္မ်ား ရွိေနပါသည္။ သုိ႕ရာတြင္ ၄င္းသည္ စာရိုက္ရာတြင္ သတ္မွတ္ထားသလုိသာ ရုိက္သြင္းရသျဖင့္ ေဇာ္ဂ်ီကဲ့သုိ႕ တုိ ၂ မ်ိဳး ျဖစ္ေနစရာ မရွိသျဖင့္ ေဇာ္ဂ်ီထက္ ပုိမုိ တည္ၿငိမ္မည္ဟု ေမွ်ာ္လင့္ရသည္။
ထုိ႕ျပင္ Myanmar – 3 ကိုအသံုးျပဳရန္အတြက္ အနည္းငယ္ရႈပ္ေထြးေသာ အဆင့္မ်ား လုိအပ္သည္။ Windows စနစ္တြင္ ဖတ္ရႈရန္အတြက္လဲ သီးသန္႕ software မ်ား သြင္းရန္ လက္ရွိအခ်ိန္တြင္ လုိအပ္ဆဲျဖစ္သည္။ ၄င္းကုိ အသံုးျပဳ ေရးသားရန္အတြက္ အခ်ိန္အနည္းငယ္ၾကာမွ် ေလ့က်င့္ရန္ လုိအပ္ပါသည္။
ဘာကုိသံုးရမလဲ၊ ဘာေၾကာင့္ လူမ်ားစု မသံုးေသးတာလဲ။
ယေန႕တြင္ အစုိးရ၀န္ႀကီးဌာနမ်ားအားလံုးကို Myanmar-3 ကုိ အသံုးျပဳရန္ ညႊန္ၾကားထားပါသည္။ ထုိ႕ေၾကာင့္ e-Government စနစ္မ်ားကို ေနာင္အနာဂါတ္တြင္ မိတ္ဆက္ခဲ့ပါက Myamar – 3 ကုိ ႏုိင္ငံသားတုိင္း မျဖစ္မေန အသံုးျပဳရမည္မွာ ေသခ်ာသေလာက္ ရွိသည္။ ထုိ႕ျပင္ Windows စနစ္မ်ားတြင္ Unicode 5.1 ကုိ အေထာက္အပံ့ေပးပါက ဖတ္ရေရးရခက္ေသာ ျပႆနာမွာ အလုိအေလ်ာက္ ေျပလည္သြားမည္ျဖစ္သည္။ (ယခုအခါ KDE သံုး Linux မ်ားတြင္ Myanmar – 3 ကုိ ဒီအတုိင္း ဖတ္လုိ႕ရၿပီျဖစ္သည္။) ထုိအခ်ိန္တြင္ ေဇာ္ဂ်ီသည္ Myanmar- 3 ထက္ပုိ၍ ေရးရ၊ ဖတ္ရလြယ္သည္ဆုိေသာ အားသာခ်က္ မရွိႏုိင္ေတာ့ေပ။
အသံုးမ်ားေသာ ေဇာ္ဂ်ီမွ Unicode 5.1 သို႕ေျပာင္းလဲႏုိင္ေရးသည္ တကယ္တမ္းအားျဖင့္ ကြန္ပ်ဴတာ သိပၸံ ျပႆနာ တစ္ရပ္မဟုတ္ပါ (အက်ယ္ကုိ ေလာကအလွႏွင့္ အင္တာဗ်ဴး ရႈ)။ Myanmar – 3 ကုိ ေျပာင္းရမည္မွာလဲ ေသခ်ာ၊ ေဇာ္ဂ်ီကုိလဲ ၾကာရွည္ အသံုးျပဳရန္လဲ အဆင္မေျပ၊ တစ္ဦးခ်င္း ေျပာင္းရန္လဲ နည္းပညာအရ လြယ္ကူ လွ်င္ျမန္ပါလွ်က္ႏွင့္ ေဇာ္ဂ်ီကုိ လူမ်ားစု ဖက္တြယ္ထားၾကျခင္းမွာ အေၾကာင္းရင္း ၂ ရပ္ေၾကာင့္ ျဖစ္သည္။ ပထမ အေၾကာင္းရင္းမွာ Myanmar – 3 တြင္ လက္ႏွိပ္စက္အတုိင္း ရုိက္မရပဲ ေလ့လာသင္ၾကားမႈ လုိအပ္ေသာေၾကာင့္ (ေဇာ္ဂ်ီ၏ တခုတည္းေသာ အားသာခ်က္) ျဖစ္သည္။ ဒုတိယ အေၾကာင္းရင္းမွာ လူမ်ားစု သံုးစြဲျခင္း မျပဳေသာေၾကာင့္ အထီးက်န္မည္ကုိ စုိးရိမ္သည့္ လူမႈေရး ျပႆနာျဖစ္ၿပီး ပုိမုိအေရးႀကီးသည္။
နိဂံုး
ယခုစာတမ္းငယ္တြင္ 8 bit font၊ Burglish၊ ေဇာ္ဂ်ီႏွင့္ Myanmar – 3 အစရွိေသာ ျမန္မာစာ စနစ္အမ်ိဳးမ်ိဳး၏ သေဘာသဘာ၀မ်ားကို သိနားလည္မွ Unicode အဆင့္မီ ျမန္မာစာစနစ္မ်ားသုိ႕ ေျပာင္းလဲရန္ အစီအစဥ္ကုိ ႀကံဆႏုိင္မည္ျဖစ္သျဖင့္ ၄င္းတုိ႕၏ ဂုဏ္သတၱိမ်ားကုိ နည္းပညာႏွင့္ လူမႈေရး (သမိုင္းေၾကာင္းႏွင့္ သံုးစြဲသူမ်ား) ရႈေထာင့္မ်ားမွ တင္ျပထားသည္။ အဆုိပါ ေတြ႕ရွိခ်က္မ်ားကုိ အေျခခံ၍ Unicode အဆင့္မီ ျမန္မာစာစနစ္မ်ားသုိ႕ ေျပာင္းလဲႏုိင္ရန္ အစီအစဥ္ကုိ ဆက္လက္ေဆြးေႏြးရန္ က်န္ရွိေနပါေသးသည္။
Thursday, May 8, 2008
နည္းလမ္းစဥ္ သရုပ္ခြဲပညာ မိတ္ဆက္
ပုစၧာ ။ ။ အပင္တစ္ပင္ (Tree) တစ္ခုကုိ ေပးထားပါမယ္ ။ အဆစ္တစ္ခု (Node) တစ္ခုမွာ ကုိင္းခြဲ (Edge) ႏွစ္ခု ရွိပါမယ္ ။ ကပ္လ်က္ အဆစ္ ႏွစ္ခုရဲ႕ ဘယ္ကုိင္းခြဲနဲ႕ ညာကိုင္းခြဲက အဆစ္တစ္ခုထဲမွာ သြားဆံုပါမယ္ ။ အဆစ္တုိင္းမွာ တန္ဖုိးတစ္ခု တြဲလ်က္ရွိပါမယ္ ။ အျမစ္ (Root) ကေနၿပီး အရြက္ (Leaf) တစ္ခုကုိ သြားဖုိ႕ လမ္းတစ္ခုစီ (Path) ရဲ႕ တန္ဖုိးကုိ လမ္းတေလွ်ာက္က အဆစ္ေတြရဲ႕ တန္ဖုိးေတြေပါင္းလဒ္အျဖစ္ အဓိပၸါယ္သတ္မွတ္ပါမယ္ ။ အနက္ - သုိ႕မဟုတ္ အျမင့္ - (Depth) ၂ သုိ႕မဟုတ္ ၂ ထက္ပုိတဲ့ အပင္ေတြမွာ အရြက္ေပါင္းမ်ားစြာ ရွိမွာျဖစ္ၿပီး အရြက္တစ္ရြက္စီကုိ သြားဖုိ႕ လမ္းေၾကာင္းကလဲ ၁ ခု သုိ႕မဟုတ္ ၁ ခုထက္ ပုိမွာျဖစ္ပါတယ္ ။ ပံုကုိ ၾကည့္ပါ ။
ပံုမွာ အေပၚက ေျပာထားတဲ့ အပင္မ်ိဳး တစ္ပင္ကုိ ျပထားပါတယ္ ။ အဆစ္ေတြနဲ႕ အကုိင္းေတြကုိ စက္၀ုိင္းေတြနဲ႕ မ်ဥ္းေၾကာင္းေတြနဲ႕ ျပထားပါတယ္ ။ မ်ဥ္းထူနဲ႕ ျပထားတဲ့ လုိင္းေၾကာင္းက ဒီအပင္ရဲ႕ တန္ဖုိးအျမင့္ဆံုး လမ္းေၾကာင္းပါ ။ ေအာက္က ၂၅ ဆုိတာက အဲဒီ တန္ဖုိးအျမင့္ဆံုး လမ္းေၾကာင္းရဲ႕ တန္ဖုိးပါ ။ အဲဒီတန္ဖုိးကုိ တြက္ထုတ္တဲ့ ပုစၧာကုိ စဥ္းစားၾကည့္ရေအာင္ ။
ဒါမ်ိဳးပုစၧာအတြက္ဆုိရင္ လူေတာ္ေတာ္မ်ားမ်ားက ေလာဘႀကီးတဲ့ခ်ဥ္းးကပ္နည္း (Greedy approach) ကုိ စဥ္းစားမိတတ္ၾကပါတယ္ ။ ဒီပုစၧာမွာေတာ့ ေလာဘႀကီးတဲ့နည္းနဲ႕ ခ်ဥ္းကပ္လုိ႕ မရပါဘူး ။ ဘာလုိ႕လဲဆုိေတာ့ တတိယေျမာက္ အဆင့္မွာ ၇ တန္ဖုိးရွိတဲ့ အဆစ္ကေန ၃ နဲ႕ ၄ တန္ဖုိးရွိတဲ့ အဆစ္ေတြကုိ ေရြးရာမွာ ေလာဘႀကီးၿပီး တန္ဖိုး ၄ ရွိတဲ့ အဆစ္ကုိ ေရြးလုိက္ရင္ ေအာက္ဆံုး အဆင့္က တန္ဖုိး ၉ ရွိတဲ့ အဆစ္ကုိ လြတ္သြားမွာ ျဖစ္လုိ႕ပါပဲ ။ (ေလာဘႀကီးတဲ့ ခ်ဥ္းကပ္နည္းနဲ႕ စဥ္းစားလုိ႕ရ ၊ မရကုိ သက္ေသျပတာ ၊ စဥ္းစားလုိ႕ ရေအာင္ ႀကိဳးစားၾကတာဟာလဲ နည္းလမ္းစဥ္ သရုပ္ခြဲပညာရဲ႕ အကုိင္းအခက္ တစ္ခုပဲ ျဖစ္ပါတယ္ ။)
စာေရးသူ ၂၀၀၀ ခုႏွစ္တုန္းက ဒီပုစၧာကုိ ရွင္းဖုိ႕ နည္းလမ္းစဥ္ (Algorithm) တစ္ခုကုိ စဥ္းစားဖူးပါတယ္ ။ အပင္ကုိ လွဲ၊ အဆစ္ေတြကို အမွတ္စဥ္တပ္ၿပီး အမွတ္စဥ္ေရတြက္သလုိ လမ္းေၾကာင္းတစ္ခုခ်င္း အျပန္ျပန္၊ အလွန္လွန္ တြက္တဲ့ ပင္ပန္းတဲ့ (Exhaustive) နည္းနဲ႕ပါ ။ ေအာက္ပါပံုမွာ ၾကည့္ပါ ။
တြက္ပံုတြက္နည္းကေတာ့ လက္ရွိေပါင္းၾကည့္မဲ့ လမ္းေၾကာင္းကုိ တေနရာမွာ သိမ္းထားပါတယ္ ။ (၀ ကဘယ္ဘက္ ၁ ကညာဘက္ပါ ။ C/C++ နဲ႕ ဆုိရင္ေတာ့ Integer variable တစ္ခုထဲကုိ ၁ ေပါင္း Shift operation ေတြနဲ႕ ေရႊ႕ယူၿပီး လမ္းေၾကာင္းကို တြက္ထုတ္လုိ႕ရေပမဲ့ Pascal ရဲ႕ ကန္႕သတ္ခ်က္ေတြေၾကာင့္ တစ္ေၾကာင္း ၊ အဲဒီတုန္းက ငယ္ေသးတာက တစ္ေၾကာင္းမုိ႕လုိ႕ ဒီ Permutation with repetition ကုိ ကုိယ့္ဘာသာကုိယ္ ေရးပစ္လုိက္ပါတယ္ ။ )
ဒီအပင္ကုိ ႀတိဂံပံု ေမးထရစ္ မွာသိမ္းထားတယ္လုိ႕ ျမင္ရင္ ေပါင္းရမဲ့တန္ဖုိး (အဆစ္) ေတြရဲ႕ တည္ေနရာကုိ current_level တန္း၊ column_of_previous_level + path_value_of_current_level တုိင္ မွာ ရွာေတြ႕ႏုိင္ပါတယ္ ။ အဲဒီအဆစ္ေတြရဲ႕ တန္ဖုိးေတြ ေပါင္းလုိက္ရင္ လက္ရွိလမ္းေၾကာင္းရဲ႕ တန္ဖုိးကုိ ရပါၿပီ ။ ဒီတန္ဖုိးေတြကုိ အႀကီးဆံုးကိန္းရွာတဲ့ နည္းလမ္းစဥ္ထဲ ထည့္လုိက္ရင္ အႀကီးဆံုးလမ္းေၾကာင္းတန္ဖုိးကုိ ရၿပီေပါ့ ။ ဒါေပမဲ့ Borland’s Turbo Pascal 7.0 Compiler နဲ႕ Compile လုပ္ထားတဲ့ ပရုိဂရမ္ကုိ Pentium MMX 166 MHz, 32 MB RAM ပါတဲ့စက္နဲ႕ အနက္ ၃၀ ရွိတဲ့ အပင္ကုိ မနက္ ၁၀ နာရီကေန စတြက္တာ ညေန ၅ နာရီအထိ အေျဖမထြက္ႏုိင္ေသးပဲ တြက္ေကာင္းတုန္း ျဖစ္ေနပါတယ္ ။ (အခု Intel Core 2 Duo E6550 2.33GHz, 2 x 2MB L2 Cache, 1066 MHz FSB, 4 x 1GB DDR2 667MHz RAM နဲ႕ တြက္ခုိင္းၾကည့္တာ ၃၂ စကၠန္႕ၾကာျမင့္ပါတယ္ ။ )
ဘာမွားသြားလဲ အေျဖရွာမၾကည့္ခင္မွာ ကၽြန္ေတာ့္ဆရာေပးတဲ့ နည္းလမ္းစဥ္က ၁ မိနစ္အတြင္း တြက္လုိ႕ၿပီးတယ္ဆုိတာကုိ ျဖည့္ေျပာခ်င္ပါတယ္ ။ သူသံုးတဲ့နည္းလမ္းကေတာ့ Recursive with table lookup လုိ႕ေခၚတဲ့ ေပါင္းစပ္ အစီအစဥ္ဆြဲနည္း (Dynamic programming) ျဖစ္ပါတယ္ ။ (ေပါင္းစပ္အစီအစဥ္ဆြဲနည္းဟာလဲ ေလာဘႀကီးတဲ့ ခ်ဥ္းကပ္နည္းလုိပဲ အေရးပါတဲ့ နည္းလမ္းတစ္ခုပါ ။ ) သူက အေျဖကုိ ဒီလုိ ပံုစံထုတ္ပါတယ္ ။ အရြက္မဟုတ္တဲ့ အဆစ္တစ္ခု (အဆစ္ ဆ) ကေန အရြက္ေတြဆီသြားတဲ့ တန္ဖုိးအျမင့္ဆံုး လမ္းေၾကာင္းဟာ အဲဒီအဆစ္ရဲ႕ ဘယ္ဘက္ ညာဘက္ အဆစ္ (ဆ ရဲ႕ ဘယ္ဘက္ အဆစ္ သုိ႕မဟုတ္ ညာဘက္အဆစ္) ေတြကေန အရြက္ေတြဆီသြားတဲ့ တန္ဖုိးအျမင့္ဆံုး လမ္းေၾကာင္း ၂ ခုထဲက ပုိမ်ားတဲ့ လမ္းေၾကာင္းရဲ႕ တန္ဖုိးကုိ အဲဒီ အဆစ္ (ဆ) ရဲ႕ တန္ဖုိး ေပါင္းထည့္ထားတာျဖစ္ၿပီး အရြက္ေတြရဲ႕ အျမင့္ဆံုးလမ္းေၾကာင္း တန္ဖုိးကေတာ့ သူတုိ႕ကုိယ္တုိင္ရဲ႕ တန္ဖုိးပဲ ျဖစ္ပါတယ္ ။
ဟုိး … စာဖတ္သူ … ဟုိး … ဒီအတုိင္း Recursive နဲ႕ ေရးလုိက္တဲ့ အစီအစဥ္ (program) ဟာလဲ အေပၚက ပင္ပန္းတဲ့နည္းလုိပဲ နာရီေပါင္းမ်ားစြာ ၾကာျမင့္သြားႏုိင္ပါတယ္ ။ ဘာလုိ႕လဲဆုိေတာ့ အနက္ ၂ မွာရွိတဲ့ အဆစ္ ၀ နဲ႕ အဆစ္ ၁ တုိ႕ရဲ႕ အေျဖဟာ သူတုိ႕ ၂ ခုရဲ႕ ဘံုဆက္ခံသူ အနက္ ၃ ၊ အဆစ္ ၁ ရဲ႕ အေျဖေပၚမူတည္ေနလုိ႕ ျဖစ္ပါတယ္ ။ တကယ္လုိ႕သာ ရုိးရုိး Recursive နဲ႕ ေရးလုိက္မယ္ဆုိရင္ အဲဒီအေျဖကုိ ၂ ခါျပန္တြက္ရမွာ ျဖစ္ပါတယ္ ။ အဲဒါေၾကာင့္မုိ႕လုိ႕ အဲဒီ အပင္နဲ႕ အရြယ္အစားတူ အပင္တစ္ပင္ထပ္စုိက္ … အဲ အဲ တည္ေဆာက္ၿပီး တြက္ၿပီးသား ရလဒ္ေတြကုိ သိမ္းထားပါမယ္ ။ ေနာက္တခါ တြက္ဖုိ႕ လုိအပ္လာတုိင္းမွာ အဲဒီရလဒ္ေတြကုိ ျပန္ၾကည့္ၿပီး တြက္ၿပီးသားဆုိရင္ ဒီတုိင္းယူသံုးလုိက္မွ အဆင္ေျပပါလိမ့္မယ္ ။
ေပါင္းစပ္ အစီအစဥ္ဆြဲျခင္း စစ္စစ္ကေတာ့ ေအာက္ဆံုးအဆင့္ကေန အထက္ကုိ ျဖည္းျဖည္းခ်င္း အေျဖတြက္လာတဲ့ နည္းျဖစ္ၿပီး ခုနက နည္းထက္ နည္းနည္းပုိျမန္းပါတယ္ ။ ဘာလုိ႕လဲဆုိေတာ့ မွီခ်က္ေတြကုိ ေခၚတဲ့အခါ (Function calls) ၀န္ပုိ (Overhead) နည္းနည္း ရွိတတ္လုိ႕ ျဖစ္ပါတယ္ ။ (အခု Intel Core 2 Duo E6550 2.33GHz, 2 x 2MB L2 Cache, 1066 MHz FSB, 4 x 1GB DDR2 667MHz RAM နဲ႕ တြက္ၾကည့္တာ ၂ နည္းစလံုး ၁ စကၠန္႕ေအာက္သာၾကာျမင့္ပါတယ္ ။ )
နည္းလမ္းစဥ္ သရုပ္ခြဲပညာမွာ အေရးပါတဲ့ အစိတ္အပုိင္း ၃ ခုရွိပါတယ္ ။ ပထမတစ္ခုက နည္းလမ္းစဥ္ရဲ႕ မွန္ကန္မႈ (Correctness of the Algorithm) ျဖစ္ပါတယ္ ။ အေပၚက ဥပမာမွာ နည္းလမ္းစဥ္အားလံုး မွန္ကန္ၾကပါတယ္ ။ ဒုတိယတစ္ခုက အခ်ိန္ၾကာျမင့္မႈ (Time Complexity) ျဖစ္ၿပီး ေနာက္ဆံုးတစ္ခုက သိမ္းဆည္းမႈ လုိအပ္ခ်က္ (Space Complexity) ျဖစ္ပါတယ္ ။ ပင္ပန္းတဲ့နည္းက အခ်ိန္ပုိၾကာေပမဲ့ သိမ္းဆည္းမႈ လုိအပ္ခ်က္ နိမ့္ပါတယ္ ။ အေျဖေတြကုိ ေပါင္းစပ္တဲ့နည္းက အခ်ိန္မၾကာေပမဲ့ သိမ္းဆည္းမႈ လုိအပ္ခ်က္ ျမင့္တယ္လုိ႕ ေကာက္ခ်က္ခ်ႏုိင္ပါတယ္ ။ ပုစၧာတစ္ရပ္အတြက္ နည္းလမ္းစဥ္အမ်ိဳးမ်ိဳး ရွိေနတတ္တာမုိ႕ နည္းလမ္းစဥ္ သရုပ္ခြဲပညာကုိ ဒီလုိေလ့လာမႈမ်ိဳးလုပ္ဖုိ႕အတြက္ အသံုးျပဳႏုိင္ပါတယ္လုိ႕ တင္ျပရင္း မိတ္ဆက္စာတမ္းငယ္ကုိ နိဂံုးခ်ဳပ္အပ္ပါတယ္ ။ ယခုလက္ရွိမွာေတာ့ ကြန္ပ်ဴတာသိပၸံမွ ျပႆနာမ်ား စာတမ္းကုိ ေရႊပြဲလာမ်ား ဖတ္ရႈဖုိ႕ ေရးသားေနပါတယ္ခင္ဗ်ာ ။
စာေရးသူေရးစမ္းထားတဲ့ အစီအစဥ္ေတြကုိ ဒီေနရာမွာ ရယူႏုိင္ပါတယ္။

