সিএসে ডিগ্রিধারী বেশিরভাগ লোকেরা অবশ্যই জেনে যাবে যে বিগ ও কী বোঝায় । এটি একটি অ্যালগোরিদম স্কেল কতটা ভাল তা মাপতে আমাদের সহায়তা করে।
কিন্তু আমি জানতে আগ্রহী নই, কীভাবে আপনি নিরূপণ করুন অথবা আপনার আলগোরিদিম জটিলতা আনুমানিক?
সিএসে ডিগ্রিধারী বেশিরভাগ লোকেরা অবশ্যই জেনে যাবে যে বিগ ও কী বোঝায় । এটি একটি অ্যালগোরিদম স্কেল কতটা ভাল তা মাপতে আমাদের সহায়তা করে।
কিন্তু আমি জানতে আগ্রহী নই, কীভাবে আপনি নিরূপণ করুন অথবা আপনার আলগোরিদিম জটিলতা আনুমানিক?
উত্তর:
আমি এখানে সহজ শর্তে এটি ব্যাখ্যা করার জন্য যথাসাধ্য চেষ্টা করব, তবে সতর্ক হতে হবে যে এই বিষয়টি আমার শিক্ষার্থীদের অবশেষে উপলব্ধি করতে কয়েক মাস সময় নেয়। আপনি জাভা বইয়ের ডেটা স্ট্রাকচার এবং অ্যালগরিদমের দ্বিতীয় অধ্যায়টিতে আরও তথ্য পেতে পারেন ।
বিগহহ পাওয়ার জন্য কোনও যান্ত্রিক পদ্ধতি নেই ।
"কুকবুক" হিসাবে কোনও কোডের টুকরো থেকে বিগহ পেতে আপনার প্রথমে বুঝতে হবে যে আপনি কোনও আকারের একটি ইনপুট দেওয়ার মাধ্যমে গণনার কতগুলি পদক্ষেপ কার্যকর করা হয় তা গণনা করার জন্য একটি গণিত সূত্র তৈরি করছেন।
উদ্দেশ্যটি সহজ: কোডটি কার্যকর করার প্রয়োজন ছাড়াই একটি তাত্ত্বিক দৃষ্টিকোণ থেকে অ্যালগরিদমগুলির তুলনা করা। পদক্ষেপের সংখ্যা যত কম, অ্যালগরিদম তত দ্রুত।
উদাহরণস্বরূপ, আসুন ধরা যাক আপনার কাছে কোডের এই টুকরা রয়েছে:
int sum(int* data, int N) {
int result = 0; // 1
for (int i = 0; i < N; i++) { // 2
result += data[i]; // 3
}
return result; // 4
}
এই ফাংশনটি অ্যারের সমস্ত উপাদানগুলির যোগফল প্রদান করে এবং আমরা সেই ফাংশনের গণ্য জটিলতা গণনা করার জন্য একটি সূত্র তৈরি করতে চাই :
Number_Of_Steps = f(N)
সুতরাং আমাদের আছে f(N)
একটি গণনামূলক পদক্ষেপের সংখ্যা গণনা একটি ফাংশন। ফাংশনটির ইনপুটটি প্রক্রিয়া করার কাঠামোর আকার। এর অর্থ এই যে এই ফাংশনটিকে বলা হয়:
Number_Of_Steps = f(data.length)
প্যারামিটারটি মান N
নেয় data.length
। এখন আমাদের ফাংশনটির আসল সংজ্ঞা দরকার f()
। এটি উত্স কোড থেকে করা হয়, যাতে প্রতিটি আকর্ষণীয় লাইনটি 1 থেকে 4 পর্যন্ত সংখ্যাযুক্ত হয়।
বিগহহ গণনা করার অনেকগুলি উপায় রয়েছে। এই বিন্দু থেকে আমরা ধরে নিতে চলেছি যে ইনপুট ডেটার আকারের উপর নির্ভর করে না এমন প্রতিটি বাক্য একটি ধ্রুবক C
সংখ্যার গণ্য পদক্ষেপ গ্রহণ করে।
আমরা ফাংশনের পৃথক সংখ্যক পদক্ষেপ যুক্ত করতে যাচ্ছি, এবং স্থানীয় ভেরিয়েবল ঘোষণা বা রিটার্ন বিবৃতি উভয়ই data
অ্যারের আকারের উপর নির্ভর করে না ।
এর অর্থ হ'ল লাইন 1 এবং 4 প্রতিটি সি পরিমাণে পদক্ষেপ নেয় এবং ফাংশনটি কিছুটা এরকম:
f(N) = C + ??? + C
পরবর্তী অংশটি হ'ল for
বিবৃতিটির মান নির্ধারণ করা । মনে রাখবেন যে আমরা গণনা সংক্রান্ত পদক্ষেপের সংখ্যা গণনা করছি, যার অর্থ হল যে for
বিবৃতিটির শৃঙ্খলা N
বার হয়ে যায়। যে যোগ হিসাবে একই C
, N
সময়:
f(N) = C + (C + C + ... + C) + C = C + N * C + C
মৃতদেহের কতবার for
মৃত্যুদন্ড কার্যকর হয় তা গণনা করার কোনও যান্ত্রিক নিয়ম নেই, কোডটি কী করে তা দেখে আপনাকে এটি গণনা করতে হবে। গণনা সহজ করার জন্য, আমরা ভেরিয়েবলের সূচনা, শর্ত এবং for
বিবৃতিটির বর্ধিত অংশগুলি উপেক্ষা করছি parts
আসল বিগহো পেতে আমাদের ফাংশনটির অ্যাসিম্পটোটিক বিশ্লেষণ প্রয়োজন । এটি মোটামুটি এভাবে করা হয়:
C
।f()
মধ্যে পলিনোমিয়াম পান standard form
।N
কাছে যাওয়ার সময় সেটিকে বড় রাখুন infinity
।আমাদের f()
দুটি পদ রয়েছে:
f(N) = 2 * C * N ^ 0 + 1 * C * N ^ 1
সমস্ত C
ধ্রুবক এবং অপ্রয়োজনীয় অংশগুলি কেড়ে নেওয়া:
f(N) = 1 + N ^ 1
যেহেতু শেষ শব্দটি সেইটি হ'ল যা বড় হয় যখন f()
অনন্তের কাছে যায় ( সীমা বিবেচনা করুন ) এটিই বিগহ যুক্তি, এবং sum()
ফাংশনটির একটি বিগহো আছে:
O(N)
কিছু চতুর বেশী সমাধান করতে কয়েক ঠাট আছেন: ব্যবহার summations যখনই আপনি করতে পারেন।
উদাহরণস্বরূপ, সংকেতগুলি ব্যবহার করে এই কোডটি সহজেই সমাধান করা যেতে পারে:
for (i = 0; i < 2*n; i += 2) { // 1
for (j=n; j > i; j--) { // 2
foo(); // 3
}
}
আপনাকে প্রথমে যেটি জিজ্ঞাসা করতে হবে তা হ'ল মৃত্যুদণ্ড কার্যকর করার আদেশ foo()
। স্বাভাবিক হওয়া উচিত O(1)
, আপনার এটি সম্পর্কে আপনার অধ্যাপকদের জিজ্ঞাসা করা উচিত। O(1)
মানে (প্রায়, বেশিরভাগ) ধ্রুবক C
, আকারের চেয়ে পৃথক N
।
for
বাক্য এক নম্বর উপর বিবৃতি চতুর হয়। সূচকটি শেষ হওয়ার পরে 2 * N
, বৃদ্ধি দুটি দ্বারা সম্পন্ন হয়। এর অর্থ হ'ল প্রথমটি for
কেবলমাত্র N
পদক্ষেপগুলি কার্যকর করা হয় এবং আমাদের গণনাটিকে দুটি দ্বারা ভাগ করতে হবে।
f(N) = Summation(i from 1 to 2 * N / 2)( ... ) =
= Summation(i from 1 to N)( ... )
দুটি সংখ্যা বাক্যটি আরও জটিল কারণ এটির মান নির্ভর করে i
। একবার দেখুন: সূচক আমি মানগুলি গ্রহণ করি: 0, 2, 4, 6, 8, ..., 2 * এন, এবং দ্বিতীয়টি for
কার্যকর করা হয়: এন প্রথম বার, এন - 2 দ্বিতীয়, এন - 4 তৃতীয় ... এন / 2 পর্যায় পর্যন্ত, যার উপর দ্বিতীয়টি for
কখনই কার্যকর হয় না।
সূত্রে, এর অর্থ:
f(N) = Summation(i from 1 to N)( Summation(j = ???)( ) )
আবার, আমরা পদক্ষেপের সংখ্যা গণনা করছি । এবং সংজ্ঞা অনুসারে, প্রতিটি সংমিশ্রণ সর্বদা এক থেকে শুরু হওয়া উচিত, এবং একের চেয়ে বড় বা সমান সংখ্যায় শেষ হওয়া উচিত।
f(N) = Summation(i from 1 to N)( Summation(j = 1 to (N - (i - 1) * 2)( C ) )
(আমরা ধরে নিচ্ছি যে foo()
এটি রয়েছে O(1)
এবং C
পদক্ষেপ নিয়েছে))
আমাদের এখানে একটি সমস্যা রয়েছে: যখন i
মানটি N / 2 + 1
উপরের দিকে নিয়ে যায়, তখন অভ্যন্তরীণ সমীকরণটি নেতিবাচক সংখ্যায় শেষ হয়! এটা অসম্ভব এবং ভুল। আমরা দুই সঙ্কলন বিভক্ত করতে কেঁদ্রগত বিন্দু মুহূর্ত হচ্ছে প্রয়োজন, i
লাগে N / 2 + 1
।
f(N) = Summation(i from 1 to N / 2)( Summation(j = 1 to (N - (i - 1) * 2)) * ( C ) ) + Summation(i from 1 to N / 2) * ( C )
মূল মুহুর্ত থেকে i > N / 2
, অভ্যন্তরটি for
কার্যকর হবে না, এবং আমরা এর শরীরে একটি ধ্রুবক সি প্রয়োগকারী জটিলতা ধরে নিচ্ছি।
এখন কিছু পরিচয়ের নিয়ম ব্যবহার করে সংক্ষেপগুলি সরল করা যেতে পারে:
w
)কিছু বীজগণিত প্রয়োগ করা:
f(N) = Summation(i from 1 to N / 2)( (N - (i - 1) * 2) * ( C ) ) + (N / 2)( C )
f(N) = C * Summation(i from 1 to N / 2)( (N - (i - 1) * 2)) + (N / 2)( C )
f(N) = C * (Summation(i from 1 to N / 2)( N ) - Summation(i from 1 to N / 2)( (i - 1) * 2)) + (N / 2)( C )
f(N) = C * (( N ^ 2 / 2 ) - 2 * Summation(i from 1 to N / 2)( i - 1 )) + (N / 2)( C )
=> Summation(i from 1 to N / 2)( i - 1 ) = Summation(i from 1 to N / 2 - 1)( i )
f(N) = C * (( N ^ 2 / 2 ) - 2 * Summation(i from 1 to N / 2 - 1)( i )) + (N / 2)( C )
f(N) = C * (( N ^ 2 / 2 ) - 2 * ( (N / 2 - 1) * (N / 2 - 1 + 1) / 2) ) + (N / 2)( C )
=> (N / 2 - 1) * (N / 2 - 1 + 1) / 2 =
(N / 2 - 1) * (N / 2) / 2 =
((N ^ 2 / 4) - (N / 2)) / 2 =
(N ^ 2 / 8) - (N / 4)
f(N) = C * (( N ^ 2 / 2 ) - 2 * ( (N ^ 2 / 8) - (N / 4) )) + (N / 2)( C )
f(N) = C * (( N ^ 2 / 2 ) - ( (N ^ 2 / 4) - (N / 2) )) + (N / 2)( C )
f(N) = C * (( N ^ 2 / 2 ) - (N ^ 2 / 4) + (N / 2)) + (N / 2)( C )
f(N) = C * ( N ^ 2 / 4 ) + C * (N / 2) + C * (N / 2)
f(N) = C * ( N ^ 2 / 4 ) + 2 * C * (N / 2)
f(N) = C * ( N ^ 2 / 4 ) + C * N
f(N) = C * 1/4 * N ^ 2 + C * N
এবং বিগহ হ'ল:
O(N²)
O(n)
যেখানে n
উপাদান, বা সংখ্যা O(x*y)
যেখানে x
এবং y
অ্যারের মাত্রা আছে। বিগ-ওহ "ইনপুটটির সাথে সম্পর্কিত", তাই এটি আপনার ইনপুটটি কী তা নির্ভর করে।
বিগ হে একটি অ্যালগোরিদমের সময় জটিলতার জন্য উপরের সীমাটি দেয়। এটি সাধারণত ডেটা সেটগুলি (তালিকা) প্রসেসিংয়ের সাথে একত্রে ব্যবহৃত হয় তবে অন্য কোথাও ব্যবহার করা যেতে পারে।
এটি সি কোডে কীভাবে ব্যবহৃত হয় তার কয়েকটি উদাহরণ।
বলুন আমাদের এন অ্যারের একটি অ্যারে রয়েছে
int array[n];
যদি আমরা অ্যারের প্রথম উপাদানটি অ্যাক্সেস করতে চাইতাম তবে এটি ও (1) হবে কারণ অ্যারে কত বড় তা বিবেচনা করে না, প্রথম আইটেমটি পেতে সর্বদা একই ধ্রুবক সময় লাগে।
x = array[0];
যদি আমরা তালিকায় একটি নম্বর খুঁজতে চাই:
for(int i = 0; i < n; i++){
if(array[i] == numToFind){ return i; }
}
এটি ও (এন) হবে কারণ আমাদের নম্বরটি সন্ধান করতে আমাদের পুরো তালিকাটি দেখতে হবে। বিগ-ও এখনও ও (এন) সত্ত্বেও আমরা আমাদের নম্বরটি প্রথমবারের মতো দেখতে পেলাম এবং একবার লুপের মধ্য দিয়ে চলতে পারি কারণ বিগ-ও একটি অ্যালগরিদমের জন্য উপরের গণ্ডিকে বর্ণনা করে (ওমেগা নীচে আবদ্ধের জন্য এবং থিটাটি শক্ত আবদ্ধের জন্য) ।
যখন আমরা নেস্টেড লুপগুলি পেতে পারি:
for(int i = 0; i < n; i++){
for(int j = i; j < n; j++){
array[j] += 2;
}
}
এটি ও (এন ^ 2) যেহেতু বাইরের লুপের প্রতিটি পাস (ও (এন)) এর জন্য আমাদের আবার পুরো তালিকাটি অতিক্রম করতে হবে তাই এন এর গুণক আমাদের এন স্কোয়ার সহ রেখে চলেছে।
এটি সবেমাত্র পৃষ্ঠটি স্ক্র্যাচ করছে তবে আপনি যখন আরও জটিল অ্যালগরিদম জটিল গণিত বিশ্লেষণ করতে পারেন তখন প্রমাণ যুক্ত জড়িতগুলি কার্যকর হয়। আশা করি এটি আপনাকে কমপক্ষে যদিও বেসিকগুলির সাথে পরিচিত করবে।
O(1)
নিজেরাই কাজ করতে পারে। উদাহরণস্বরূপ সি স্ট্যান্ডার্ড এপিআইগুলিতে bsearch
অন্তর্নিহিত O(log n)
, strlen
হয় O(n)
এবং qsort
হয় O(n log n)
(প্রযুক্তিগতভাবে এর কোনও গ্যারান্টি নেই, এবং কুইকোর্টের নিজেই সবচেয়ে খারাপ জটিলতা রয়েছে O(n²)
, তবে ধরে নেওয়া আপনার libc
লেখক একটি মরন নয়, এর গড় ক্ষেত্রে জটিলতা O(n log n)
এবং এটি ব্যবহার করে একটি পাইভট সিলেকশন কৌশল যা কেসকে আঘাত করার প্রতিক্রিয়া হ্রাস করে O(n²)
)। এবং উভয়ই bsearch
এবং qsort
তুলনামূলক ফাংশনটি প্যাথলজিকাল হলে আরও খারাপ হতে পারে।
আপনার নির্দিষ্ট সমস্যার জন্য বিগ ও টাইম কীভাবে নির্ধারণ করা যায় তা জানার ক্ষেত্রে, কিছু সাধারণ ক্ষেত্রে জেনে রাখা আপনার অ্যালগরিদমে সিদ্ধান্ত নিতে আপনাকে অনেক বেশি সাহায্য করতে পারে।
Http://en.wikedia.org/wiki/Big_O_notation#Orders_of_common_function থেকে তুলে নেওয়া বেশ কয়েকটি সাধারণ কেস এখানে রয়েছে :
ও (1) - সংখ্যার সমান বা বিজোড় কিনা তা নির্ধারণ করা; ধ্রুব আকারের সন্ধানের টেবিল বা হ্যাশ টেবিল ব্যবহার করে
ও (লগইন) - বাইনারি অনুসন্ধানের মাধ্যমে বাছাই করা অ্যারেতে একটি আইটেম সন্ধান করা
ও (এন) - একটি বাছাই করা তালিকায় একটি আইটেম সন্ধান করা; দুটি এন-অঙ্কের সংখ্যা যুক্ত করা হচ্ছে
ও (এন 2 ) - একটি সাধারণ অ্যালগরিদমের দ্বারা দুটি এন-অঙ্কের সংখ্যাগুলি গুণ করা; দুটি n × n ম্যাট্রিক যোগ করা; বুদ্বুদ সাজান বা সন্নিবেশ সাজান
ও (এন 3 ) - দুটি অ × n ম্যাট্রিককে সাধারণ অ্যালগরিদম দ্বারা গুণ করে
ও (সি এন ) - গতিশীল প্রোগ্রামিং ব্যবহার করে ভ্রমণকারী বিক্রয় সমস্যার সমস্যার (সঠিক) সমাধান সন্ধান করা; দুটি লজিক্যাল স্টেটমেন্ট ব্রুট ফোর্স ব্যবহার করে সমান কিনা তা নির্ধারণ করে
ও (এন!) - ব্রুট ফোর্স অনুসন্ধানের মাধ্যমে ভ্রমণের বিক্রয়কর্মীর সমস্যা সমাধান করা
ও (এন এন ) - অ্যাসিপোটোটিক জটিলতার জন্য সহজ সূত্রগুলি তৈরি করতে প্রায়শই ও (এন!) এর পরিবর্তে ব্যবহৃত হয়
x&1==1
বিজোড়তা পরীক্ষা করতে ব্যবহার করবেন না কেন ?
x & 1
যথেষ্ট হবে, চেক করার দরকার নেই == 1
; সিতে অপারেটর অগ্রাধিকারের জন্য ধন্যবাদx&1==1
হিসাবে মূল্যায়ন করা হয় , সুতরাং এটি পরীক্ষার মতোই একই )। আমি মনে করি আপনি উত্তরটি ভুলভাবে লিখছেন; সেখানে একটি আধা-কোলন আছে, কমা নয়। এটি বৈষম্য / বিজোড় পরীক্ষার জন্য আপনার দেখার টেবিলের প্রয়োজন হবে না তা বলছে না, এটি উভয়টি / জোড় টেস্টিং এবং অনুসন্ধানের টেবিল পরীক্ষা করা অপারেশন are x&(1==1)
x&1
O(1)
ছোট অনুস্মারক: big O
সংকেতটি অ্যাসিপটোটিক জটিলতা বোঝাতে ব্যবহৃত হয় (এটি যখন সমস্যাটির আকার অনন্ত হয়ে যায়) এবং এটি একটি ধ্রুবককে আড়াল করে।
এর অর্থ হ'ল ও (এন) এর একটি অ্যালগরিদমের মধ্যে এবং ও (এন 2 ) এর মধ্যে দ্রুততমটি সর্বদা প্রথমটি হয় না (যদিও সেখানে সর্বদা n এর মান থাকে যা আকারের সমস্যার ক্ষেত্রে> এন, প্রথম অ্যালগরিদম হয়) দ্রুততর).
নোট করুন যে গোপন ধ্রুবকটি প্রয়োগের উপর নির্ভর করে!
এছাড়াও, কিছু ক্ষেত্রে, রানটাইম ইনপুটটির আকার n এর একটি ডিস্ট্রিমেন্টিক ফাংশন নয় । উদাহরণস্বরূপ দ্রুত বাছাই করে বাছাই করুন: এন উপাদানগুলির একটি অ্যারে বাছাই করার জন্য প্রয়োজনীয় সময়টি ধ্রুবক নয় তবে অ্যারের প্রারম্ভিক কনফিগারেশনের উপর নির্ভর করে।
বিভিন্ন সময় জটিলতা আছে:
গড় কেস (সাধারণত বের করা অনেক কঠিন ...)
...
একটি ভাল ভূমিকা হ'ল আর। সেডজউইক এবং পি ফ্লাজলেট দ্বারা রচিত অ্যালগরিদমের বিশ্লেষণের একটি ভূমিকা ।
আপনি যেমনটি বলেছেন, কোডটি অনুকূলকরণের সময় premature optimisation is the root of all evil
এবং (যদি সম্ভব হয়) প্রকৃত প্রোফাইলিং সর্বদা ব্যবহার করা উচিত। এমনকি এটি আপনাকে আপনার অ্যালগোরিদমের জটিলতা নির্ধারণে সহায়তা করতে পারে।
এখানে উত্তর দেখে আমি মনে করি আমরা উপসংহারে আসতে পারি যে আমাদের অধিকাংশ প্রকৃতপক্ষে দ্বারা অ্যালগরিদম ক্রম আনুমানিক না খুঁজছি এটা এবং এর পরিবর্তে দিয়ে গণক সাধারণ জ্ঞান ব্যবহার, উদাহরণস্বরূপ, মাস্টার পদ্ধতি হিসাবে আমরা বিশ্ববিদ্যালয়ে চিন্তা করা হয়। এর সাথে আমার অবশ্যই যোগ করতে হবে যে এমনকি অধ্যাপক আমাদের কেবল এটি গণনা করার পরিবর্তে এটি সম্পর্কে ভাবতে উত্সাহিত করেছিলেন (পরে) ।
এছাড়াও এটি সংযুক্ত ফাংশনগুলির জন্য কীভাবে করা হয় তা যুক্ত করতে চাই :
ধরুন আমাদের ( স্কিম কোড ) এর মতো একটি ফাংশন রয়েছে :
(define (fac n)
(if (= n 0)
1
(* n (fac (- n 1)))))
যা পুনরাবৃত্তভাবে প্রদত্ত সংখ্যার ফ্যাকটোরিয়াল গণনা করে।
প্রথম পদক্ষেপটি হ'ল কেবলমাত্র এই ক্ষেত্রে ফাংশনটির শরীরের জন্য পারফরম্যান্সের বৈশিষ্ট্যটি নির্ধারণের চেষ্টা করা , শরীরে বিশেষ কিছু করা হয় না, কেবল একটি গুণ (বা মান 1 ফেরত)।
সুতরাং শরীরের জন্য কর্মক্ষমতা: ও (1) (ধ্রুবক)।
পরবর্তী চেষ্টা করুন এবং পুনরাবৃত্তির কলগুলির জন্য এটি নির্ধারণ করুন । এই ক্ষেত্রে আমাদের কাছে এন -1 পুনরাবৃত্ত কল রয়েছে।
সুতরাং পুনরাবৃত্তির কলগুলির জন্য সম্পাদনাটি হ'ল: ও (এন -1) (অর্ডার এন, যেমন আমরা তুচ্ছ অংশগুলি ফেলে দিই)।
তারপরে এই দুটিকে একসাথে রাখুন এবং তারপরে পুরো পুনরাবৃত্ত ফাংশনের জন্য আপনার পারফরম্যান্স থাকবে:
1 * (এন -1) = ও (এন)
পিটার , আপনার উত্থাপিত বিষয়গুলির উত্তর দিতে ; আমি এখানে যে পদ্ধতিটি বর্ণনা করছি তা বাস্তবে এটি বেশ ভালভাবে পরিচালনা করে। তবে মনে রাখবেন যে এটি এখনও একটি অনুমান এবং সম্পূর্ণ গাণিতিকভাবে সঠিক উত্তর নয়। এখানে বর্ণিত পদ্ধতিটিও আমাদের বিশ্ববিদ্যালয়ে যে পদ্ধতিতে শেখানো হয়েছিল তার মধ্যে একটি এবং আমি যদি মনে করি সঠিকভাবে আমি এই উদাহরণটিতে ব্যবহৃত ফ্যাকটোরিয়ালের চেয়ে অনেক বেশি উন্নত অ্যালগরিদমের জন্য ব্যবহৃত হত।
অবশ্যই এটি সমস্ত নির্ভর করে যে আপনি ফাংশনটির শরীরের চলমান সময় এবং পুনরাবৃত্ত কলগুলির সংখ্যাটি কতটা ভালভাবে অনুমান করতে পারেন তার উপর নির্ভর করে তবে অন্যান্য পদ্ধতির ক্ষেত্রে এটি ঠিক ঠিক।
যদি আপনার ব্যয়টি বহুবর্ষীয় হয় তবে কেবলমাত্র তার গুণক ছাড়াই সর্বোচ্চ-অর্ডার শর্তটি রাখুন। উদাহরণ:
হে ((ঢ / 2 + 1 টি) * (ঢ / 2)) = হে (ঢ 2 /4 + N / 2) = হে (ঢ 2 /4) = হে (ঢ 2 )
এটি অসীম সিরিজের জন্য কাজ করে না, মনে রাখবেন। সাধারণ ক্ষেত্রে কোনও একক রেসিপি নেই, যদিও কিছু সাধারণ ক্ষেত্রে, নিম্নলিখিত অসমতা প্রয়োগ হয়:
ও (লগ এন ) <ও ( এন ) <ও ( এন লগ এন ) <ও ( এন 2 ) <ও ( এন কে ) <ও (ই এন ) <ও ( এন !)
আমি তথ্যের দিক দিয়ে এটি সম্পর্কে চিন্তা করি। যে কোনও সমস্যা নির্দিষ্ট সংখ্যক বিট শেখার সমন্বয়ে গঠিত।
আপনার মূল সরঞ্জামটি সিদ্ধান্ত পয়েন্ট এবং তাদের এনট্রপি ধারণা। কোনও সিদ্ধান্ত পয়েন্টের এনট্রপি হ'ল এটি আপনাকে দেওয়া গড় তথ্য। উদাহরণস্বরূপ, যদি কোনও প্রোগ্রামে দুটি শাখার সাথে কোনও সিদ্ধান্ত পয়েন্ট থাকে, তবে এটি এনট্রপি হ'ল প্রতিটি শাখার সম্ভাবনার সমষ্টিটি সেই শাখার বিপরীত সম্ভাবনার লগ 2 বারের বার করে । এই সিদ্ধান্তটি কার্যকর করে আপনি কতটা শিখছেন।
উদাহরণস্বরূপ, if
দুটি শাখা রয়েছে এমন একটি বিবৃতিতে উভয়ই সমানভাবে সম্ভবত, 1/2 * লগ (2/1) + 1/2 * লগ (2/1) = 1/2 * 1 + 1/2 * 1 এর এনট্রপি রয়েছে = 1. সুতরাং এর এনট্রপি 1 বিট is
মনে করুন আপনি এন = 1024 এর মতো এন আইটেমের একটি সারণী সন্ধান করছেন। এটি একটি 10-বিট সমস্যা কারণ লগ (1024) = 10 বিট। সুতরাং আপনি যদি এটি বিবৃতি দিয়ে সন্ধান করতে পারেন যার সমান সম্ভাব্য ফলাফল রয়েছে তবে এটির জন্য 10 টি সিদ্ধান্ত নেওয়া উচিত।
আপনি বাইনারি অনুসন্ধানের সাথে এটি পান।
মনে করুন আপনি লিনিয়ার অনুসন্ধান করছেন। আপনি প্রথম উপাদানটির দিকে তাকান এবং জিজ্ঞাসা করুন এটি কি আপনি চান এটি কিনা। সম্ভাবনাগুলি হ'ল এটি 1-1024 এবং 1023/1024 যা এটি নয়। সেই সিদ্ধান্তের এনট্রপিটি 1/1024 * লগ (1024/1) + 1023/1024 * লগ (1024/1023) = 1/1024 * 10 + 1023/1024 * প্রায় 0 = প্রায় .01 বিট। আপনি খুব অল্প শিখেছি! দ্বিতীয় সিদ্ধান্তটি এর চেয়ে ভাল নয়। এই কারণেই লিনিয়ার অনুসন্ধান এত ধীর। আসলে এটি আপনাকে শিখতে হবে এমন বিট সংখ্যার মধ্যে সূচকীয়।
ধরুন আপনি ইনডেক্সিং করছেন। ধরুন, টেবিলটি অনেকগুলি বিনের মধ্যে পূর্বে সাজানো হয়েছে, এবং আপনি কিছুতে বিটগুলির কিছুটি সরাসরি টেবিলের প্রবেশের সূচকে ব্যবহার করেন। যদি 1024 টি বিন থাকে তবে সমস্ত 1024 সম্ভাব্য ফলাফলের জন্য এনট্রপিটি 1/1024 * লগ (1024) + 1/1024 * লগ (1024) + ... হয়। এটি 1/1024 * 10 বার 1024 ফলাফল, বা এটির একটি সূচীকরণ ক্রিয়াকলাপের জন্য 10 বিট এনট্রপি। এজন্য সূচীকরণ অনুসন্ধান দ্রুত।
এখন বাছাই সম্পর্কে চিন্তা করুন। আপনার কাছে এন আইটেম রয়েছে এবং আপনার একটি তালিকা রয়েছে। প্রতিটি আইটেমের জন্য আপনাকে তালিকায় আইটেমটি কোথায় যায় তা অনুসন্ধান করতে হবে এবং তারপরে তালিকায় যুক্ত করতে হবে। সুতরাং বাছাই করতে অন্তর্নিহিত অনুসন্ধানের ধাপগুলির সংখ্যা প্রায় N এর বেশি হয়।
সুতরাং বাইনারি সিদ্ধান্তের ভিত্তিতে প্রকারভেদে প্রায় সমান সম্ভাব্য ফলাফলগুলি সমস্ত ও (এন লগ এন) পদক্ষেপ গ্রহণ করে। একটি ও (এন) বাছাই অ্যালগরিদম যদি এটি অনুসন্ধানের উপর ভিত্তি করে থাকে তবে সম্ভব হয়।
আমি খুঁজে পেয়েছি যে প্রায় সমস্ত অ্যালগোরিদমিক পারফরম্যান্সের সমস্যাগুলি এইভাবে দেখা যায়।
শুরু থেকে শুরু করা যাক।
প্রথমত, নীতিটি মেনে নিন যে ডেটাতে কিছু নির্দিষ্ট সাধারণ ক্রিয়াকলাপ O(1)
সময়ে করা যেতে পারে , অর্থাত্ ইনপুট আকারের চেয়ে স্বতন্ত্র time সিতে এই আদিম ক্রিয়াগুলি সমন্বিত
এই নীতিটির ন্যায়সঙ্গত হওয়ার জন্য একটি সাধারণ কম্পিউটারের মেশিনের নির্দেশাবলী (আদিম পদক্ষেপ) এর বিশদ অধ্যয়ন প্রয়োজন। বর্ণিত প্রতিটি অপারেশন কিছু সংখ্যক মেশিনের নির্দেশাবলী দিয়ে করা যেতে পারে; প্রায়শই এক বা দুটি নির্দেশের প্রয়োজন হয়। ফলস্বরূপ, সি এর বিভিন্ন ধরণের বিবৃতি O(1)
সময় কার্যকর করা যেতে পারে, অর্থাত্ ইনপুট থেকে কিছুটা ধীরে ধীরে সময় স্বতন্ত্র থাকে। এই সহজ অন্তর্ভুক্ত
সি-তে, অনেকগুলি লুপগুলি কিছু সূচকে সূচক ভেরিয়েবলের সূচনা করে এবং লুপের চারপাশে প্রতিবার 1 দ্বারা পরিবর্তনশীল বৃদ্ধি করে তৈরি হয়। সূচকটি কিছু সীমাতে পৌঁছে ফোর-লুপটি শেষ হয়। উদাহরণস্বরূপ, জন্য লুপ
for (i = 0; i < n-1; i++)
{
small = i;
for (j = i+1; j < n; j++)
if (A[j] < A[small])
small = j;
temp = A[small];
A[small] = A[i];
A[i] = temp;
}
সূচক ভেরিয়েবল ব্যবহার করে i। এটি প্রতিবার লুপের চারপাশে 1 দ্বারা বৃদ্ধি পায় এবং আমি এন - 1 এ পৌঁছালে পুনরাবৃত্তিগুলি বন্ধ হয়।
যাইহোক, এই মুহুর্তের জন্য, ফর্ম-লুপের সহজ ফর্মের দিকে ফোকাস করুন, যেখানে সূচক পরিবর্তনশীল বর্ধিত পরিমাণের দ্বারা বিভক্ত চূড়ান্ত এবং প্রাথমিক মানগুলির মধ্যে পার্থক্য আমাদের জানায় আমরা কতবার লুপের চারপাশে যাই । এই গণনাটি সঠিক, যদি না লাফের স্টেটমেন্টের মাধ্যমে লুপ থেকে বেরিয়ে আসার উপায় থাকে; এটি যে কোনও ক্ষেত্রে পুনরাবৃত্তির সংখ্যার উপরের একটি বাউন্ড।
উদাহরণস্বরূপ, লুপটির জন্য ((n − 1) − 0)/1 = n − 1 times
পুনরাবৃত্তি ঘটে, যেহেতু 0 i এর প্রাথমিক মান, n - 1 হ'ল i দ্বারা পৌঁছে যাওয়া সর্বোচ্চ মান (যেমন, যখন আমি n − 1 এ পৌঁছায়, লুপটি বন্ধ হয়ে যায় এবং i = n− এর সাথে কোনও পুনরাবৃত্তি ঘটে না) 1), এবং 1 টি লুপের প্রতিটি পুনরাবৃত্তিতে যুক্ত হবে।
সরল ক্ষেত্রে, যেখানে প্রতিটি পুনরাবৃত্তির জন্য লুপের শরীরে ব্যয় করা সময় একই হয়, আমরা লুপের চারপাশে বারের সংখ্যার সাহায্যে শরীরের জন্য বিগ-ওহ উপরের গণ্ডাকে গুণ করতে পারি । কড়া কথায় বলতে গেলে লুপ ইনডেক্সের সীমাবদ্ধতার সাথে প্রথম তুলনা করার জন্য আমাদের অবশ্যই ল (সূচী) ও ও (1) সময় যুক্ত করতে হবে , কারণ আমরা লুপটির চারপাশে যাওয়ার চেয়ে আরও একবার সময় পরীক্ষা করি। যাইহোক, লুপটি শূন্য বার কার্যকর করা সম্ভব না হলে লুপটি আরম্ভ করার সময় এবং একবারে সীমাটি পরীক্ষা করার সময় হ'ল নিম্ন-অর্ডার শব্দটি যা সংক্ষেপ নিয়মের দ্বারা বাদ দেওয়া যায়।
এখন এই উদাহরণটি বিবেচনা করুন:
(1) for (j = 0; j < n; j++)
(2) A[i][j] = 0;
আমরা জানি যে রেখাটি (1)O(1)
সময় নেয় । স্পষ্টতই, আমরা লুপটির প্রায় বার ঘুরে যাই, যেমন আমরা রেখার (1) পাওয়া উপরের সীমাটি থেকে নিম্ন সীমাটি বিয়োগ করে এবং তারপরে 1 যোগ করে নির্ধারণ করতে পারি যেহেতু দেহ, রেখা (2), O (1) সময় নেয়, আমরা j বৃদ্ধি করার সময় এবং n এর সাথে j এর তুলনা করার সময়টিকে অবহেলা করতে পারি, উভয়ই ও (1) are সুতরাং, লাইনের চলমান সময় (1) এবং (2) n এবং O (1) এর গুণফল , যা হয় O(n)
।
একইভাবে, আমরা বাইরের লুপের চলমান সময়কে লাইনগুলি (2) (4) এর মাধ্যমে অন্তর্ভুক্ত করতে পারি, যা এটি
(2) for (i = 0; i < n; i++)
(3) for (j = 0; j < n; j++)
(4) A[i][j] = 0;
আমরা ইতিমধ্যে প্রতিষ্ঠিত করেছি যে রেখার লুপ (3) এবং (4) ও (এন) সময় নেয়। সুতরাং, আমি i বাড়াতে ও (1) সময়টিকে অবহেলা করতে পারি এবং প্রতিটি পুনরাবৃত্তিতে আমি <এন কিনা তা পরীক্ষা করে দেখতে পারি যে বাইরের লুপের প্রতিটি পুনরাবৃত্তিটি ও (এন) সময় নেয়।
বাইরের লুপের i = 0 আরম্ভের এবং (n + 1) স্ট্যান্ডের শর্ত পরীক্ষা <i অনুরূপভাবে O (1) সময় নেয় এবং উপেক্ষিত হতে পারে। পরিশেষে, আমরা পর্যবেক্ষণ করেছি যে আমরা বাইরের লুপটি n বার বার ঘুরে বেড়াচ্ছি, প্রতিটি পুনরাবৃত্তির জন্য ও (এন) সময় নিয়ে মোট
O(n^2)
চলমান সময় দিচ্ছি।
আরও বাস্তব উদাহরণ।
আপনি যদি কোডটি বিশ্লেষণ না করে নিজের কোডটির ক্রম অনুমিতভাবে অনুমান করতে চান, আপনি আপনার কোডের এন এবং সময়ের ক্রমবর্ধমান মানগুলির একটি ধারাতে আটকে থাকতে পারেন। লগ স্কেলে আপনার সময়গুলি প্লট করুন। কোডটি যদি ও (x ^ n) হয় তবে মানগুলি opeাল n এর একটি লাইনে পড়তে হবে।
এটি কেবল কোড অধ্যয়ন করার বিভিন্ন সুবিধা রয়েছে। একটি জিনিসের জন্য, আপনি দেখতে পাচ্ছেন যে আপনি যে সময়টিতে চলেছেন সেখানে রান সময়টি তার অ্যাসিম্পটোটিক ক্রমের কাছে চলে আসে। এছাড়াও, আপনি দেখতে পাচ্ছেন যে কিছু কোড যা আপনি ভেবেছিলেন যে ও (x) অর্ডার হয়েছে তা হ'ল অর্ডার হ'ল ও (x ^ 2), উদাহরণস্বরূপ, লাইব্রেরি কলগুলিতে সময় ব্যয় করার কারণে।
মূলত 90% সময় কাটানো জিনিসটি কেবল লুপগুলি বিশ্লেষণ করে। আপনার কি একক, ডাবল, ট্রিপল নেস্ট লুপ রয়েছে? আপনার ও (এন), ও (এন ^ 2), ও (এন ^ 3) চলমান সময় রয়েছে।
খুব কমই (যদি আপনি একটি বিস্তৃত বেস গ্রন্থাগার দিয়ে প্ল্যাটফর্ম না লিখে থাকেন (উদাহরণস্বরূপ,। নেট বিসিএল, বা সি ++ এর এসটিএল) আপনি এমন কোনও কিছুই দেখতে পাবেন যা কেবলমাত্র আপনার লুপগুলি দেখার চেয়ে আরও কঠিন) (বিবৃতি দেওয়ার জন্য, যাও, ইত্যাদি ...)
বিগ ও স্বরলিপি দরকারী কারণ এটির সাথে কাজ করা সহজ এবং অপ্রয়োজনীয় জটিলতা এবং বিশদগুলি লুকায় (অপ্রয়োজনীয় কিছু সংজ্ঞা দেওয়ার জন্য)। বিভাজন এবং অ্যালগরিদমকে জয় করার জটিলতার বাইরে কাজ করার একটি দুর্দান্ত উপায় হ'ল গাছ পদ্ধতি। ধরা যাক আপনার মাঝারি পদ্ধতির সাথে কুইকোর্টের একটি সংস্করণ রয়েছে, তাই আপনি প্রতিবার অ্যারেটিকে পুরোপুরি ভারসাম্যপূর্ণ সাববারে বিভক্ত করেন।
আপনার সাথে কাজ করা সমস্ত অ্যারে সম্পর্কিত একটি গাছ তৈরি করুন। মূলটিতে আপনার মূল অ্যারে রয়েছে, মূলটিতে দুটি শিশু রয়েছে যা সাবারি রয়েছে ra আপনার নীচে একক উপাদান অ্যারে না হওয়া পর্যন্ত এটি পুনরাবৃত্তি করুন।
যেহেতু আমরা ও (এন) সময়ে মধ্যমটি খুঁজে পেতে পারি এবং ও (এন) সময়ে দুটি অংশে অ্যারের ভাগ করে নিতে পারি, তাই প্রতিটি নোডে সম্পন্ন কাজটি হ'ল (কে) যেখানে k অ্যারের আকার হয়। গাছের প্রতিটি স্তরের (সর্বাধিক) সম্পূর্ণ অ্যারে থাকে তাই স্তর অনুসারে কাজটি হ'ল (এন) (সাবহারির আকারগুলি এন পর্যন্ত যুক্ত হয়, এবং যেহেতু আমাদের স্তরে ও (কে) থাকে তাই আমরা এটি যুক্ত করতে পারি) । গাছটিতে কেবলমাত্র লগ (এন) স্তর থাকে যতক্ষণ না প্রতিটি সময় আমরা ইনপুট অর্ধেক করে রাখি।
অতএব আমরা ও (এন * লগ (এন)) দ্বারা কাজের পরিমাণকে উপরের সীমাবদ্ধ করতে পারি।
তবে, বিগ ও কিছু বিবরণ গোপন করে যা আমরা মাঝে মাঝে উপেক্ষা করতে পারি না। ফিবোনাচি সিক্যুয়েন্সটি গণনা করার বিষয়ে বিবেচনা করুন
a=0;
b=1;
for (i = 0; i <n; i++) {
tmp = b;
b = a + b;
a = tmp;
}
এবং কেবল ধরে নিই যে a এবং b জাভাতে বিগইন্টিজার বা এমন কিছু যা নির্বিচারে সংখ্যক সংখ্যক পরিচালনা করতে পারে। বেশিরভাগ লোকেরা বলবেন এটি কোনও ওঠা (এন) অ্যালগরিদম ছাড়ানো ছাড়াই। যুক্তিটি হ'ল আপনার লুপের জন্য এন পুনরাবৃত্তি রয়েছে এবং লুপের পাশে ও (1) এর কাজ রয়েছে।
তবে ফিবোনাচি সংখ্যা বড়, এন-থাই ফিবোনাচি সংখ্যাটি এনে এক্সপোনেনশিয়াল তাই কেবল সংরক্ষণ করা এটি এন বাইটের ক্রম হিসাবে গ্রহণ করবে। বড় পূর্ণসংখ্যার সাথে সংযোজন সম্পাদন করতে ও (এন) এর পরিমাণের পরিমাণ লাগবে। সুতরাং এই পদ্ধতিতে কাজ মোট পরিমাণ হয়
1 + 2 + 3 + ... + এন = এন (এন -1) / 2 = ও (এন ^ 2)
সুতরাং এই অ্যালগরিদম চতুর্ভুজ সময় চালায়!
অ্যালগরিদমকে টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো করার জন্য এবং বড় হে অপারেটরগুলির সাথে একত্রিত করুন। এটিই আমি জানি।
আরও তথ্যের জন্য, বিষয়টির উইকিপিডিয়া পৃষ্ঠাটি দেখুন ।
আমি যে অ্যালগরিদম / ডেটা স্ট্রাকচার ব্যবহার করি এবং / বা পুনরাবৃত্তি নেস্টিংয়ের তাত্ক্ষণিক বিশ্লেষণের সাথে পরিচিতি। অসুবিধা হ'ল আপনি যখন কোনও লাইব্রেরির ফাংশনটি কল করেন, সম্ভবত একাধিকবার - আপনি প্রায়শই অনিশ্চিত থাকতে পারেন যে আপনি সময়কালে অযথা ফাংশনটি কল করছেন বা তারা কোন প্রয়োগ প্রয়োগ করছেন। সম্ভবত লাইব্রেরির ফাংশনগুলির জটিলতা / দক্ষতা পরিমাপ হওয়া উচিত, তা সে বিগ হে বা অন্য কোনও মেট্রিক হোক, এটি ডকুমেন্টেশন বা এমনকি ইন্টেলিসেন্সে উপলভ্য ।
"আপনি কীভাবে হিসাব করবেন" বিগ ও, এটি গণনা জটিল জটিলতার তত্ত্বের অংশ । কিছু (অনেক) বিশেষ ক্ষেত্রে আপনি কিছু সহজ হিউরিস্টিক্স (যেমন নেস্টেড লুপগুলির জন্য গুণমান লুপের সংখ্যা) নিয়ে আসতে সক্ষম হবেন, esp। যখন আপনি যা চান তা হ'ল কোনও উচ্চতর আবদ্ধ অনুমান, এবং এটি খুব হতাশাবাদী হলে আপনি আপত্তি করবেন না - যা আমি অনুমান করি আপনার প্রশ্নটি সম্ভবত এটিই।
আপনি যদি সত্যিই কোনও অ্যালগরিদমের জন্য আপনার প্রশ্নের উত্তর দিতে চান তবে আপনি এই তত্ত্বটি প্রয়োগ করতে পারেন। সরল "খারাপ পরিস্থিতি" বিশ্লেষণের পাশাপাশি আমি অনুশীলিত বিশ্লেষণকে অনুশীলনে খুব দরকারী বলে মনে করেছি ।
1 ম কেস জন্য ভেতরের লুপ কার্যকর n-i
, বার তাই মৃত্যুদণ্ড কার্যকর মোট সংখ্যা জন্য সমষ্টি i
থেকে যাচ্ছে 0
করার n-1
এর (কারণ সমান নিম্ন চেয়ে কম বা না হোক) n-i
। আপনি শেষ পর্যন্ত n*(n + 1) / 2
, তাই পেতে O(n²/2) = O(n²)
।
২ য় লুপের জন্য, বাইরের লুপের i
মধ্যে 0
এবং n
অন্তর্ভুক্ত; তারপরে অভ্যন্তরীণ লুপটি কার্যকর করা হয় যখন j
তার চেয়ে কঠোরভাবে বড় হয় n
, যা তখন অসম্ভব।
মাস্টার পদ্ধতিটি (বা এর একটি বিশেষত্ব) ব্যবহার করার পাশাপাশি আমি পরীক্ষামূলকভাবে আমার অ্যালগরিদমগুলি পরীক্ষা করি। এটি প্রমাণ করতে পারে না যে কোনও নির্দিষ্ট জটিলতা শ্রেণি অর্জন করা হয়েছে, তবে এটি গাণিতিক বিশ্লেষণ উপযুক্ত কিনা তা আশ্বাস প্রদান করতে পারে। এই আশ্বাসে সহায়তার জন্য, আমি আমার পরীক্ষাগুলির সাথে একত্রে কোড কভারেজ সরঞ্জামগুলি ব্যবহার করি, এটি নিশ্চিত করতে যে আমি সমস্ত ক্ষেত্রে ব্যায়াম করছি।
খুব সাধারণ উদাহরণ হিসাবে বলুন যে আপনি .NET ফ্রেমওয়ার্কের তালিকা সাজানোর গতিতে স্যানিটি পরীক্ষা করতে চেয়েছিলেন। আপনি নীচের মতো কিছু লিখতে পারেন, তারপরে এক্সেলের ফলাফলগুলি বিশ্লেষণ করে নিশ্চিত করুন যে তারা কোনও এন * লগ (এন) বক্ররেখা ছাড়িয়েছে না।
এই উদাহরণে আমি তুলনার সংখ্যা পরিমাপ করি তবে প্রতিটি নমুনার আকারের জন্য প্রয়োজনীয় সময়টি পরীক্ষা করাও বুদ্ধিমানের। তবে আপনাকে অবশ্যই আরও সতর্ক হতে হবে যে আপনি কেবল অ্যালগোরিদম পরিমাপ করছেন এবং আপনার পরীক্ষার অবকাঠামো থেকে নিদর্শনগুলিও অন্তর্ভুক্ত করছেন না।
int nCmp = 0;
System.Random rnd = new System.Random();
// measure the time required to sort a list of n integers
void DoTest(int n)
{
List<int> lst = new List<int>(n);
for( int i=0; i<n; i++ )
lst[i] = rnd.Next(0,1000);
// as we sort, keep track of the number of comparisons performed!
nCmp = 0;
lst.Sort( delegate( int a, int b ) { nCmp++; return (a<b)?-1:((a>b)?1:0)); }
System.Console.Writeline( "{0},{1}", n, nCmp );
}
// Perform measurement for a variety of sample sizes.
// It would be prudent to check multiple random samples of each size, but this is OK for a quick sanity check
for( int n = 0; n<1000; n++ )
DoTest(n);
স্পেস জটিলতাগুলির জন্যও অনুমতি দিতে ভুলবেন না যা যদি কারও কাছে সীমিত স্মৃতির সংস্থান থাকে তবে উদ্বেগের কারণ হতে পারে। সুতরাং উদাহরণস্বরূপ আপনি শুনতে পাচ্ছেন যে কেউ ধ্রুবক স্পেস অ্যালগরিদম চাইছেন যা মূলত এটি বলার একটি উপায় যা অ্যালগরিদমের দ্বারা নেওয়া স্থানের পরিমাণ কোডের অভ্যন্তরের কোনও কারণের উপর নির্ভর করে না।
কখনও কখনও জটিলতা থেকে বোঝা যায় যে কতবার কিছু বলা হয়, কতবার একটি লুপ কার্যকর হয়, কতবার মেমরি বরাদ্দ করা হয়, এবং এই জাতীয় প্রশ্নের উত্তর দেওয়ার আরও একটি অংশ।
শেষ অবধি, বড় ও সবচেয়ে খারাপ ক্ষেত্রে, সেরা কেস এবং orণকরণের ক্ষেত্রে ব্যবহার করা যেতে পারে যেখানে সাধারণত এটি সবচেয়ে খারাপ ক্ষেত্রে যা অ্যালগোরিদমকে কতটা খারাপ হতে পারে তা বর্ণনা করার জন্য ব্যবহৃত হয়।
আপনার অ্যালগোরিদমের প্রত্যাশিত আচরণটি প্রায়শই কী উপেক্ষা করা হয় । এটি আপনার অ্যালগরিদমের বিগ-ও পরিবর্তন করে না , তবে এটি "অকালীন অপটিমাইজেশন ... .." বিবৃতিটির সাথে সম্পর্কিত does
আপনার অ্যালগরিদমের প্রত্যাশিত আচরণটি হ'ল - খুব ডাবিত হয়ে পড়ে - আপনি যে অ্যালগোরিদমটি সম্ভবত দেখবেন এমন ডেটাতে কাজ করতে আপনি কত দ্রুত আশা করতে পারেন।
উদাহরণস্বরূপ, আপনি যদি কোনও তালিকার কোনও মান সন্ধান করছেন তবে এটি হে (এন), তবে আপনি যদি জানেন যে বেশিরভাগ তালিকার মধ্যে আপনার মানটি সামনে থাকে তবে আপনার অ্যালগরিদমের সাধারণ আচরণটি দ্রুত।
এটি সত্যিই পেরেক করার জন্য আপনার "ইনপুট স্পেস" এর সম্ভাব্যতা বন্টনকে বর্ণনা করতে সক্ষম হতে হবে (যদি আপনাকে একটি তালিকা সাজানোর প্রয়োজন হয় তবে সেই তালিকাটি ইতিমধ্যে কতবার বাছাই করা যায়? এটি কতবার সম্পূর্ণ বিপরীত হয়? প্রায়শই এটি বেশিরভাগ ক্ষেত্রে বাছাই করা হয়?) এটি সর্বদা সম্ভব হয় না যে আপনি এটি জানেন তবে কখনও কখনও আপনি তা করেন।
দুর্দান্ত প্রশ্ন!
দাবি অস্বীকার: এই উত্তরে মিথ্যা বিবৃতি রয়েছে নীচের মন্তব্যগুলি দেখুন।
আপনি যদি বিগ ও ব্যবহার করছেন তবে আপনি আরও খারাপ মামলার কথা বলছেন (এর পরে কী বোঝায় তার আরও বেশি)। তদতিরিক্ত, গড় ক্ষেত্রে জন্য মূলধন থিটা এবং সেরা ক্ষেত্রে একটি বড় ওমেগা রয়েছে।
বিগ ও এর একটি সুন্দর আনুষ্ঠানিক সংজ্ঞা জন্য এই সাইটটি দেখুন: https://xlinux.nist.gov/dads/HTML/bigOnotation.html
f (n) = O (g (n)) এর অর্থ c এবং k এর ধনাত্মক ধ্রুবক রয়েছে, যেমন সমস্ত n ≥ k এর জন্য 0 ≤ f (n) ≤ cg (n)। সি এবং কে এর মানগুলি অবশ্যই ফ এর জন্য নির্ধারণ করতে হবে এবং এটি n এর উপর নির্ভর করবে না।
ঠিক আছে, তাহলে এখন "বেস্ট-কেস" এবং "সবচেয়ে খারাপ ক্ষেত্রে" জটিলতা বলতে আমরা কী বুঝি?
এটি সম্ভবত উদাহরণগুলির মাধ্যমে সর্বাধিক স্পষ্টভাবে চিত্রিত হয়েছে। উদাহরণস্বরূপ, যদি আমরা একটি সাজানো অ্যারেতে একটি সন্ধানের জন্য লিনিয়ার অনুসন্ধান ব্যবহার করি তবে সবচেয়ে খারাপ পরিস্থিতিটি যখন আমরা অ্যারের শেষ উপাদানটি অনুসন্ধান করার সিদ্ধান্ত নিই তেমনি অ্যারেতে আইটেম রয়েছে যতগুলি পদক্ষেপ নেওয়া হবে। সবচেয়ে ভাল কেসটি হ'ল যখন আমরা প্রথম উপাদানটি অনুসন্ধান করব যেহেতু আমরা প্রথম চেক পরে সম্পন্ন করব।
এই সমস্ত বিশেষণ- কেস জটিলতার বিন্দুটি হ'ল আমরা একটি অনুমানমূলক প্রোগ্রামটি নির্দিষ্ট ভেরিয়েবলের আকারের ক্ষেত্রে পরিপূর্ণতা অর্জন করতে যে পরিমাণ সময় চালায় সেগুলি গ্রাফ করার একটি উপায় অনুসন্ধান করছি। তবে অনেক অ্যালগরিদমের জন্য আপনি যুক্তি দিতে পারেন যে কোনও নির্দিষ্ট আকারের ইনপুটটির জন্য একক সময় নেই। লক্ষ্য করুন যে এটি কোনও ফাংশনের মৌলিক প্রয়োজনের সাথে বিরোধী, কোনও ইনপুটটির একাধিক আউটপুট থাকা উচিত নয়। সুতরাং আমরা একটি অ্যালগরিদমের জটিলতা বর্ণনা করতে একাধিক ফাংশন নিয়ে হাজির। এখন, যদিও আকারের অ্যারের অনুসন্ধানে আপনি অ্যারেটি যা খুঁজছেন এবং n এর সাথে আনুপাতিকভাবে নির্ভর করছেন তার উপর নির্ভর করে বিভিন্ন পরিমাণে সময় লাগতে পারে, তবে আমরা সেরা-কেস, গড়-কেস ব্যবহার করে অ্যালগরিদমের তথ্যমূলক বিবরণ তৈরি করতে পারি , এবং সবচেয়ে খারাপ ক্ষেত্রে ক্লাস।
দুঃখিত, এটি এত খারাপ লেখা হয়েছে এবং অনেক প্রযুক্তিগত তথ্যের অভাব রয়েছে। তবে আশা করি সময় জটিলতা ক্লাসগুলি সম্পর্কে চিন্তাভাবনা সহজ করে তুলবে। একবার আপনি এগুলির সাথে স্বাচ্ছন্দ্যবস্থ হয়ে উঠলে এটি আপনার প্রোগ্রামের মাধ্যমে পার্স করা এবং আপনার ডেটা স্ট্রাকচারের উপর নির্ভর করে লুপ লুপের মতো জিনিসগুলি সন্ধান করার মতো সাধারণ বিষয় হয়ে ওঠে যে কী ধরণের ইনপুট ক্ষুদ্রতর মামলার ফলস্বরূপ এবং কী ইনপুট ফলবে? সবচেয়ে খারাপ ক্ষেত্রে।
কীভাবে এটি প্রোগ্রামিয়ালি সমাধান করতে হয় তা আমি জানি না, তবে লোকেদের প্রথম কাজটি হ'ল আমরা যে কাজগুলি করেছি তার নির্দিষ্ট সংখ্যার জন্য অ্যালগরিদমকে নমুনা হিসাবে বলি, 4n ^ 2 + 2n + 1 আমাদের 2 টি বিধি রয়েছে:
যদি আমরা f (x) সরল করি, যেখানে f (x) হ'ল ক্রিয়াকলাপের সংখ্যার সূত্র, (4n ^ 2 + 2n + 1 উপরে বর্ণিত), আমরা এতে বিগ-ও মান পাই [ও (এন ^ 2) কেস]। তবে এটি প্রোগ্রামে ল্যাঞ্জরেজ ইন্টারপোলেশনের জন্য অ্যাকাউন্টে থাকতে হবে, এটি কার্যকর করা কঠিন হতে পারে। এবং যদি আসল বিগ-ও মান হ'ল ও (2 ^ n) হয় এবং আমাদের ও (x ^ n) এর মতো কিছু থাকতে পারে, তাই সম্ভবত এই অ্যালগরিদম প্রোগ্রামযোগ্য নয়। তবে যদি কেউ আমাকে ভুল প্রমাণ করে তবে আমাকে কোডটি দিন। । । ।
কোড এ এর জন্য, বহিরাগত লুপটি n+1
কয়েকবার সম্পাদিত হবে , '1' সময় মানে এমন প্রক্রিয়া যা আমি এখনও প্রয়োজনীয়তা পূরণ করি কিনা তা যাচাই করে। এবং অভ্যন্তরীণ লুপ n
বার, n-2
বার চালায় .... সুতরাং 0+2+..+(n-2)+n= (0+n)(n+1)/2= O(n²)
,।
কোড বি এর জন্য, যদিও অভ্যন্তরীণ লুপটি পদক্ষেপ এবং foo () চালায় না, তবে অভ্যন্তরীণ লুপটি n বারের জন্য কার্যকর করা হবে বাইরের লুপের নির্বাহের সময়ের উপর নির্ভর করে যা হে (এন)
আমি বিগ-ওকে কিছুটা ভিন্ন দিক দিয়ে ব্যাখ্যা করতে চাই।
বিগ-ও কেবল প্রোগ্রামগুলির জটিলতার সাথে তুলনা করা যার অর্থ ইনপুটগুলি যখন বাড়ছে এবং ক্রিয়া করতে ব্যয় করা সঠিক সময়টি নয়, তখন তারা কতটা বাড়ছে।
বড়-ও সূত্রগুলিতে আইএমএইচও আপনি আরও জটিল সমীকরণ ব্যবহার না করাই ভাল (আপনি নিম্নলিখিত গ্রাফের সাথে কেবল আঁকড়ে থাকতে পারেন)) তবে আপনি এখনও আরও সঠিক সূত্র ব্যবহার করতে পারেন (যেমন 3 ^ n, n ^ 3, .. ।) তবে এর চেয়ে বেশি কখনও কখনও বিভ্রান্তিকর হতে পারে! এটি যতটা সম্ভব সহজ রাখা আরও ভাল।
আমি আবারও জোর দিতে চাই যে এখানে আমরা আমাদের অ্যালগরিদমের সঠিক সূত্র পেতে চাই না। ইনপুটগুলি যখন বাড়ছে তখন কেবল কীভাবে এটি বৃদ্ধি পায় তা আমরা দেখতে চাই এবং সেই অর্থে অন্যান্য অ্যালগরিদমের সাথে তুলনা করি। অন্যথায় আপনি বেঞ্চ চিহ্নিতকরণের মতো বিভিন্ন পদ্ধতি ব্যবহার করতে পারেন।