程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C#中應用基數排序算法對字符串停止排序的示例

C#中應用基數排序算法對字符串停止排序的示例

編輯:C#入門知識

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>。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved