আমি আসলে স্ট্যান্ডার্ড সেট পাত্রে নিজেকে বেশিরভাগই অকেজো বলে মনে করি এবং কেবল অ্যারে ব্যবহার করতে পছন্দ করি তবে আমি এটি অন্যভাবে করি।
সেট ছেদগুলি গণনা করতে, আমি প্রথম অ্যারে দিয়ে পুনরাবৃত্তি করি এবং একক বিট দিয়ে উপাদান চিহ্নিত করি। তারপরে আমি দ্বিতীয় অ্যারের মাধ্যমে পুনরাবৃত্তি করি এবং চিহ্নিত উপাদানগুলির সন্ধান করি। ভয়েলা, হ্যাশ টেবিলের চেয়ে অনেক কম কাজ এবং মেমরির সাথে রৈখিক সময়ে ছেদ স্থাপন করুন, উদাহরণস্বরূপ ইউনিয়ন এবং পার্থক্যগুলি এই পদ্ধতিটি ব্যবহার করে প্রয়োগ করা সমান সহজ। এটি সাহায্য করে যে আমার কোডবেসগুলি সূচকগুলির পরিবর্তে সূচকের উপাদানগুলির চারপাশে ঘুরে বেড়ায় (আমি উপাদানগুলির সূচকগুলি উপাদানগুলির উপাত্তগুলির মধ্যে নকল করি না) এবং খুব কমই বাছাই করার জন্য কিছু প্রয়োজন হয়, তবে আমি বছরের পর বছর কোনও সেট ডেটা কাঠামো ব্যবহার করি নি ফলাফল.
আমার কাছে কিছু অশুভ বিট-ফিডলিং সি কোড রয়েছে আমি যখন উপাদানগুলি যেমন উদ্দেশ্যে কোনও ডেটা ফিল্ড না দেয়। এতে ট্র্যাশড এলিমেন্টগুলি চিহ্নিত করার উদ্দেশ্যে সর্বাধিক উল্লেখযোগ্য বিট (যা আমি কখনই ব্যবহার করি না) সেট করে উপাদানগুলির মেমোরি ব্যবহার করে। এটি মোটামুটি স্থূল, যদি না আপনি সত্যিই অ্যাসেম্বলি স্তরে কাজ করে থাকেন তবে কেবল এটি উল্লেখ করতে চেয়েছিলেন যে উপাদানগুলি ট্র্যাভারসালের জন্য নির্দিষ্ট ক্ষেত্র নির্দিষ্ট না করে এমন ক্ষেত্রেও এটি কীভাবে প্রযোজ্য তা আপনি কীভাবে নিশ্চিত করতে পারেন যদি নির্দিষ্ট বিট কখনও ব্যবহার করা হবে না। এটি আমার ডিনকি আই 7 এর এক সেকেন্ডেরও কম সময়ে 200 মিলিয়ন উপাদানগুলির মধ্যে একটি সেট ছেদটি গণনা করতে পারে (2.4 জিগের তথ্য)। std::set
একই সময়ে প্রতিটি একশ মিলিয়ন উপাদান থাকা দুটি দৃষ্টান্তের মধ্যে একটি সেট ছেদ করার চেষ্টা করুন ; এমনকি কাছে আসে না।
যে সরাইয়া...
তবে আমি প্রতিটি এলিমেন্টোকে অন্য ভেক্টরে যুক্ত করে এবং উপাদানটি ইতিমধ্যে বিদ্যমান কিনা তা পরীক্ষা করেও এটি করতে পারি।
নতুন ভেক্টরটিতে ইতিমধ্যে কোনও উপাদান উপস্থিত রয়েছে কিনা তা যাচাই করা সাধারণত একটি রৈখিক সময়ের অপারেশন হতে চলেছে যা সেট ছেদটিকে নিজেই এক চতুর্ভুজ অপারেশন করে তুলবে (ইনপুট আকারের বিস্ফোরক পরিমাণের কাজ)। আমি যদি উপরের কৌশলটি সুপারিশ করি তবে আপনি যদি কেবল সাদামাটা পুরাতন ভেক্টর বা অ্যারে ব্যবহার করতে চান এবং এমনভাবে করেন যাতে চমকপ্রদভাবে স্কেল হয়।
মূলত: কোন ধরণের অ্যালগরিদমগুলির জন্য একটি সেট প্রয়োজন এবং অন্য কোনও ধারক ধরণের দিয়ে করা উচিত নয়?
আপনি যদি আমার পক্ষপাতদুষ্ট মতামত না জিজ্ঞাসা করেন তবে কিছুই নয় যদি আপনি ধারক স্তরে এটি সম্পর্কে কথা বলছেন (যেমন কোনও ডেটা স্ট্রাকচার হিসাবে নির্দিষ্টভাবে কার্যকরভাবে দক্ষতার সাথে সেটগুলি সরবরাহ করার জন্য প্রয়োগ করা হয়), তবে প্রচুর পরিমাণে ধারণাগত স্তরে সেট লজিক প্রয়োজন। উদাহরণস্বরূপ, আসুন আমরা বলি যে আপনি একটি গ্লোব বিশ্বের এমন প্রাণীদের সন্ধান করতে চান যা উড়ন্ত এবং সাঁতার কাট উভয়ই সক্ষম এবং আপনার একটি সেটে উড়ন্ত প্রাণী রয়েছে (আপনি প্রকৃতপক্ষে কোনও সেট ধারক ব্যবহার করেন কিনা) এবং অন্যটিতে সাঁতার কাটা যায় । সেক্ষেত্রে আপনি একটি সেট ছেদ চাই। আপনি যদি এমন প্রাণীগুলি চান যেগুলি উড়ে যায় বা যাদুকরী হয় তবে আপনি একটি সেট ইউনিয়ন ব্যবহার করুন। অবশ্যই এটি বাস্তবায়নের জন্য আপনার কোনও সেট ধারক প্রয়োজন নেই এবং সর্বাধিক অনুকূল বাস্তবায়নের সাধারণত সেট হিসাবে নকশাকৃত একটি ধারক প্রয়োজন হয় না বা চান না।
ট্যানজেন্ট অফ অফ গেঞ্জ
ঠিক আছে, আমি এই সেট ছেদ করার পদ্ধতির বিষয়ে জিমি জেমস থেকে কিছু সুন্দর প্রশ্ন পেয়েছি। এটি বিষয়বস্তু বন্ধ করে দিচ্ছে তবে ওহ ভাল, আমি আরও আগ্রহী লোকেরা এই ছেদটি স্থাপনের জন্য এই বেসিক ইন্টুসিভ পদ্ধতির ব্যবহার দেখতে আগ্রহী যাতে তারা কেবলমাত্র সেট অপারেশনের লক্ষ্যে সুষম বাইনারি গাছ এবং হ্যাশ টেবিলের মতো পুরো সহায়ক কাঠামো তৈরি না করে। যেমনটি উল্লেখ করা হয়েছে মৌলিক প্রয়োজনীয়তা হ'ল তালিকাগুলি অগভীর অনুলিপি করুন যাতে তারা কোনও ভাগ করা উপাদানকে সূচী বা নির্দেশ করছে যা প্রথম অরক্ষিত তালিকা বা অ্যারের মধ্য দিয়ে পাসের সাহায্যে ট্র্যাভারড হিসাবে চিহ্নিত হতে পারে বা দ্বিতীয়টিতে যা যা বেছে নিতে পারে দ্বিতীয় তালিকা মাধ্যমে পাস।
যাইহোক, উপাদানগুলি স্পর্শ না করে বহুগঠিত প্রসঙ্গে এমনকি এটি ব্যবহারিকভাবে সম্পাদন করা যেতে পারে যে:
- দুটি সমষ্টিতে উপাদানগুলির সূচকগুলি রয়েছে।
- সূচকের পরিধি খুব বেশি বড় নয় (বলুন [0, 2 ^ 26), বিলিয়ন বা তার বেশি নয়) এবং যুক্তিযুক্তভাবে ঘন দখল করা হয়েছে।
এটি আমাদের সেট অপারেশনের উদ্দেশ্যে একটি সমান্তরাল অ্যারে (উপাদান প্রতি মাত্র একটি বিট) ব্যবহার করতে দেয়। নকশা:
পুল থেকে একটি সমান্তরাল বিট অ্যারে অর্জন করে এবং এটি পুলটিতে ছেড়ে দেওয়ার সময় কেবল থ্রেড সিঙ্ক্রোনাইজেশন হওয়া দরকার (সুযোগের বাইরে যাওয়ার সময় স্পষ্টভাবে সম্পন্ন করা হয়েছিল)। সেট অপারেশন করতে প্রকৃত দুটি লুপগুলিতে কোনও থ্রেড সিঙ্কগুলি জড়িত থাকতে হবে না। আমাদের যদি থ্রেড কেবল স্থানীয়ভাবে বিটগুলি বরাদ্দ করতে এবং মুক্ত করতে পারে তবে সমান্তরাল বিট পুলটি ব্যবহার করার দরকার নেই, তবে বিট পুলটি কোডবেসে প্যাটার্নটি সাধারণীকরণে কার্যকর হতে পারে যা এই জাতীয় উপাত্ত উপস্থাপনের ক্ষেত্রে ফিট করে যেখানে কেন্দ্রীয় উপাদানগুলি প্রায়শই উল্লেখ করা হয় where সূচক দ্বারা যাতে প্রতিটি থ্রেড দক্ষ মেমরি পরিচালনা নিয়ে বিরক্ত না হয়। আমার অঞ্চলের প্রধান উদাহরণ হ'ল সত্তা-উপাদান সিস্টেম এবং সূচিযুক্ত জাল উপস্থাপনা। উভয়েরই প্রায়শই সেট ছেদ করা দরকার এবং কেন্দ্রীয়ভাবে সঞ্চিত সমস্ত কিছু (ইসিএস এবং অংশ, প্রান্তে উপাদান এবং সত্ত্বা,
যদি সূচকগুলি ঘনভাবে দখল করা হয় না এবং খুব কম ছড়িয়ে পড়ে থাকে তবে এটি এখনও সমান্তরাল বিট / বুলিয়ান অ্যারের যুক্তিসঙ্গত স্পর্শ প্রয়োগের সাথে প্রযোজ্য, যা কেবল 512-বিট খণ্ডে মেমরি সঞ্চয় করে (512 স্বতন্ত্র সূচকগুলি প্রতিনিধিত্ব করে অনিয়ন্ত্রিত নোডে 64 বাইট) ) এবং সম্পূর্ণ শূন্য স্থায়ী ব্লক বরাদ্দ এড়িয়ে চলে ips আপনার কেন্দ্রীয় ডেটা স্ট্রাকচারগুলি অল্প পরিমাণে উপাদানগুলি দ্বারা দখল করা থাকলে আপনি ইতিমধ্যে এমন কিছু ব্যবহার করছেন এমন সম্ভাবনা রয়েছে।
... একটি বিরল বিটসেটের জন্য সমান্তরাল বিট অ্যারে হিসাবে পরিবেশন করার জন্য একই ধারণা। এই কাঠামোগুলি নিজেকে অপরিবর্তনীয়তার দিকে ধার দেয় যেহেতু অগভীর অনুলিপি সহজেই অনুলিপি করা যায় যা নতুন অপরিবর্তনীয় অনুলিপি তৈরি করতে গভীর অনুলিপি করার প্রয়োজন হয় না।
শত শত মিলিয়ন উপাদানগুলির মধ্যে পুনরায় সেট ছেদগুলি খুব গড় মেশিনে এই পদ্ধতির ব্যবহার করে একটি সেকেন্ডের অধীনে করা যেতে পারে এবং এটি একক থ্রেডের মধ্যে।
এটি অর্ধেক সময়ের মধ্যেও করা যেতে পারে যদি ক্লায়েন্টের ফলাফলের ছেদগুলির জন্য উপাদানগুলির একটি তালিকা প্রয়োজন না হয়, যেমন তারা যদি উভয় তালিকার মধ্যে থাকা উপাদানগুলিতে কেবল কিছু যুক্তি প্রয়োগ করতে চায়, তবে তারা কেবলমাত্র পাস করতে পারে একটি ফাংশন পয়েন্টার বা ফান্টেক্টর বা ডেলিগেট বা যে কোনও কিছুকে ফিরে যেতে কল করে এমন উপাদানগুলির পরিসীমা প্রক্রিয়াকরণে। এই প্রভাব কিছু:
// 'func' receives a range of indices to
// process.
set_intersection(func):
{
parallel_bits = bit_pool.acquire()
// Mark the indices found in the first list.
for each index in list1:
parallel_bits[index] = 1
// Look for the first element in the second list
// that intersects.
first = -1
for each index in list2:
{
if parallel_bits[index] == 1:
{
first = index
break
}
}
// Look for elements that don't intersect in the second
// list to call func for each range of elements that do
// intersect.
for each index in list2 starting from first:
{
if parallel_bits[index] != 1:
{
func(first, index)
first = index
}
}
If first != list2.num-1:
func(first, list2.num)
}
... বা এই প্রভাব কিছু। প্রথম চিত্রের সিউডোকোডের সর্বাধিক ব্যয়বহুল অংশটি intersection.append(index)
দ্বিতীয় লুপে রয়েছে এবং এটি std::vector
আগে থেকে ছোট তালিকার আকারের জন্যও সংরক্ষিত জন্য প্রযোজ্য ।
আমি যদি ডিপ কপি করি সব?
আচ্ছা, থামো! যদি আপনার ছেদগুলি সেট করার দরকার হয় তবে এটি বোঝায় যে আপনি বিপরীতে ছেদ করার জন্য ডেটা নকল করছেন। সম্ভাবনা হ'ল এমনকি আপনার অতি ক্ষুদ্রতম বস্তুগুলিও 32-বিট সূচকগুলির চেয়ে ছোট নয়। আপনার উপাদানগুলির ঠিকানা পরিসর 2 range 32 (2 ^ 32 উপাদান নয়, 2 ^ 32 বাইট) হ্রাস করা খুব সম্ভব যদি না আপনার প্রকৃতপক্ষে 4.3 বিলিয়ন ডলারের বেশি উপাদান তাত্ক্ষণিকভাবে প্রয়োজন হয়, যার পর্যায়ে সম্পূর্ণ ভিন্ন সমাধানের প্রয়োজন হয় ( এবং এটি অবশ্যই মেমরিতে সেট পাত্রে ব্যবহার করছে না)।
মূল ম্যাচ
যে উপাদানগুলিতে উপাদানগুলি অভিন্ন নয় তবে মিল কীগুলি থাকতে পারে সেখানে সেট অপারেশন করা আমাদের কীভাবে হবে? সেক্ষেত্রে উপরের মত একই ধারণা। আমাদের কেবল সূচকে প্রতিটি অনন্য কী ম্যাপ করতে হবে। উদাহরণস্বরূপ, কীটি যদি স্ট্রিং হয় তবে ইন্টার্নযুক্ত স্ট্রিংগুলি এটি করতে পারে। এই ক্ষেত্রে একটি ট্রাই বা হ্যাশ টেবিলের মতো একটি দুর্দান্ত ডেটা স্ট্রাকচারকে 32-বিট সূচকগুলিতে স্ট্রিং কীগুলি ম্যাপ করার জন্য বলা হয়, তবে ফলাফলটি 32-বিট সূচকগুলিতে সেট ক্রিয়াকলাপ করার জন্য আমাদের যেমন কাঠামোগুলির প্রয়োজন নেই।
খুব সহজ এবং সরল আলগোরিদিমিক সমাধান এবং ডেটা স্ট্রাকচারগুলি পুরোপুরি এগুলি খুলে যায় যখন আমরা মেশিনের সম্পূর্ণ ঠিকানা পরিসর নয়, খুব যুক্তিসঙ্গত পরিসরে উপাদানগুলির সূচকগুলির সাথে কাজ করতে পারি, এবং তাই এটি প্রায়শই এটির চেয়ে বেশি মূল্যযুক্ত প্রতিটি অনন্য কী জন্য একটি অনন্য সূচক পেতে সক্ষম।
আমি সূচকগুলি ভালবাসি!
আমি পিজ্জা এবং বিয়ারের মতো সূচকগুলিও পছন্দ করি। আমি যখন আমার 20-এর দশকে ছিলাম, তখন আমি সত্যিই সি ++ তে প্রবেশ করি এবং সমস্ত ধরণের সম্পূর্ণ স্ট্যান্ডার্ড-কমপ্লায়েন্ট ডেটা স্ট্রাকচার ডিজাইন করা শুরু করি (সংকলন-সময়ে রেঞ্জের কর্টরের একটি ফিল কর্টারকে পূরণ করার জন্য যুক্ত কৌশলগুলি সহ)। বিপরীতমুখী সময়ে যে সময়ের অপচয় ছিল।
যদি আপনি আপনার ডাটাবেসটিকে অ্যারেগুলিতে কেন্দ্রীয়ভাবে স্টোর করে এবং মেশিনের পুরো ঠিকানাযোগ্য পরিসীমা জুড়ে এমনভাবে স্ট্রোক করার পরিবর্তে সূচিকাগুলির পরিবর্তে সূচকের চারপাশে ঘুরিয়ে নিয়ে থাকেন তবে আপনি কেবলমাত্র অ্যালগরিদমিক এবং ডেটা কাঠামো সম্ভাবনার একটি পৃথিবী অন্বেষণ করতে পারেন পাত্রে এবং অ্যালগরিদমের নকশা করা যা প্লেইন পুরাতন int
বা এর চারপাশে ঘোরে int32_t
। এবং আমি শেষ ফলাফলটি এত বেশি দক্ষ এবং বজায় রাখা সহজ হিসাবে পেয়েছি যেখানে আমি নিয়মিত উপাদানগুলি এক ডেটা কাঠামো থেকে অন্যটিতে অন্যটিতে স্থানান্তর করছিলাম না।
কিছু উদাহরণস্বরূপ কেসগুলি ব্যবহার করে যখন আপনি কেবল ধরে নিতে পারেন যে কোনও অনন্য মানের T
একটি অনন্য সূচক রয়েছে এবং এর উদাহরণ থাকবে কেন্দ্রীয় অ্যারেতে:
মাল্টিথ্রেডেড রেডিক্স প্রকারভেদ যা সূচকের জন্য স্বাক্ষরযুক্ত পূর্ণসংখ্যার সাথে ভালভাবে কাজ করে । আমার আসলে একটি মাল্টিথ্রেডেড রেডিক্স সাজান যা ইন্টেলের নিজস্ব সমান্তরাল সাজ হিসাবে প্রায় এক মিলিয়ন উপাদানকে সাজানোর জন্য প্রায় 1/10 তম সময় নেয় std::sort
এবং এ জাতীয় বৃহত ইনপুটগুলির চেয়ে ইন্টেল এর ইতিমধ্যে 4 গুণ দ্রুত is ইন্টেল অবশ্যই তুলনামূলক ভিত্তিক সাজানোর কারণে এবং জিনিসকে ডিকশনিকভাবে বাছাই করতে পারে তাই এটি অনেক বেশি নমনীয়, তাই এটি কমলাতে আপেলের তুলনা করে। তবে এখানে আমার প্রায়শই কমলা দরকার, যেমন আমি কেবল ক্যাশে-বান্ধব মেমরি অ্যাক্সেসের ধরণগুলি অর্জন করতে বা ডুপ্লিকেটগুলি দ্রুত ফিল্টার আউট করার জন্য একটি রেডিক্স সারণি পাস করতে পারি।
লিঙ্ক তালিকা, গাছ, গ্রাফ, পৃথক chaining হ্যাশ টেবিল, ইত্যাদি নোড প্রতি গাদা বরাদ্দ ছাড়া মত কাঠামো বিল্ড লিঙ্ক করার ক্ষমতা । আমরা কেবলমাত্র নোডগুলিকে বাল্কে বরাদ্দ করতে পারি, উপাদানগুলির সমান্তরাল করতে পারি এবং সূচির সাথে তাদের সংযুক্ত করি link নোডগুলি নিজেরাই পরবর্তী নোডের জন্য 32-বিট সূচক হয়ে যায় এবং এর মতো একটি বড় অ্যারেতে সঞ্চিত হয়:
সমান্তরাল প্রক্রিয়াকরণের জন্য বন্ধুত্বপূর্ণ। প্রায়শই সংযুক্ত কাঠামো সমান্তরাল প্রক্রিয়াজাতকরণের জন্য এতটা বন্ধুত্বপূর্ণ হয় না, যেহেতু গাছের সাথে সমান্তরালতা অর্জনের চেষ্টা করা বা লিঙ্কযুক্ত তালিকার বিপরীতে যেমন ট্র্যাকসাল লিখিত হয়, কেবল অ্যারের মাধ্যমে লুপের জন্য সমান্তরাল কাজ করে যাবার চেষ্টা করা যায়। সূচক / কেন্দ্রীয় অ্যারের উপস্থাপনা সহ, আমরা সর্বদা সেই কেন্দ্রীয় অ্যারেতে যেতে পারি এবং চুনকি সমান্তরাল লুপগুলিতে সমস্ত কিছুতে প্রক্রিয়া করতে পারি। আমাদের কাছে সর্বদা সমস্ত উপাদানগুলির কেন্দ্রীয় অ্যারে থাকে আমরা এই পদ্ধতিতে প্রক্রিয়া করতে পারি, এমনকি আমরা কেবল কিছু প্রক্রিয়া করতে চাইলেও (কেন্দ্রীয় বিন্যাসের মাধ্যমে ক্যাশে-বান্ধব অ্যাক্সেসের জন্য একটি রেডিক্স-বাছাই করা তালিকার সাহায্যে উপাদানগুলি সূচিবদ্ধভাবে তৈরি করতে পারে এমন সময়ে আপনি উপাদানগুলি প্রক্রিয়া করতে পারেন)।
ধ্রুবক সময়ে ফ্লাইয়ের প্রতিটি উপাদানের সাথে ডেটা সংযুক্ত করতে পারে । উপরের বিটের সমান্তরাল অ্যারের ক্ষেত্রে হিসাবে, আমরা অস্থায়ী প্রক্রিয়াজাতকরণের জন্য উপাদানগুলির সাথে সহজে এবং অত্যন্ত সস্তায় সমান্তরাল তথ্য সংযুক্ত করতে পারি। এটি অস্থায়ী ডেটার বাইরেও কেস ব্যবহার করে। উদাহরণস্বরূপ, একটি জাল সিস্টেম ব্যবহারকারীদের যতটা ইউভি মানচিত্র তারা চান তার সাথে জালটিতে সংযুক্ত করার অনুমতি দিতে পারে। এই জাতীয় ক্ষেত্রে, আমরা এওএস পদ্ধতির সাহায্যে প্রতিটি একক ভার্টেক্সে এবং মুখের মধ্যে কতটি ইউভি মানচিত্র থাকবে তা কেবল হার্ড-কোড করতে পারি না। আমাদের ফ্লাইতে এই জাতীয় ডেটা সংযুক্ত করতে সক্ষম হওয়া দরকার, এবং সমান্তরাল অ্যারেগুলি খুব সহজেই কার্যকর এবং যে কোনও ধরণের হে পরিশীলিত সাহসী ধারক, এমনকি হ্যাশ টেবিলের চেয়ে অনেক কম সস্তা।
একে অপরের সাথে সামঞ্জস্য রেখে সমান্তরাল অ্যারেগুলি রাখার ত্রুটি-প্রবণ প্রকৃতির কারণে অবশ্যই সমান্তরাল অ্যারেগুলি ভ্রান্ত হয়। যখনই আমরা সূচক 7 এ কোনও উপাদানটিকে "মূল" অ্যারে থেকে সরিয়ে ফেলি, উদাহরণস্বরূপ, "বাচ্চাদের" জন্য আমাদের একইভাবে কাজ করতে হবে। তবে, বেশিরভাগ ভাষায় এই ধারণাটিকে সাধারণ উদ্দেশ্যমূলক ধারক হিসাবে সাধারণকরণ করার পক্ষে যথেষ্ট সহজ, যাতে সমান্তরাল অ্যারেগুলি একে অপরের সাথে সিঙ্ক করে রাখার জন্য যুক্তিযুক্ত যুক্তি কেবল পুরো কোডবেজ জুড়েই এক জায়গায় উপস্থিত থাকতে পারে এবং এমন একটি সমান্তরাল অ্যারে ধারক হতে পারে পরবর্তী সন্নিবেশের পরে পুনরায় দাবি করতে অ্যারেতে থাকা খালি জায়গাগুলির জন্য প্রচুর মেমরির অপচয় না করার জন্য উপরের স্পার অ্যারে প্রয়োগ ব্যবহার করুন।
আরও বিস্তৃতি: বিরল বিটসেট গাছ
ঠিক আছে, আমি আরও কিছু ব্যাখ্যা করার জন্য একটি অনুরোধ পেয়েছি যা আমি ব্যঙ্গাত্মক বলে মনে করি, তবে আমি যেভাবেই হোক না কেন এটি এত মজাদার কারণ! লোকেরা যদি এই ধারণাটি পুরো নতুন স্তরে নিয়ে যেতে চায় তবে এন + এম উপাদানগুলির মধ্যে লিনিং লুপিং ছাড়াই সেট ছেদগুলি করা সম্ভব। এটি আমার চূড়ান্ত ডেটা স্ট্রাকচার যা আমি যুগে যুগে এবং মূলত মডেলগুলির জন্য ব্যবহার করে আসছি set<int>
:
উভয় তালিকায় প্রতিটি উপাদানকে পরীক্ষা না করেও এটি সেট ছেদগুলি সম্পাদন করতে পারে কারণ হায়ারার্কির মূলে থাকা একটি সেট বিট এটি ইঙ্গিত করতে পারে যে, বলুন, মিলিয়ন মিলিয়ন উপাদান সেটে দখল করেছে in কেবলমাত্র একটি বিট পরিদর্শন করে, আমরা জানতে পারি যে পরিসরের এন সূচকগুলি [first,first+N)
সেটে রয়েছে, যেখানে এন খুব বড় সংখ্যক হতে পারে।
দখলকৃত সূচকগুলি অনুসরণ করার সময় আমি এটি লুপ অপটিমাইজার হিসাবে ব্যবহার করি, কারণ ধরা যাক যে সেটটিতে 8 মিলিয়ন সূচক দখল করা আছে। ভাল, সাধারণত আমাদের ক্ষেত্রে স্মৃতিতে 8 মিলিয়ন পূর্ণসংখ্যার অ্যাক্সেস করতে হবে। এটির সাহায্যে এটি সম্ভাব্য মাত্র কয়েকটি বিট পরিদর্শন করতে পারে এবং অধিষ্ঠিত সূচকের সূচিপত্রগুলি লুপ করতে পারে। তদুপরি, এটি সূচকগুলির পরিসীমাটি সাজানো ক্রমে থাকে যা মূল ক্যাটা-বান্ধব অনুক্রমিক অ্যাক্সেসের বিরোধিতা হিসাবে বলে, মূল উপাদান ডেটা অ্যাক্সেস করতে ব্যবহৃত সূচকগুলির একটি অরসেটেড অ্যারে মাধ্যমে পুনরাবৃত্তি করে। অবশ্যই এই কৌশলটি অত্যন্ত বিচ্ছিন্ন ক্ষেত্রেগুলির চেয়ে খারাপতর ঘটবে, সবচেয়ে খারাপ পরিস্থিতিটি প্রতিটি একক সূচকের মতো একটি সমান সংখ্যার (বা প্রত্যেকেই অদ্ভুত), যার ক্ষেত্রে কোনও সংকীর্ণ অঞ্চল নেই। তবে আমার ব্যবহারের ক্ষেত্রে কমপক্ষে,