• 读写ini文件


    C# 使用文件流来读写ini文件

    背景

      之前采用ini文件作为程序的配置文件,觉得这种结构简单明了,配置起来也挺方便。然后操作方式是通过WindowsAPI,然后再网上找到一个基于WindowsAPI封装的help类,用起来倒也顺手。用的多了,觉得还可以使用文件流来操作,后来就发现了EasyConfig。

      EasyConfig是一个纯C#的开源ini文件操作库,但是在使用上有诸多不便,只是个人感觉,于是个人将其改造了一下,是自己喜欢用的风格。

    资源下载

      如果不清楚ini文件结构,请百度一下,这里贴一个示例文件。

     Ini文件示例

    [Video]
    #是否全屏
    Fullscreen = true
    #宽度

    Width = 1280

    #电视高度
    #高度
    Height = 720

    [Level1]
    NumberOfEnemies=2000#数值
    Lives = 10
    Timer = 999
    EnemyNames = "Steve", "Sam", "Bill"
    EnemyGuns = 13, 28, 43, 499
    CanShoot = true, yes, on, no, false, off

    Ini文件示例

      EasyConfig 原版

      EasyConfig 改写后

    代码示例

      首先来看看改写后,怎么去使用她来读写Ini文件。

    复制代码
            static void Main(string[] args)
            {
                ConfigFile configFile = new ConfigFile("Test.ini");
    
                //遍历Config文件
                foreach (var group in configFile.SettingGroups)
                {
                    Console.WriteLine("****************************");
                    Console.WriteLine(group.Key + ":");
                    Console.WriteLine();
    
                    foreach (var value in group.Value.Settings)
                        Console.WriteLine("{0} = {1} (Is Array? {2}),{3}", value.Key, value.Value.RawValue, value.Value.IsArray, value.Value.Desp);
    
                    Console.WriteLine();
                }
                //读取值主要是在具体的配置项上进行读取,是首先定位到[Group],其次就是具体的项
                //使用泛型读取值,并指定读取失败时的默认值
                var fullScreen = configFile["Video"]["Fullscreen"].As<int>(-1);//失败
                var bFullScreen = configFile["Video"]["Fullscreen"].AsBool();//成功
                var arrCanShoot = configFile["Level1"]["CanShoot"].AsArray<bool>();
                //读取时 该项不存在,不存在的组或者项会自动添加
                var noexists = configFile["Video"]["xxxxxxxxxxx"].AsString();
                var noexists2 = configFile["Video111111111"]["xxxxxxxxxxx"].AsString();
    
                //写入值有2种方法,可以直接向某组下写入一项,也可以定位到某组某项,写入值
                //写入值 该项不存在,组或者项会自动创建
                configFile["Video"].WriteSetting("NewName", "EasyConfig");
                configFile["Video"].WriteSetting("NewName", "EasyConfig2.0");
                configFile["Video22222222"].WriteSetting("c1", "1");
                //索引器不过是返回Setting
                configFile["Video3333"]["UserName"].SetValue("admin");
                configFile["Viedo4444"]["Sex"].SetValue("", "", "保密");
                //写入值,该项不存在
                configFile["Video222"].WriteSetting("NewName", "EasyConfig3.0");
    
    
                Console.ReadKey(true);
    
                configFile.Save("TestConfig2.txt");
            }
    复制代码

      基本上自己想要的效果,则是基于 ConfigFile["GroupName"]["Key"] 这样的方式来进行读写。

      另外附上一个基于WindowsAPI操作的封装类。

     IniFileHelp

    /// <summary>
    /// Provides methods for reading and writing to an INI file.
    /// </summary>
    public class IniFileHelp
    {
    /// <summary>
    /// The maximum size of a section in an ini file.
    /// </summary>
    /// <remarks>
    /// This property defines the maximum size of the buffers
    /// used to retreive data from an ini file. This value is
    /// the maximum allowed by the win32 functions
    /// GetPrivateProfileSectionNames() or
    /// GetPrivateProfileString().
    /// </remarks>
    public const int MaxSectionSize = 32767; // 32 KB

    //The path of the file we are operating on.
    private string m_path;

    #region P/Invoke declares

    /// <summary>
    /// A static class that provides the win32 P/Invoke signatures
    /// used by this class.
    /// </summary>
    /// <remarks>
    /// Note: In each of the declarations below, we explicitly set CharSet to
    /// Auto. By default in C#, CharSet is set to Ansi, which reduces
    /// performance on windows 2000 and above due to needing to convert strings
    /// from Unicode (the native format for all .Net strings) to Ansi before
    /// marshalling. Using Auto lets the marshaller select the Unicode version of
    /// these functions when available.
    /// </remarks>
    [System.Security.SuppressUnmanagedCodeSecurity]
    private static class NativeMethods
    {
    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    public static extern int GetPrivateProfileSectionNames(IntPtr lpszReturnBuffer,
    uint nSize,
    string lpFileName);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    public static extern uint GetPrivateProfileString(string lpAppName,
    string lpKeyName,
    string lpDefault,
    StringBuilder lpReturnedString,
    int nSize,
    string lpFileName);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    public static extern uint GetPrivateProfileString(string lpAppName,
    string lpKeyName,
    string lpDefault,
    [In, Out] char[] lpReturnedString,
    int nSize,
    string lpFileName);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    public static extern int GetPrivateProfileString(string lpAppName,
    string lpKeyName,
    string lpDefault,
    IntPtr lpReturnedString,
    uint nSize,
    string lpFileName);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    public static extern int GetPrivateProfileInt(string lpAppName,
    string lpKeyName,
    int lpDefault,
    string lpFileName);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    public static extern int GetPrivateProfileSection(string lpAppName,
    IntPtr lpReturnedString,
    uint nSize,
    string lpFileName);

    //We explicitly enable the SetLastError attribute here because
    // WritePrivateProfileString returns errors via SetLastError.
    // Failure to set this can result in errors being lost during
    // the marshal back to managed code.
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool WritePrivateProfileString(string lpAppName,
    string lpKeyName,
    string lpString,
    string lpFileName);


    }
    #endregion

    /// <summary>
    /// Initializes a new instance of the <see cref="IniFileHelp"/> class.
    /// </summary>
    /// <param name="path">The ini file to read and write from.</param>
    public IniFileHelp(string path)
    {
    //Convert to the full path. Because of backward compatibility,
    // the win32 functions tend to assume the path should be the
    // root Windows directory if it is not specified. By calling
    // GetFullPath, we make sure we are always passing the full path
    // the win32 functions.
    m_path = System.IO.Path.GetFullPath(path);
    }

    /// <summary>
    /// Gets the full path of ini file this object instance is operating on.
    /// </summary>
    /// <value>A file path.</value>
    public string Path
    {
    get
    {
    return m_path;
    }
    }

    #region Get Value Methods

    /// <summary>
    /// Gets the value of a setting in an ini file as a <see cref="T:System.String"/>.
    /// </summary>
    /// <param name="sectionName">The name of the section to read from.</param>
    /// <param name="keyName">The name of the key in section to read.</param>
    /// <param name="defaultValue">The default value to return if the key
    /// cannot be found.</param>
    /// <returns>The value of the key, if found. Otherwise, returns
    /// <paramref name="defaultValue"/></returns>
    /// <remarks>
    /// The retreived value must be less than 32KB in length.
    /// </remarks>
    /// <exception cref="ArgumentNullException">
    /// <paramref name="sectionName"/> or <paramref name="keyName"/> are
    /// a null reference (Nothing in VB)
    /// </exception>
    public string GetString(string sectionName,
    string keyName,
    string defaultValue)
    {
    if (sectionName == null)
    throw new ArgumentNullException("sectionName");

    if (keyName == null)
    throw new ArgumentNullException("keyName");

    StringBuilder retval = new StringBuilder(IniFileHelp.MaxSectionSize);

    NativeMethods.GetPrivateProfileString(sectionName,
    keyName,
    defaultValue,
    retval,
    IniFileHelp.MaxSectionSize,
    m_path);

    return retval.ToString();
    }

    /// <summary>
    /// Gets the value of a setting in an ini file as a <see cref="T:System.Int16"/>.
    /// </summary>
    /// <param name="sectionName">The name of the section to read from.</param>
    /// <param name="keyName">The name of the key in section to read.</param>
    /// <param name="defaultValue">The default value to return if the key
    /// cannot be found.</param>
    /// <returns>The value of the key, if found. Otherwise, returns
    /// <paramref name="defaultValue"/>.</returns>
    /// <exception cref="ArgumentNullException">
    /// <paramref name="sectionName"/> or <paramref name="keyName"/> are
    /// a null reference (Nothing in VB)
    /// </exception>
    public int GetInt16(string sectionName,
    string keyName,
    short defaultValue)
    {
    int retval = GetInt32(sectionName, keyName, defaultValue);

    return Convert.ToInt16(retval);
    }

    /// <summary>
    /// Gets the value of a setting in an ini file as a <see cref="T:System.Int32"/>.
    /// </summary>
    /// <param name="sectionName">The name of the section to read from.</param>
    /// <param name="keyName">The name of the key in section to read.</param>
    /// <param name="defaultValue">The default value to return if the key
    /// cannot be found.</param>
    /// <returns>The value of the key, if found. Otherwise, returns
    /// <paramref name="defaultValue"/></returns>
    /// <exception cref="ArgumentNullException">
    /// <paramref name="sectionName"/> or <paramref name="keyName"/> are
    /// a null reference (Nothing in VB)
    /// </exception>
    public int GetInt32(string sectionName,
    string keyName,
    int defaultValue)
    {
    if (sectionName == null)
    throw new ArgumentNullException("sectionName");

    if (keyName == null)
    throw new ArgumentNullException("keyName");


    return NativeMethods.GetPrivateProfileInt(sectionName, keyName, defaultValue, m_path);
    }

    /// <summary>
    /// Gets the value of a setting in an ini file as a <see cref="T:System.Double"/>.
    /// </summary>
    /// <param name="sectionName">The name of the section to read from.</param>
    /// <param name="keyName">The name of the key in section to read.</param>
    /// <param name="defaultValue">The default value to return if the key
    /// cannot be found.</param>
    /// <returns>The value of the key, if found. Otherwise, returns
    /// <paramref name="defaultValue"/></returns>
    /// <exception cref="ArgumentNullException">
    /// <paramref name="sectionName"/> or <paramref name="keyName"/> are
    /// a null reference (Nothing in VB)
    /// </exception>
    public double GetDouble(string sectionName,
    string keyName,
    double defaultValue)
    {
    string retval = GetString(sectionName, keyName, "");

    if (retval == null || retval.Length == 0)
    {
    return defaultValue;
    }

    return Convert.ToDouble(retval, CultureInfo.InvariantCulture);
    }

    #endregion

    #region GetSectionValues Methods

    /// <summary>
    /// Gets all of the values in a section as a list.
    /// </summary>
    /// <param name="sectionName">
    /// Name of the section to retrieve values from.
    /// </param>
    /// <returns>
    /// A <see cref="List{T}"/> containing <see cref="KeyValuePair{T1, T2}"/> objects
    /// that describe this section. Use this verison if a section may contain
    /// multiple items with the same key value. If you know that a section
    /// cannot contain multiple values with the same key name or you don't
    /// care about the duplicates, use the more convenient
    /// <see cref="GetSectionValues"/> function.
    /// </returns>
    /// <exception cref="ArgumentNullException">
    /// <paramref name="sectionName"/> is a null reference (Nothing in VB)
    /// </exception>
    public List<KeyValuePair<string, string>> GetSectionValuesAsList(string sectionName)
    {
    List<KeyValuePair<string, string>> retval;
    string[] keyValuePairs;
    string key, value;
    int equalSignPos;

    if (sectionName == null)
    throw new ArgumentNullException("sectionName");

    //Allocate a buffer for the returned section names.
    IntPtr ptr = Marshal.AllocCoTaskMem(IniFileHelp.MaxSectionSize);

    try
    {
    //Get the section key/value pairs into the buffer.
    int len = NativeMethods.GetPrivateProfileSection(sectionName,
    ptr,
    IniFileHelp.MaxSectionSize,
    m_path);

    keyValuePairs = ConvertNullSeperatedStringToStringArray(ptr, len);
    }
    finally
    {
    //Free the buffer
    Marshal.FreeCoTaskMem(ptr);
    }

    //Parse keyValue pairs and add them to the list.
    retval = new List<KeyValuePair<string, string>>(keyValuePairs.Length);

    for (int i = 0; i < keyValuePairs.Length; ++i)
    {
    //Parse the "key=value" string into its constituent parts
    //Cancel a string start with '#'
    var item = keyValuePairs[i].Trim();
    if (item.Length > 0 && !item.StartsWith("#"))
    {
    equalSignPos = keyValuePairs[i].IndexOf('=');
    key = keyValuePairs[i].Substring(0, equalSignPos);

    value = keyValuePairs[i].Substring(equalSignPos + 1,
    keyValuePairs[i].Length - equalSignPos - 1);

    retval.Add(new KeyValuePair<string, string>(key, value));
    }
    }

    return retval;
    }

    /// <summary>
    /// Gets all of the values in a section as a dictionary.
    /// </summary>
    /// <param name="sectionName">
    /// Name of the section to retrieve values from.
    /// </param>
    /// <returns>
    /// A <see cref="Dictionary{T, T}"/> containing the key/value
    /// pairs found in this section.
    /// </returns>
    /// <remarks>
    /// If a section contains more than one key with the same name,
    /// this function only returns the first instance. If you need to
    /// get all key/value pairs within a section even when keys have the
    /// same name, use <see cref="GetSectionValuesAsList"/>.
    /// </remarks>
    /// <exception cref="ArgumentNullException">
    /// <paramref name="sectionName"/> is a null reference (Nothing in VB)
    /// </exception>
    public Dictionary<string, string> GetSectionValues(string sectionName)
    {
    List<KeyValuePair<string, string>> keyValuePairs;
    Dictionary<string, string> retval;

    keyValuePairs = GetSectionValuesAsList(sectionName);

    //Convert list into a dictionary.
    retval = new Dictionary<string, string>(keyValuePairs.Count);

    foreach (KeyValuePair<string, string> keyValuePair in keyValuePairs)
    {
    //Skip any key we have already seen.
    if (!retval.ContainsKey(keyValuePair.Key))
    {
    retval.Add(keyValuePair.Key, keyValuePair.Value);
    }
    }

    return retval;
    }

    #endregion

    #region Get Key/Section Names

    /// <summary>
    /// Gets the names of all keys under a specific section in the ini file.
    /// </summary>
    /// <param name="sectionName">
    /// The name of the section to read key names from.
    /// </param>
    /// <returns>An array of key names.</returns>
    /// <remarks>
    /// The total length of all key names in the section must be
    /// less than 32KB in length.
    /// </remarks>
    /// <exception cref="ArgumentNullException">
    /// <paramref name="sectionName"/> is a null reference (Nothing in VB)
    /// </exception>
    public string[] GetKeyNames(string sectionName)
    {
    int len;
    string[] retval;

    if (sectionName == null)
    throw new ArgumentNullException("sectionName");

    //Allocate a buffer for the returned section names.
    IntPtr ptr = Marshal.AllocCoTaskMem(IniFileHelp.MaxSectionSize);

    try
    {
    //Get the section names into the buffer.
    len = NativeMethods.GetPrivateProfileString(sectionName,
    null,
    null,
    ptr,
    IniFileHelp.MaxSectionSize,
    m_path);

    retval = ConvertNullSeperatedStringToStringArray(ptr, len);
    }
    finally
    {
    //Free the buffer
    Marshal.FreeCoTaskMem(ptr);
    }

    return retval;
    }

    /// <summary>
    /// Gets the names of all sections in the ini file.
    /// </summary>
    /// <returns>An array of section names.</returns>
    /// <remarks>
    /// The total length of all section names in the section must be
    /// less than 32KB in length.
    /// </remarks>
    public string[] GetSectionNames()
    {
    string[] retval;
    int len;

    //Allocate a buffer for the returned section names.
    IntPtr ptr = Marshal.AllocCoTaskMem(IniFileHelp.MaxSectionSize);

    try
    {
    //Get the section names into the buffer.
    len = NativeMethods.GetPrivateProfileSectionNames(ptr,
    IniFileHelp.MaxSectionSize, m_path);

    retval = ConvertNullSeperatedStringToStringArray(ptr, len);
    }
    finally
    {
    //Free the buffer
    Marshal.FreeCoTaskMem(ptr);
    }

    return retval;
    }

    /// <summary>
    /// Converts the null seperated pointer to a string into a string array.
    /// </summary>
    /// <param name="ptr">A pointer to string data.</param>
    /// <param name="valLength">
    /// Length of the data pointed to by <paramref name="ptr"/>.
    /// </param>
    /// <returns>
    /// An array of strings; one for each null found in the array of characters pointed
    /// at by <paramref name="ptr"/>.
    /// </returns>
    private static string[] ConvertNullSeperatedStringToStringArray(IntPtr ptr, int valLength)
    {
    string[] retval;

    if (valLength == 0)
    {
    //Return an empty array.
    retval = new string[0];
    }
    else
    {
    //Convert the buffer into a string. Decrease the length
    //by 1 so that we remove the second null off the end.
    string buff = Marshal.PtrToStringAuto(ptr, valLength - 1);

    //Parse the buffer into an array of strings by searching for nulls.
    retval = buff.Split('');
    }

    return retval;
    }

    #endregion

    #region Write Methods

    /// <summary>
    /// Writes a <see cref="T:System.String"/> value to the ini file.
    /// </summary>
    /// <param name="sectionName">The name of the section to write to .</param>
    /// <param name="keyName">The name of the key to write to.</param>
    /// <param name="value">The string value to write</param>
    /// <exception cref="T:System.ComponentModel.Win32Exception">
    /// The write failed.
    /// </exception>
    private void WriteValueInternal(string sectionName, string keyName, string value)
    {
    if (!NativeMethods.WritePrivateProfileString(sectionName, keyName, value, m_path))
    {
    throw new System.ComponentModel.Win32Exception();
    }
    }

    /// <summary>
    /// Writes a <see cref="T:System.String"/> value to the ini file.
    /// </summary>
    /// <param name="sectionName">The name of the section to write to .</param>
    /// <param name="keyName">The name of the key to write to.</param>
    /// <param name="value">The string value to write</param>
    /// <exception cref="T:System.ComponentModel.Win32Exception">
    /// The write failed.
    /// </exception>
    /// <exception cref="ArgumentNullException">
    /// <paramref name="sectionName"/> or <paramref name="keyName"/> or
    /// <paramref name="value"/> are a null reference (Nothing in VB)
    /// </exception>
    public void WriteValue(string sectionName, string keyName, string value)
    {
    if (sectionName == null)
    throw new ArgumentNullException("sectionName");

    if (keyName == null)
    throw new ArgumentNullException("keyName");

    if (value == null)
    throw new ArgumentNullException("value");

    WriteValueInternal(sectionName, keyName, value);
    }

    /// <summary>
    /// Writes an <see cref="T:System.Int16"/> value to the ini file.
    /// </summary>
    /// <param name="sectionName">The name of the section to write to .</param>
    /// <param name="keyName">The name of the key to write to.</param>
    /// <param name="value">The value to write</param>
    /// <exception cref="T:System.ComponentModel.Win32Exception">
    /// The write failed.
    /// </exception>
    public void WriteValue(string sectionName, string keyName, short value)
    {
    WriteValue(sectionName, keyName, (int)value);
    }

    /// <summary>
    /// Writes an <see cref="T:System.Int32"/> value to the ini file.
    /// </summary>
    /// <param name="sectionName">The name of the section to write to .</param>
    /// <param name="keyName">The name of the key to write to.</param>
    /// <param name="value">The value to write</param>
    /// <exception cref="T:System.ComponentModel.Win32Exception">
    /// The write failed.
    /// </exception>
    /// <exception cref="ArgumentNullException">
    /// <paramref name="sectionName"/> or <paramref name="keyName"/> are
    /// a null reference (Nothing in VB)
    /// </exception>
    public void WriteValue(string sectionName, string keyName, int value)
    {
    WriteValue(sectionName, keyName, value.ToString(CultureInfo.InvariantCulture));
    }

    /// <summary>
    /// Writes an <see cref="T:System.Single"/> value to the ini file.
    /// </summary>
    /// <param name="sectionName">The name of the section to write to .</param>
    /// <param name="keyName">The name of the key to write to.</param>
    /// <param name="value">The value to write</param>
    /// <exception cref="T:System.ComponentModel.Win32Exception">
    /// The write failed.
    /// </exception>
    /// <exception cref="ArgumentNullException">
    /// <paramref name="sectionName"/> or <paramref name="keyName"/> are
    /// a null reference (Nothing in VB)
    /// </exception>
    public void WriteValue(string sectionName, string keyName, float value)
    {
    WriteValue(sectionName, keyName, value.ToString(CultureInfo.InvariantCulture));
    }

    /// <summary>
    /// Writes an <see cref="T:System.Double"/> value to the ini file.
    /// </summary>
    /// <param name="sectionName">The name of the section to write to .</param>
    /// <param name="keyName">The name of the key to write to.</param>
    /// <param name="value">The value to write</param>
    /// <exception cref="T:System.ComponentModel.Win32Exception">
    /// The write failed.
    /// </exception>
    /// <exception cref="ArgumentNullException">
    /// <paramref name="sectionName"/> or <paramref name="keyName"/> are
    /// a null reference (Nothing in VB)
    /// </exception>
    public void WriteValue(string sectionName, string keyName, double value)
    {
    WriteValue(sectionName, keyName, value.ToString(CultureInfo.InvariantCulture));
    }

    #endregion

    #region Delete Methods

    /// <summary>
    /// Deletes the specified key from the specified section.
    /// </summary>
    /// <param name="sectionName">
    /// Name of the section to remove the key from.
    /// </param>
    /// <param name="keyName">
    /// Name of the key to remove.
    /// </param>
    /// <exception cref="ArgumentNullException">
    /// <paramref name="sectionName"/> or <paramref name="keyName"/> are
    /// a null reference (Nothing in VB)
    /// </exception>
    public void DeleteKey(string sectionName, string keyName)
    {
    if (sectionName == null)
    throw new ArgumentNullException("sectionName");

    if (keyName == null)
    throw new ArgumentNullException("keyName");

    WriteValueInternal(sectionName, keyName, null);
    }

    /// <summary>
    /// Deletes a section from the ini file.
    /// </summary>
    /// <param name="sectionName">
    /// Name of the section to delete.
    /// </param>
    /// <exception cref="ArgumentNullException">
    /// <paramref name="sectionName"/> is a null reference (Nothing in VB)
    /// </exception>
    public void DeleteSection(string sectionName)
    {
    if (sectionName == null)
    throw new ArgumentNullException("sectionName");

    WriteValueInternal(sectionName, null, null);
    }

    #endregion
    }

    IniFileHelp

    MSD_radix_sort

     

    一、这次是在上一次尝试基础上进行的,预期是达到上次性能的9倍。

    MSD的基本手法就是不断切片。
    每一步都是把整体数据切割成256片,如上图所示,实际情况切片未必均匀,有的slice内可能一个元素也没有。

    接下来对于每个切片怎么办呢?
    答案是继续切,对于特殊数据来讲,切片过程可以很快结束,这样就可以实现比LSD更快的速度。

    这里面最困难的地方就是如何存储每个slice的头和尾。
    如果采用下述方式,应该是行不通的。
    这个方式需要做数组元素插入,还要跟踪中间数据,因此没具体考虑。

    我真正采用的是下表:


    表中第一项表示第一个元素开启一个类别,紧跟的0表示此元素和上面的1是同一类。
    至于2表明在切片过程中是一个孤立的元素,后续就没必要再切片了。
    这个方式可以大大简化编码。

    二、伪代码。

    for each slice
        if slice-tag == 2 continue;
        if slice-tag == 1
            slice it;
            update bookkeeping
    复制代码
    int main(){
        HANDLE heap = NULL;
        Bucket bucket[BUCKETSLOTCOUNT];
        PageList * pageListPool;
        int plpAvailable = 0;
        int * pages = NULL;
        int * pagesAvailable = NULL;
        int * objIdx;
        unsigned short * s;
        __int8 * classifier = NULL;
    
        time_t timeBegin;
        time_t timeEnd;
    
        heap = HeapCreate(HEAP_NO_SERIALIZE|HEAP_GENERATE_EXCEPTIONS, 1024*1024, 0);
        if (heap != NULL){
            pages = (int * )HeapAlloc(heap, 0, (TFSI/PAGEGRANULAR + BUCKETSLOTCOUNT + 8) * PAGEAMOUNT);
            pageListPool = (PageList *)HeapAlloc(heap, 0, (TFSI/PAGEGRANULAR + 8) * sizeof(PageList));
            s = (unsigned short *)HeapAlloc(heap, 0, TFSI*sizeof(unsigned short));
            objIdx = (int *)HeapAlloc(heap, 0, TFSI * sizeof(int));
            classifier = (__int8 *)HeapAlloc(heap, 0, (TFSI+8)*sizeof(__int8));
        }
        MakeSure(pages != NULL && pageListPool != NULL && objIdx != NULL && classifier != NULL);
    
        for(int i=0; i<TFSI; i++) objIdx[i]=i;
        timeBegin = clock();
        for (int i=0; i<TFSI; i++) s[i] = rand();
        timeEnd = clock();
        printf("
    %f(s) consumed in generating numbers", (double)(timeEnd-timeBegin)/CLOCKS_PER_SEC);
    
        SecureZeroMemory(classifier, TFSI*sizeof(__int8));
        classifier[0] = 1;
        classifier[TFSI] = 1;
        
        timeBegin = clock();
    
        bool no_need_further_processing = false;
        for (int t=sizeof(short)-1; t>=0; t--){
            int bucketIdx;
            int slice_pointer = 0;
            int slice_base = 0;
            int flagCounter = 0;
    
            if (no_need_further_processing) break;
    
            //classifier: 1 new catagory
            //classifier: 2 completed catagory process
            while (slice_pointer < TFSI){
                if (classifier[slice_pointer] == 2){
                    slice_base = slice_pointer;
                    classifier[slice_base] = 0;
                    while (classifier[slice_pointer] == 0){
                        slice_pointer++;
                        flagCounter++;
                    }
                    classifier[slice_base] = 2;
    
                    if (flagCounter == TFSI) no_need_further_processing = true;
                    continue;
                }
                
                if (classifier[slice_pointer] == 1){
                    FillMemory(pages, (TFSI/PAGEGRANULAR + BUCKETSLOTCOUNT + 8) * PAGEAMOUNT, 0xff);
                    SecureZeroMemory(pageListPool, (TFSI/PAGEGRANULAR + 8) * sizeof(PageList));
                    pagesAvailable = pages;
                    plpAvailable = 0;
    
                    for(int i=0; i<256; i++){
                        bucket[i].currentPagePtr = pagesAvailable;
                        bucket[i].offset = 0;
                        bucket[i].pl.PagePtr = pagesAvailable;
                        bucket[i].pl.next = NULL;
                        pagesAvailable += PAGEGRANULAR;
                        bucket[i].currentPageListItem = &(bucket[i].pl);
                    }
    
                    slice_base = slice_pointer;
                    classifier[slice_base] = 0;
                    while (classifier[slice_pointer] == 0){
                        //for each slice element, push_back to pages;
                        unsigned char * cell = (unsigned char *)&s[objIdx[slice_pointer]];
                        bucketIdx =  cell[t];
                        //save(bucketIdx, objIdx[i]);
                        bucket[bucketIdx].currentPagePtr[ bucket[bucketIdx].offset ] = objIdx[slice_pointer];
                        bucket[bucketIdx].offset++;
                        if (bucket[bucketIdx].offset == PAGEGRANULAR){
                            bucket[bucketIdx].currentPageListItem->next = &pageListPool[plpAvailable];
                            plpAvailable++;
                            bucket[bucketIdx].currentPageListItem->next->PagePtr = pagesAvailable;
                            bucket[bucketIdx].currentPageListItem->next->next = NULL;
                            
                            bucket[bucketIdx].currentPagePtr = pagesAvailable;
                            bucket[bucketIdx].offset = 0;
                            pagesAvailable += PAGEGRANULAR;
                            
                            bucket[bucketIdx].currentPageListItem = bucket[bucketIdx].currentPageListItem->next;
                        }
    
                        slice_pointer++;
                    }
                    classifier[slice_base] = 1;
    
                    //update classifier;
                    //update objIdx index
                    int start = slice_base;
                    for (int i=0; i<256; i++){
                        PageList * p;
                        p = &(bucket[i].pl);
                        //classifier: 1 new catagory
                        //classifier: 2 complete catagory process
                        classifier[start] = 1;
    
                        int counters = 0;
                        while (p){
                            for (int t=0; t<PAGEGRANULAR; t++){
                                int idx = p->PagePtr[t];
                                if (idx != TERMINATOR){
                                    objIdx[start] = idx;
                                    start++;
                                    counters++;
                                }
                                if (idx == TERMINATOR) break;
                            }
                            p = p->next;
                        }
                        if (counters == 1) classifier[start-1] = 2;
                    }
                    //update objIdx index
                }   //if (classifier[slice_pointer] == 1)
            }        //while (slice_pointer < TFSI) 
        }            //for (int t=sizeof(short)-1; t>=0; t--)
    
        timeEnd = clock();
        printf("
    %f(s) consumed in generating results", (double)(timeEnd-timeBegin)/CLOCKS_PER_SEC);
        
        //for(int i=0; i<TFSI; i++) printf("%d
    ", s[objIdx[i]]);
    
        HeapFree(heap, 0, pages);
        HeapFree(heap, 0, pageListPool);
        HeapFree(heap, 0, s);
        HeapFree(heap, 0, objIdx);
        HeapFree(heap, 0, classifier);
        HeapDestroy(heap);
    
        return 0;
    }
    复制代码

    三、测试

    1024*1024*100 个短整型。

    时间  5.438s

    看到这里就知道杯具了,比LSD还慢。

    如果应用到二维表,会更惨不忍睹。试了下果然如此。

    四、讨论

    如果哪位有更好的方法,欢迎讨论。

    或者,基数排序只是一个花瓶?

     
     
    分类: C/C++
  • 相关阅读:
    gulp ( http://markpop.github.io/2014/09/17/Gulp入门教程 )
    less 官网讲解 ( http://www.bootcss.com/p/lesscss/ )
    js 闭包 弊端
    js 闭包 理解 copy
    js 中 的 if使用条件
    $ each() 小结
    文件自动加载
    (openssl_pkey_get_private 函数不存在)phpstudy开启openssl.dll 时提示httpd.exe 丢失libssl-1_1.dll
    form
    js字符串处理
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3371317.html
Copyright © 2020-2023  润新知