c# - যদি স্ট্রিংগুলি.NET এ অনাক্রম্য হয়, তাহলে কেন Substring O(n) সময় নেয়?



time-complexity (4)

আপডেট: আমি এই প্রশ্নটি খুব পছন্দ করেছি, আমি শুধু এটি ব্লগ করেছি। স্ট্রিং, immutability এবং অধ্যবসায় দেখুন

সংক্ষিপ্ত উত্তর হল: হে (এন) হল O (1) যদি বড় বড় না হয়। বেশিরভাগ মানুষ ক্ষুদ্র স্ট্রিং থেকে ক্ষুদ্র স্তরগুলিকে বের করে নেয়, তাই জটিলতাটি অসম্পূর্ণভাবে কীভাবে বৃদ্ধি পায় তা সম্পূর্ণ অপ্রাসঙ্গিক

দীর্ঘ উত্তর হল:

একটি অননুমোদিত তথ্য কাঠামো এমনভাবে তৈরি করা হয়েছে যে অনুলিপিের অনুমতিগুলি কেবলমাত্র একটি ছোট পরিমাণে (সাধারণত O (1) বা O (lg n)) কপি বা নতুন বরাদ্দকরণের মূলটির স্মৃতি পুনঃব্যবহারের জন্য "স্থায়ী" অপরিবর্তনীয় তথ্য গঠন। .NET এর স্ট্রিংগুলি অপরিবর্তনীয়। আপনার প্রশ্ন মূলত "কেন তারা অবিরত না"?

কারন আপনি যখন নেটওয়ার্কে প্রোগ্রামগুলিতে স্ট্রিংগুলিতে সাধারণত কাজ করেন তখন দেখেন যে, এটি কেবলমাত্র একটি সম্পূর্ণ নতুন স্ট্রিং তৈরির জন্য একেবারেই খারাপভাবে প্রতিটি খারাপ ভাবেই হয়। জটিল জটিল তথ্য কাঠামো নির্মাণের ব্যয় এবং অসুবিধা নিজের জন্য অর্থ প্রদান করে না।

লোকেরা সাধারণত একটি ছোট স্ট্রিং বের করতে "সাবস্ট্রিং" ব্যবহার করে - বলতে পারে, দশ বা ত্রিশ অক্ষর - কিছুটা লম্বা স্ট্রিং - সম্ভবত কয়েকটি অক্ষর। আপনার একটি কমা দ্বারা বিচ্ছিন্ন ফাইলটিতে পাঠ্য একটি লাইন আছে এবং আপনি তৃতীয় ক্ষেত্রটি সরাতে চান, যা একটি শেষ নাম। লাইন সম্ভবত কয়েক দম্পতি লম্বা হতে পারে, নামটি কয়েক ডজন হবে। স্ট্রিং বরাদ্দকরণ এবং পঞ্চাশ বাইটের মেমরি অনুলিপি আধুনিক হার্ডওয়্যারগুলিতে আশ্চর্যজনকভাবে দ্রুত । যে একটি নতুন তথ্য কাঠামো তৈরি করে যা একটি বিদ্যমান স্ট্রিং এর সাথে একটি দৈর্ঘ্যের মাঝামাঝি পয়েন্টার ধারণ করে তাও অদ্ভুতভাবে অপ্রাসঙ্গিক। "দ্রুত যথেষ্ট" যথেষ্ট দ্রুত সংজ্ঞা দ্বারা হয়।

নিষ্কাশিত substrings সাধারণত আকার ছোট এবং জীবনকাল সংক্ষিপ্ত হয়; আবর্জনা সংগ্রাহক শীঘ্রই তাদের পুনরুদ্ধার করতে যাচ্ছে, এবং তারা প্রথম স্থানে হিপ উপর অনেক রুম নিতে না। তাই মেমরি অধিকাংশ পুনঃব্যবহার উত্সাহিত যে একটি ধারাবাহিক কৌশল ব্যবহার করে একটি জয় নয়; আপনি যা করেছেন তা সব আপনার আবর্জনা সংগ্রাহক ধীর পেতে কারণ এখন এখন অভ্যন্তর পয়েন্টার পরিচালনা সম্পর্কে চিন্তা করতে হবে।

যদি সাধারণত স্ট্রিংগুলির উপর লোকেদের সাবস্ট্রিং অপারেশনগুলি সম্পূর্ণ ভিন্ন হয়, তবে এটি একটি স্থায়ী পদ্ধতির সাথে যেতে বুদ্ধিমান হবে। যদি মানুষের সাধারণত মিলিয়ন-অক্ষর স্ট্রিং থাকে এবং হাজার হাজার চরিত্রের পরিসর সহ হাজার হাজার ওভারল্যাপিং সাবস্ট্রিংগুলিকে বের করে আনা হয় এবং সেসব স্তরগুলি হিপের উপর দীর্ঘ সময় ধরে থাকে, তবে এটি স্থায়ীভাবে সাবস্ট্রিং পদ্ধতির; এটা নষ্ট এবং নির্বোধ হবে না। কিন্তু বেশিরভাগ লাইন-অফ-প্রোগ্রাম প্রোগ্রামার এমন কিছু না করেও কিছুটা অস্বাভাবিক কিছু করেন না । .NET হিউম্যান জিনোম প্রজেক্টের চাহিদাগুলির জন্য উপযোগী একটি প্ল্যাটফর্ম নয়; ডিএনএ বিশ্লেষণ প্রোগ্রামাররা প্রতিদিন যারা স্ট্রিং ব্যবহার বৈশিষ্ট্য সঙ্গে সমস্যা সমাধান করতে হবে; অদ্ভুত আপনি না যে ভাল। কয়েকটি যারা তাদের নিজস্ব স্থায়ী তথ্য কাঠামোগুলি ঘনিষ্ঠভাবে ব্যবহার করে যা তাদের ব্যবহারের দৃশ্যগুলির সাথে মেলে।

উদাহরণস্বরূপ, আমার দল এমন প্রোগ্রামগুলি লিখেছে যা আপনি লিখেছেন C # এবং VB কোড-এর-ফ্লাই বিশ্লেষণ করে। কিছু কোড ফাইলগুলি প্রচুর পরিমাণে রয়েছে এবং এইভাবে আমরা O (n) স্ট্রিং ম্যানিপুলেশন সাবস্ট্রিংগুলি সরাতে বা অক্ষর সন্নিবেশ করতে বা মুছে ফেলতে পারছি না। আমরা একটি পাঠ্য বাফারের সম্পাদনাগুলিকে দ্রুত এবং দক্ষতার সাথে বিদ্যমান স্ট্রিং ডেটা এবং তার বর্তমান লিকিক্যাল এবং সিন্ট্যাকটিক বিশ্লেষণগুলির একটি সাধারণ সম্পাদনাতে পুনঃব্যবহার করার অনুমতি দেয় এমন সম্পাদনাগুলির প্রতিনিধিত্বের জন্য স্থায়ী ইমিউটেবল ডেটা স্ট্রাকচারগুলির একটি গুচ্ছ তৈরি করেছি। এটি সমাধান করার একটি কঠিন সমস্যা এবং এটির সমাধানটি সি # এবং ভিবি কোড সম্পাদনা নির্দিষ্ট ডোমেনে সংকীর্ণভাবে সংশোধন করা হয়েছিল। বিল্ট-ইন স্ট্রিং টাইপটি আমাদের জন্য এই সমস্যার সমাধান করার জন্য অবাস্তব হবে।

যে স্ট্রিংগুলি .NET তে অপরিবর্তনীয় রয়েছে, আমি অবাক হলাম কেন তারা এমন string.Substring() ডিজাইন করেছেন। string.Substring() O(1) পরিবর্তে O ( substring.Length ) সময় নেয়?

অর্থাৎ ট্রেডপোজ কি ছিল?


Answer #1

এখানে কোনও উত্তর নেই "বন্ধনী সমস্যা", যা বলা হয় যে .NET- এ স্ট্রিংগুলিকে একটি বিএসটিআর ("পয়েন্টার এর আগে" মেমরিতে সংরক্ষিত দৈর্ঘ্য) এবং সিএসটিআর (স্ট্রিংটি শেষ হয় '\ 0')।

স্ট্রিং "হ্যালো সেখানে" হিসাবে প্রতিনিধিত্ব করা হয়

0B 00 00 00 48 00 65 00 6C 00 6F 00 20 00 74 00 68 00 65 00 72 00 65 00 00 00

(যদি নির্ধারিত অবস্থায় একটি char* নির্ধারিত হয়, পয়েন্টার 0x48 নির্দেশ করবে।)

এই কাঠামোটি একটি স্ট্রিং (অনেক প্রসঙ্গে দরকারী) এর দ্রুত সন্ধানের জন্য অনুমতি দেয় এবং পয়েন্টারকে P / V32 (বা অন্যান্য) এপিআইগুলিতে প্রবেশের অনুমতি দেয় যা একটি নল-সমাপ্ত স্ট্রিংয়ের প্রত্যাশা করে।

যখন আপনি Substring(0, 5) তখন "ওহ, কিন্তু আমি প্রতিশ্রুতি দিয়েছি যে শেষ চরিত্রটির পরে একটি অস্পষ্ট চরিত্র থাকবে" বলে নিয়মটি আপনাকে একটি অনুলিপি তৈরি করতে হবে। এমনকি যদি আপনি উপসর্গটি শেষ পর্যন্ত পান তবে অন্য ভেরিয়েবলগুলিকে দূষিত না করে দৈর্ঘ্য স্থাপন করার কোনও জায়গা নেই।

কখনও কখনও, আপনি সত্যিই "স্ট্রিং মধ্যম" সম্পর্কে কথা বলতে চান, এবং আপনি অপরিহার্যভাবে P / Invoke আচরণ সম্পর্কে যত্ন নেন না। সম্প্রতি যোগ করা ReadOnlySpan<T> কাঠামোটি কোনও অনুলিপি উপাদানের জন্য ব্যবহার করা যেতে পারে:

string s = "Hello there";
ReadOnlySpan<char> hello = s.AsSpan(0, 5);
ReadOnlySpan<char> ell = hello.Slice(1, 3);

ReadOnlySpan<char> "substring" স্বাধীনভাবে দৈর্ঘ্য সঞ্চয় করে এবং মূল্যের শেষে একটি '\ 0' থাকে বলে গ্যারান্টি দেয় না। এটি "স্ট্রিং মত" অনেক উপায়ে ব্যবহার করা যেতে পারে, তবে এটি "স্ট্রিং" নয় কারণ এটিতে বিএসআরআর বা সিএসআরটি বৈশিষ্ট্যগুলিও নেই (তাদের উভয়ই কম)। যদি আপনি কখনই (সরাসরি) P / ইনকোকেশন করেন না তবে এতে কোনও পার্থক্য নেই (যতক্ষণ না আপনি যে API টি কল করতে চান তার কোনও ReadOnlySpan<char> ওভারলোড নেই)।

ReadOnlySpan<char> একটি রেফারেন্স টাইপের ক্ষেত্র হিসাবে ব্যবহার করা যাবে না, তাই সেখানে s.AsMemory(0, 5) ReadOnlyMemory<char> ( s.AsMemory(0, 5) ), যা s.AsMemory(0, 5) ReadOnlyMemory<char> থাকার একটি পরোক্ষ উপায়, তাই একই পার্থক্য -from- string বিদ্যমান।

পূর্বের উত্তরের কিছু উত্তর / মন্তব্যগুলি সম্পর্কে কথা বলা হয়েছে যে, আবর্জনা সংগ্রাহককে প্রায় এক মিলিয়ন চরিত্রের স্ট্রিং রাখতে হবে যখন আপনি 5 অক্ষর সম্পর্কে কথা বলতে থাকবেন। ReadOnlySpan<char> পদ্ধতির সাথে আপনি ReadOnlySpan<char> আচরণ করতে পারেন তা ঠিক। আপনি যদি শুধু সংক্ষিপ্ত কম্পিউটিং করছেন তবে ReadOnlySpan পদ্ধতিটি সম্ভবত ভাল। যদি আপনি এটির জন্য কিছুটা সময় ধরে রাখতে চান এবং আপনি কেবল মূল স্ট্রিংটির একটি ছোট শতাংশ রাখতে যাচ্ছেন, তবে সঠিক উপসর্গটি (অতিরিক্ত তথ্য বন্ধ করতে) সম্ভবত ভাল। মাঝখানে কোথাও একটি স্থানান্তর বিন্দু আছে, কিন্তু এটি আপনার নির্দিষ্ট ব্যবহার উপর নির্ভর করে।


Answer #2

জাভা বড় স্ট্রিং রেফারেন্স ব্যবহৃত, কিন্তু:

জাভা স্মৃতি লিক এড়াতে, পাশাপাশি কপি করার জন্য তার আচরণ পরিবর্তন

আমি মনে করি এটি উন্নত হতে পারে যদিও: কেন শুধু কপি করা হয় শর্তাবলী?

যদি সাবস্ট্রিং কমপক্ষে পিতামাতার আকারের অর্ধেক, তবে একজন পিতামাতার রেফারেন্স করতে পারে। অন্যথায় শুধুমাত্র একটি কপি করতে পারেন। এটি এখনও একটি উল্লেখযোগ্য সুবিধা প্রদান করার সময় মেমরি অনেক লিক এড়ানো।


Answer #3

.Substring কারণ স্ট্রিং অপরিবর্তনীয়, .Substring অবশ্যই কমপক্ষে মূল স্ট্রিংটির একটি অংশ তৈরি করতে হবে। এন বাইট একটি কপি করা উচিত হে (এন) সময় নিতে হবে।

আপনি কিভাবে ধ্রুবক সময় বাইট একটি গুচ্ছ অনুলিপি করতে হবে মনে করেন?

সম্পাদন করুন: মেহেরদাদ স্ট্রিং অনুলিপি নকল করার পরামর্শ দেন না, তবে এটির একটি অংশে রেফারেন্স রাখেন।

.SubString(n, n+3) বিবেচনা করুন, একটি মাল্টি মেগাবাইট স্ট্রিং, যার উপর কেউ কল করে। .SubString(n, n+3) (স্ট্রিংয়ের মধ্যবর্তী যে কোনো n এর জন্য)।

এখন, সমগ্র স্ট্রিং গার্বেজ সংগ্রহ করা যাবে না কারণ শুধুমাত্র একটি রেফারেন্স ধরে রাখা হয় 4 অক্ষর? যে স্থান একটি হাস্যকর বর্জ্য মত মনে হয়।

উপরন্তু, substrings (যা এমনকি substrings ভিতরে হতে পারে) ট্র্যাকিং রেফারেন্স, এবং জিসি (উপরে উল্লিখিত হিসাবে) পরাস্ত করতে অনুকূল সময় অনুলিপি করার চেষ্টা, ধারণা একটি দুঃস্বপ্ন তোলে। এটা সহজ, এবং আরও নির্ভরযোগ্য, অনুলিপি করতে .SubString , এবং .SubString মডেল বজায় রাখা।

সম্পাদনা করুন: বৃহত্তর স্ট্রিংগুলির মধ্যে সাবস্ট্রিংয়ের রেফারেন্সগুলি রাখার বিষয়ে বিপদ সম্পর্কে একটু ভালভাবে পড়া আছে।






time-complexity