C# 版本八大排序算法|.Net 架构

前言

高质量博客汇总https://blog.csdn.net/yu_cblog/category_12379430.html成熟常用的开发工具和框架https://blog.csdn.net/yu_cblog/category_12737979.htmlDocker从认识到实践再到底层原理https://blog.csdn.net/yu_cblog/category_12424689.html操作系统和计算机网络从入门到深入https://blog.csdn.net/yu_cblog/category_12524753.html

C++/C和Go语言版本的八大排序

【排序】万字九大排序宝藏汇总 轻松拿下九大排序算法【带动画】 (包含超详细的解释和注释)https://blog.csdn.net/Yu_Cblog/article/details/122848138Go语言实现八大排序|排序算法|超详细保姆级别注释https://blog.csdn.net/Yu_Cblog/article/details/132843117

C# 的八大排序

cs 复制代码
internal class RandomArrayGenerator
{
    public static int[] GenerateRandomIntArray(int length, int min, int max)
    {
        Random random = new Random();
        int[] array = new int[length];
        for (int i = 0; i < length; i++)
            array[i] = random.Next(min, max);
        return array;
    }
}
internal class Utils
{
    public static void ShowList<T>(T container)
    {
        // 处理 IEnumerable<T> 类型的容器,如 List<T>, Stack<T>, Queue<T>
        if (container is IEnumerable enumerable)
        {
            foreach (var item in enumerable)
            {
                Console.Write(item + " ");
            }
        }
        // 处理 Dictionary<TKey, TValue> 类型的容器
        else if (container is IDictionary dictionary)
        {
            foreach (DictionaryEntry entry in dictionary)
            {
                Console.Write($"[{entry.Key}, {entry.Value}] ");
            }
        }
        else
        {
            Console.WriteLine("Unsupported container type.");
            return;
        }
        Console.WriteLine();
    }
    public static void Swap<T>(ref T lhs, ref T rhs)
    {
        T temp;
        temp = lhs;
        lhs = rhs;
        rhs = temp;
    }
}
internal class SortMethods
{
    public static void BubbleSort(int[] arr)
    {
        int sz = arr.Length;
        for (int i = 0; i < sz - 1; i++)
            for (int j = 0; j < sz - 1 - i; j++)
                if (arr[j] > arr[j + 1])
                    Utils.Swap(ref arr[j], ref arr[j + 1]);
    }
    public static void SelectSort(int[] arr)
    {
        int sz = arr.Length;
        for (int i = 0; i < sz - 1; i++) 
        {
            int min_idx = i;
            for(int j = i+ 1; j < sz; j++)
                if (arr[j] < arr[min_idx])
                    min_idx = j;
            Utils.Swap(ref arr[i], ref arr[min_idx]);
        }
    }
    public static void InsertSort(int[] arr)
    {
        int sz = arr.Length;
        int sort_num = 0;
        for (int i = 0; i < sz; i++)
        {
            int j;
            sort_num = arr[i]; // the number need to be sort
            for(j =i - 1; j>= 0; j--)
            {
                if (arr[j] < sort_num) break;
                arr[j + 1] = arr[j];
            }
            arr[j + 1] = sort_num;
        }
    }
    private static void ShellSortInGroup(int[] arr, int pos, int step)
    {
        // pos+step is the idx of the first element in this group
        // and sort this group with insert_sort, same with insert sort
        int sort_num = 0;
        int i = 0, j = 0;
        int sz = arr.Length;
        for (i = pos + step; i < sz; i += step)
        {
            sort_num = arr[i];
            for (j = i - step; j >= 0; j -= step)
            {
                if (arr[j] < sort_num) break;
                arr[j + step] = arr[j];
            }
            arr[j + step] = sort_num;
        }
    }
    public static void ShellSort(int[] arr)
    {
        int i = 0;
        int step = 0;
        int sz = arr.Length;
        // step is the step length, each time it is reduced to half of the original value,
        // take an integer, the last one must be 1
        for (step = sz / 2; step > 0; step /= 2) 
            for (i = 0; i < step; i++)
                ShellSortInGroup(arr, i, step);
    }
    private static int QuickSortPartSort(int[] arr, int begin, int end)
    {
        int left = begin;
        int right = end;
        int keyi = left;
        while (left < right) 
        {
            // right move first, find smaller
            while (left < right && arr[right] >= arr[keyi]) --right;
            // left move, find bigger
            while (left < right && arr[left] <= arr[keyi]) ++left;
            Utils.Swap(ref arr[left], ref arr[right]);
        }
        Utils.Swap(ref arr[keyi], ref arr[right]);
        keyi = left;
        return keyi;
    }
    private static void QuickSortByRange(int[] arr, int begin, int end)
    {
        // The interval does not exist or has only one value and does not need to be processed anymore
        // Quick sort: Get the key right each time, and recursively solve the numbers on both sides of the key
        if (begin >= end) return;
        int keyi = QuickSortPartSort(arr, begin, end);
        QuickSortByRange(arr, begin, keyi - 1);
        QuickSortByRange(arr, keyi + 1, end);
    }
    public static void QuickSort(int[] arr)
    {
        int begin = 0; int end = arr.Length - 1;
        QuickSortByRange(arr, begin, end);
    }
    private static void MergeSortByRange(int[] arr, int[] temp, int start, int end)
    {
        Debug.Assert(arr.Length == temp.Length, "arr.Length should equal to temp.Length");
        if (start >= end) return;
        int mid = start + (end - start) / 2; // find the mid idx of the array
        // cut the array into to parts
        int istart1 = start;
        int iend1 = mid;
        int istart2 = mid + 1;
        int iend2 = end;
        // both part call the range sort
        MergeSortByRange(arr, temp, istart1, iend1);
        MergeSortByRange(arr, temp, istart2, iend2);
        // merge 2 parts
        int i = start;
        while (istart1 <= iend1 && istart2 <= iend2)
        {
            temp[i] = arr[istart1] < arr[istart2] ? arr[istart1++] : arr[istart2++];
            ++i;
        }
        while (istart1 <= iend1)
        {
            temp[i] = arr[istart1];
            i++;
            istart1++;
        }
        while (istart2 <= iend2)
        {
            temp[i] = arr[istart2];
            i++;
            istart2++;
        }
        Array.Copy(temp, start, arr, start, end - start + 1);
    }
    public static void MergeSort(int[] arr)
    {
        if (arr.Length < 2) return;
        int[] temp = new int[arr.Length];
        MergeSortByRange(arr, temp, 0, arr.Length - 1);
    }
    private static void HeapSortAdjustDown(int[] arr, int begin, int end)
    {
        int parent = begin;
        int child = parent * 2 + 1;
        while(child <= end)
        {
            if ((child + 1 <= end) && (arr[child] < arr[child + 1])) child++;
            if (arr[parent] > arr[child]) return;
            Utils.Swap(ref arr[parent], ref arr[child]);
            parent = child;
            child = parent * 2 + 1;
        }
    }
    public static void HeapSort(int[] arr)
    {
        int i = 0;
        // make_heap
        for (i = (arr.Length - 1) / 2; i >= 0; i--)
            HeapSortAdjustDown(arr, i, arr.Length - 1);
        // swap first element and the last element
        for (i = arr.Length - 1; i > 0; i--)
        {
            Utils.Swap(ref arr[0], ref arr[i]);
            HeapSortAdjustDown(arr, 0, i - 1);
        }
    }
    internal class RadixSort
    {
        private static int K = -1; // Up to three digits
        private const int RADIX = 10; // ten radixes
        private static Queue<int>[] Q = Enumerable.Range(0, RADIX).Select(_ => new Queue<int>()).ToArray(); // array of queue
        private static int GetKey(int val, int k)
        {
            int key = 0;
            while (k >= 0) 
            {
                key = val % 10;
                val /= 10;
                k--;
            }
            return key;
        }
        private static void Distribute(int[] arr, int left, int right, int k)
        {
            for(int i = left; i < right; i++)
            {
                int key = GetKey(arr[i], k);
                Q[key].Enqueue(arr[i]);
            }
        }
        private static void Collect(int[] arr)
        {
            /* No need to distinguish the order, just recycle the data into the array
            Check all queues, because we don't know which queues have data and which don't */
            int k = 0;
            for(int i = 0; i < RADIX; ++i)
                while (Q[i].Count > 0)
                    arr[k++] = Q[i].Dequeue();
        }
        private static void SortByRange(int[] arr, int left, int right)
        {
            Debug.Assert(K > 0, "need to init the K in Sort()");
            for (int i = 0; i < K; ++i)
            {
                // How many digits are there and how many times are they repeated
                // distribute the data
                Distribute(arr, left, right, i); // i represents the digit I am currently operating on
                // collect the data
                Collect(arr);
            }
        }
        private static bool CheckSequenceValidity(int[] arr)
        {
            /* Radix sorting can generally only process non - negative numbers,
                otherwise special preprocessing is required */
            foreach (int number in arr)
                if (number < 0)
                    return false;
            return true;
        }
        public static void Sort(int[] arr, int InputK)
        {
            K = InputK;
            int left = 0; int right = arr.Length;
            Debug.Assert(CheckSequenceValidity(arr));
            SortByRange(arr, left, right);
        }
    }
    public static void Run()
    {
        //int[] arr = new int[] { 1, 3, 5, 7, 9, 2, 4, 6, 8, 10, 12 };
        int len = 10;
        int max = 100;
        int min = 0;
        int[] arr = RandomArrayGenerator.GenerateRandomIntArray(len, min, max);
        int[] sorted_arr = (int[])arr.Clone();
        Array.Sort(sorted_arr);
        RadixSort.Sort(arr, 3); // 3 refs to the max digits number of the seq
        if (len <= 30)
        {
            Console.Write("My Sort:    "); Utils.ShowList(arr);
            Console.Write("Array.Sort: "); Utils.ShowList(sorted_arr);
        }
        Console.WriteLine(arr.SequenceEqual(sorted_arr));
    }
}

性能测试

性能测试代码如下所示。

cs 复制代码
internal class PerformanceTest
{
    public static void RunPerformanceTests(int numberOfTests)
    {
        int len = 10000; // 可以根据需要调整数组的大小
        int max = 100000;
        int min = 0;
        Random rnd = new Random();
        // Create an initial array and copy it for different sorting methods
        int[] originalArray = Enumerable.Range(0, len).Select(x => rnd.Next(min, max)).ToArray();
        Stopwatch sw = new Stopwatch();
        Console.WriteLine("Running performance tests...");
        // Used to store the total time for each sort
        double[] times = new double[8]; // Corresponding to 8 sorting methods
        for (int test = 0; test < numberOfTests; test++)
        {
            int[] tempArray;
            // Bubble Sort
            tempArray = (int[])originalArray.Clone();
            sw.Restart();
            BubbleSort(tempArray);
            sw.Stop();
            times[0] += sw.Elapsed.TotalMilliseconds;
            // Select Sort
            tempArray = (int[])originalArray.Clone();
            sw.Restart();
            SelectSort(tempArray);
            sw.Stop();
            times[1] += sw.Elapsed.TotalMilliseconds;
            // Insert Sort
            tempArray = (int[])originalArray.Clone();
            sw.Restart();
            InsertSort(tempArray);
            sw.Stop();
            times[2] += sw.Elapsed.TotalMilliseconds;
            // Shell Sort
            tempArray = (int[])originalArray.Clone();
            sw.Restart();
            ShellSort(tempArray);
            sw.Stop();
            times[3] += sw.Elapsed.TotalMilliseconds;
            // Quick Sort
            tempArray = (int[])originalArray.Clone();
            sw.Restart();
            QuickSort(tempArray);
            sw.Stop();
            times[4] += sw.Elapsed.TotalMilliseconds;
            // Merge Sort
            tempArray = (int[])originalArray.Clone();
            sw.Restart();
            MergeSort(tempArray);
            sw.Stop();
            times[5] += sw.Elapsed.TotalMilliseconds;
            // Heap Sort
            tempArray = (int[])originalArray.Clone();
            sw.Restart();
            HeapSort(tempArray);
            sw.Stop();
            times[6] += sw.Elapsed.TotalMilliseconds;
            // Radix Sort
            tempArray = (int[])originalArray.Clone();
            sw.Restart();
            RadixSort.Sort(tempArray, 6); // Assuming 6 digits max for simplicity
            sw.Stop();
            times[7] += sw.Elapsed.TotalMilliseconds;
        }
        // print avg time
        string[] sortNames = { "Bubble Sort", "Select Sort", "Insert Sort", "Shell Sort", "Quick Sort", "Merge Sort", "Heap Sort", "Radix Sort" };
        Console.WriteLine($"Average times for {numberOfTests} tests:");
        for (int i = 0; i < times.Length; i++)
        {
            Console.WriteLine($"{sortNames[i],-12}: {times[i] / numberOfTests} ms");
        }
    }
}

测试结果

相关推荐
励志成为嵌入式工程师41 分钟前
c语言简单编程练习9
c语言·开发语言·算法·vim
捕鲸叉1 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer1 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
wheeldown2 小时前
【数据结构】选择排序
数据结构·算法·排序算法
观音山保我别报错3 小时前
C语言扫雷小游戏
c语言·开发语言·算法
TangKenny4 小时前
计算网络信号
java·算法·华为
景鹤4 小时前
【算法】递归+深搜:814.二叉树剪枝
算法
iiFrankie4 小时前
SCNU习题 总结与复习
算法
Dola_Pan5 小时前
C++算法和竞赛:哈希算法、动态规划DP算法、贪心算法、博弈算法
c++·算法·哈希算法
小林熬夜学编程5 小时前
【Linux系统编程】第四十一弹---线程深度解析:从地址空间到多线程实践
linux·c语言·开发语言·c++·算法