排序算法C#实现之计数排序、桶排序、基数排序详解

【任务目标】

将一组无序数组变为有序

【计数排序原理】

  • 找到数组中的最大值Max和最小值Min。那么数组中其他的所有数都在Min和Max之间
  • 设置Max-Min+1个桶(盒子、容器,怎么说都可以),每个桶只能装一种数。那么数组中的所有数都能找到对应的桶,桶中数字的个数表示数组中有多少个这样的数。
  • 按顺序把桶中的数字取出来,桶内数字个数为0表示改桶内没数字了,继续取下一个桶,直到取完对应数字为Max的桶。此时按顺序取出来的数字是有序的。

【计数排序原理概括】

根据数组中最大值和最小值设置相应数量的有序桶,让数组中的数据在放置过程中自然有序。

【桶排序原理】

在计数排序中,会有很多桶是空的,例如最小值为1,最大值为10000时,会有很多空桶。为了减小桶的数量,让桶内可以放置一定范围内的数字(范围=桶的大小),而不是一种数字。对每个桶内的数字单独排序,随后再将桶内数字按顺序取出,取出来的数字是有序的。

这实际上是将待排序数组划分为了很多小部分(即桶),在小部分中分别排序,这个划分是有选择性的,选择的结果是每个小部分之间是有序的,这和快速排序类似,实际上快速排序中的每个小部分都可以采用其他排序方法,桶排序中每个小部分也可以采用其他排序方法。归并排序虽然也划分了很多小部分,但每个部分之间没有有序性。

【桶排序原理概括】

将无序数组划分为多个有序部分,对每个部分分别排序,连接形成有序数组

【基数排序原理】

对于这样一组数据A={32,87,234,631,126},通过依次比较每个数的个位、十位、百位来比较他们的大小。比较个位时A={631,32,234,126,87}。比较十位时,A={32,126,234,631,87}。比较百位时,A={32,87,126,234,631},此时有序。

设置0~9共十个桶,根据A中数字每位的大小放入对应的桶中,再依次从桶中取出数字。这样有相同位数的数字得到了正确排序,直到所有位置的数字都得到正确的排序,数组就有序了。

【基数排序原理概括】

通过比较数组中不同数字的在不同位数处的大小使得数组有序。

【代码实现】

using System;
using System.Collections.Generic;
using System.Linq;

namespace Sort
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] A = new int[30];
            Random ra = new Random();
            for (int i = 0; i < 30; i++)
            {
                A[i] = ra.Next(200);
            }
            Program ps = new Program();
            ps.BucketSort(A,5);
            Console.WriteLine("排序结果:");
            foreach (int a in A)
            {
                Console.Write(a + " ");
            }
            bool isSorted = true;
            for (int i = 0; i < A.Length - 1; i++)
            {
                if (A[i] > A[i + 1])
                    isSorted = false;
            }
            Console.Write(isSorted);
            Console.ReadKey();
        }

        public void CountingSort(int[] A)
        {
            //找出数组中的最大最小值
            int max = 0;
            int min = 0;
            for (int i = 0; i < A.Length; i++)
            {
                if (A[i] > max)
                {
                    max = A[i];
                }
                if (A[i] < min)
                {
                    min = A[i];
                }
            }

            //创建桶,有max-min+1个桶,每个桶只能存放一种数
            int[] buckets=new int[max-min+1];
            //遍历数组,找出在数组中,在最大值和最小值之间每个数的个数
            for (int i = 0; i < A.Length; i++)
            {
                buckets[A[i] - min]++;
            }
            //根据桶中每个数的个数排序
            int count = 0;//数组下标
            for (int i = 0; i < buckets.Length; i++)
            {
                while (buckets[i]>0)
                {
                    A[count] = i + min;
                    buckets[i]--;
                    count++;
                }
            }
        }

        public void BucketSort(int[] A,int size)
        {
            //找出数组中的最大最小值
            int max = 0;
            int min = 0;
            for (int i = 0; i < A.Length; i++)
            {
                if (A[i] > max)
                {
                    max = A[i];
                }
                if (A[i] < min)
                {
                    min = A[i];
                }
            }

            //创建桶,每个桶可以存放size种数
            int bucketCount = (max - min)/size + 1;
            List> buckets=new List>();
            for (int i = 0; i < bucketCount; i++)
            {
                buckets.Add(new List());
            }
            for (int i = 0; i < A.Length; i++)
            {
                int bucketNum = (A[i] - min)/size;
                buckets[bucketNum].Add(A[i]);
            }
            int count = 0;//数组下标
            for (int i = 0; i < bucketCount; i++)
            {
                //对每个桶内的数重新排序,可以用其他排序方法
                List bucket= buckets[i];
                bucket.Sort();
                foreach (int temp in bucket)
                {
                    A[count] = temp;
                    count++;
                }                                        

            }

        }

        public void RadixSort(int[] A )
        {
            //找出最大值
            int max = 0;
            for (int i = 0; i < A.Length; i++)
            {
                if (A[i] > max)
                {
                    max = A[i];
                }
            }
            //求最大值有几位数
            int num=0;
            while (max>0)
            {
                max /= 10;
                num++;
            }

            //创建桶
            List> buckets=new List>();
            for (int i = 0; i < 10; i++)
            {
                buckets.Add(new List());
            }

            for (int i = 0; i < num; i++)
            {
                //将数组中的元素分配到桶中
                for (int j = 0; j < A.Length; j++)
                {
                    //取出345中的十位,先除100取余数,再除10取整数
                    int remainder = (int) (A[j]%Math.Pow(10, i + 1)/Math.Pow(10, i));
                    buckets[remainder].Add(A[j]);//添加进对应序号(0~9)的桶中
                }

                //再将桶中的数据取出放回到数组中
                int count = 0;//数组下标
                for (int j = 0; j < 10; j++)//桶的标号
                {
                    List curBucket = buckets[j];
                    while (curBucket.Count>0)
                    {
                        A[count] = curBucket[0];//取第一个
                        curBucket.RemoveAt(0);//移除第一个
                        count++;//数组下标增加
                    }
                }
            }

        }
    }
}

【实现结果】

你可能感兴趣的:(数据结构与算法)