C#中應用基數排序算法對字符串停止排序的示例。本站提示廣大學習愛好者:(C#中應用基數排序算法對字符串停止排序的示例)文章只能為提供參考,不一定能成為您想要的結果。以下是C#中應用基數排序算法對字符串停止排序的示例正文
開端之前
假定最長字符串的長度是L,以L作為輸出的長度, 然後假定一切的字符串都"補齊"到此長度,這個補齊只是邏輯上的,我們可以設想有一種"空字符", 它小於任何其它字符,用此字符補齊一切長度缺乏的字符串。例如:最長的字符串長度為9,有一個字符串A長度為6, 那末當比擬第7位字符的時刻,我們讓A[7]為"空字符"。
假如要包括一切的字符仿佛其實不輕易,我們先界說一個字符集, 待排序字符串中的一切字符都包括在這個字符集裡
//字符集 private string _myCharSet = "0123456789qwertyuiopasdfghjklzxcvbnm";
再來一個生成隨機字符串的辦法(C#完成):
private Random _random = new Random(); string[] GetRandStrings(int size, int minLength, int maxLength) { string[] strs = new string[size]; int len = 0; StringBuilder sb = new StringBuilder(maxLength); for (int i = 0; i < strs.Length; i++) { //先隨機肯定一個長度 len = _random.Next(minLength, maxLength); for (int j = 0; j < len; j++) { //隨機拔取一個字符 sb.Append(_myCharSet[_random.Next(_myCharSet.Length)]); } strs[i] = sb.ToString(); sb.Clear(); } return strs; }
這裡依照字符的整數表現來肯定桶的規模,再為"空字符"預備一個桶。 為了表現"空字符"這個特例,這裡用default(char),即'\0'表現它, 由於當挪用string.ElementAtOrDefault(int)辦法時,假如超越索引會前往'\0'。
低級版本(C#)
void StringRadixSort(string[] strArray) { if (strArray == null || strArray.Length == 0 || strArray.Contains(null)) { return; } //取得字符串的最年夜長度 int maxLength = 0; foreach (string s in strArray) { if (s.Length > maxLength) { maxLength = s.Length; } } //肯定字符的整數規模 int rangeStart = _myCharSet[0]; int rangeEnd = _myCharSet[0]; foreach (char ch in _myCharSet) { if (ch < rangeStart) rangeStart = ch; if (ch >= rangeEnd) rangeEnd = ch + 1; } //也要為"空字符"分派一個桶,其索引為0 int bucketCount = rangeEnd - rangeStart + 1; LinkedList<string>[] buckets = new LinkedList<string>[bucketCount]; //初始化一切的桶 for (int i = 0; i < buckets.Length; i++) { buckets[i] = new LinkedList<string>(); } //從最初一個字符開端排序 int currentIndex = maxLength - 1; while (currentIndex >= 0) { foreach (string theString in strArray) { //假如超越索引,前往'\0'字符(default(char)) char ch = theString.ElementAtOrDefault(currentIndex); if (ch == default(char)) { //"空字符"的處置 buckets[0].AddLast(theString); } else { //將字符映照到桶 int index = ch - rangeStart + 1; buckets[index].AddLast(theString); } } //從桶裡順次取回字符串,完成一趟排序 int i = 0; foreach (LinkedList<string> bucket in buckets) { while (bucket.Count > 0) { strArray[i++] = bucket.First(); bucket.RemoveFirst(); } } currentIndex--; } }
稍作"改進"
用作肯定字符的整數規模的代碼略顯蛋疼,並且依據字符集來看, 其實不是區間內一切的整數對應的字符都能夠湧現,是以會有如許的情形: 我們給某些基本不會湧現的字符分派了桶,這純屬糟蹋。 我們可以用一個字典(散列)來記載字符和它的桶之間的映照。因而有了上面的代碼。
private Dictionary<char, int> _charOrderDict = new Dictionary<char, int>(_myCharSet.Length); void BuildCharOrderDict() { char[] sortedCharSet = _myCharSet.ToArray(); //應用默許的比擬器排序 Array.Sort(sortedCharSet); //為"空字符"零丁創立映照 _charOrderDict.Add(default(char), 0); for (int i = 0; i < sortedCharSet.Length; i++) { // 保留的是字符及其對應的桶的索引 _charOrderDict.Add(sortedCharSet[i], i + 1); } }
也能夠不消默許的字符排序來作為映照,而完整本身界說字符之間的年夜小關系。 上面是調劑後的代碼:
void StringRadixSort(string[] strArray) { if (strArray == null || strArray.Length == 0 || strArray.Contains(null)) { return; } //取得字符串的最年夜長度 int maxLength = 0; foreach (string s in strArray) { if (s.Length > maxLength) { maxLength = s.Length; } } //為每個字符(包含空字符'\0')分派一個桶 //"空字符"索引應為0 int bucketCount = _myCharSet.Length + 1; LinkedList<string>[] buckets = new LinkedList<string>[bucketCount]; //初始化一切的桶 for (int i = 0; i < buckets.Length; i++) { buckets[i] = new LinkedList<string>(); } //從最初一個字符開端排序 int currentIndex = maxLength - 1; while (currentIndex >= 0) { foreach (string theString in strArray) { //假如超越索引,前往'\0'字符(default(char)) char ch = theString.ElementAtOrDefault(currentIndex); //依據字符次序的界說查詢字符 int index = _charOrderDict[ch]; buckets[index].AddLast(theString); } //從桶裡順次取回字符串,完成一趟排序 int i = 0; foreach (LinkedList<string> bucket in buckets) { while (bucket.Count > 0) { strArray[i++] = bucket.First(); bucket.RemoveFirst(); } } currentIndex--; } }
Now, it works! 假如采取的疾速排序來做, 當時間龐雜度為O(n∗logn)O(n∗logn)。外面上看,基數排序更好,不外嚴厲來講, 基數排序的時光龐雜度應當是O(k∗n)O(k∗n),個中k和字符串長度正相干。 此時兩種算法的比擬可以經由過程比擬k和lognlogn的比擬成果近似得出。 假如字符串的長度很長,即k很年夜,而輸出范圍n不年夜的時刻, 就會有k>lognlogn,此時疾速排序反而更有優勢。反之,則基數排序能夠更優。
最初...
杯具的是,當我擴展字符集,將鍵盤上一切字符都加出來後, 發明基數排序的成果和Array.Sort(string[]辦法的排序成果其實不一樣。 細心不雅察資本治理器對文件名的排序,才發明其字符串排序的規矩要龐雜的多,並不是簡略的比擬字符。 查詢相干材料後發明,字符串的排序乃至還要斟酌區域文明的影響,即便都是拉丁字母, 分歧地域的排序規矩都能夠紛歧樣,是以, 應用基數排序完成的字符串排序算法似乎並沒有多年夜適用價值<T-T>。