代码改变世界

算法

2018-01-13 17:46  梦游0和1的世界  阅读(186)  评论(0编辑  收藏  举报

 

 class Program
    {
        static void Main(string[] args)
        {

            int[] arr = new int[100];

            Random r = new Random();

            for (int i = 0; i < arr.Length; i++)
            {
                arr[i] = r.Next(1, 1000);
            }

            radixSort(arr,0,arr.Length-1,3);
            arr.ToList().ForEach(i => Console.Write(" " + i));


            Console.ReadKey();
        }

        public static void BobSort(int[] input)
        {
            //冒泡排序i循环每次使一个最大元素在末尾
            //j循环应该排序在末尾的若干已排序大值  循环次数=总排序次数-已排序次数
            int temp = 0;

            for (int i = 0; i < input.Length - 1; i++)
            {
                for (int j = 0; j < input.Length - 1 - i; j++)
                {
                    if (input[j] > input[j + 1])
                    {
                        temp = input[j];
                        input[j] = input[j + 1];
                        input[j + 1] = temp;
                    }
                }
            }
        }

        public static void InsertSort(int[] arr)
        {

            //插入排序  类似于理牌
            //第一位默认有序,从第二位开始,抽出,插入,元素往后移动
            //当抽出元素大于当前比对元素,不作操作,当小于当前比对元素,将后置元素往后依此挪一位,留出空间给要插入的元素
            int curval;
            int curindex;

            for (int i = 1; i < arr.Length; i++)
            {
                curindex = i;
                curval = arr[i];

                //直至索引到1时,0时不用再比较,为最小,直接赋值
                //每往后比较一位,将元素往后挪一位
                while (curindex >= 1 && curval < arr[curindex - 1])
                {
                    arr[curindex] = arr[curindex - 1];
                    curindex--;
                }

                arr[curindex] = curval;

            }
        }


        public static void ShellSort(int[] arr)
        {

            //希尔排序为直接插入排序的改进版,意在交换远端的元素,避免使得某些后置位小元素从当前位置推至第一个的情况
            //每次取一个步长,将步长分组内的数据插入排序,再逐步减少步长,达到使整个数组大致升序的样子
            //例如100长度的数组 第一次步长为50 ,0 和49 为一组,1和50为一组....第二次步长为25, 0 24 49 74 为一组
            //最后一次步长为1时,直接插入排序效率提高,不会出现当前元素推至第一个的情况

            for (int gap = arr.Length / 2; gap > 0; gap /= 2)
            {
                //每次组的数量为步长的长度
                for (int i = 0; i < gap; i++)
                {
                    //开始组内插入排序,组内每个数据的间隔为gap,插入排序第一个默认有序,所以j=i+gap(第二个数)
                    for (int j = i + gap; j < arr.Length; j += gap)
                    {
                        //原理参照插入排序
                        int curindex = j;
                        int curval = arr[j];

                        while (curindex >= i + gap && curval < arr[curindex - gap])
                        {
                            arr[curindex] = arr[curindex - gap];
                            curindex -= gap;
                        }

                        arr[curindex] = curval;
                    }
                }
            }
        }


        public static int Piovt(int[] arr, int left, int right)
        {
            //快速排序 1    以第一个元素为标准元素,在数组右侧找到比之小的移动到标准元素坑位,再从左侧找到比之大的,到右侧坑位,坑位在左右交互
            //              随着左右指针的距离越来越近直至重合,左侧都比标准元素小,右侧比之大         

            int l = left, r = right, piovtval = arr[l];     //默认第一个数为标准元素

            while (l < r)
            {
                while (l < r && arr[r] > piovtval)   //从右侧找到了大于标准数的,索引下标为r
                    r--;
                if (l < r)  //指针如果重合说明两侧已经达到要求,不用再为下轮作准备                              
                {
                    arr[l] = arr[r];                   //把此数扔到标准数坑位,注意此时不是把标准数和找到的数交换位置,只需要把找到的数扔到坑位即可
                    l++;                                //下次将从左侧找比标准数大的,此时的arr[l]是上面找到的比标准数小的数,所以l++跳过
                }


                while (l < r && arr[l] < piovtval)   //从左侧找到了大于标准数的,索引下标为r
                    l++;
                if (l < r)   ////指针如果重合说明两侧已经达到要求,不用再为下轮作准备 
                {
                    arr[r] = arr[l];                   //把此数扔到标准数坑位
                    r--;
                }


            }

            arr[l] = piovtval;   //最后指针重合时把标准数放入坑位

            return l;
        }

        public static void QuickSort(int[] arr, int l, int r)
        {
            int mid;
            if (l < r)
            {
                mid = Piovt(arr, l, r);
                QuickSort(arr, l, mid - 1);
                QuickSort(arr, mid + 1, r);
            }

        }

        public static void MergeMethod(int[] arr, int low, int mid, int high)
        {
            // 3根指针,i 第一个数据集合的起始位,  mid 结束位
            //          j 第二个数据集合的起始位,  high 结束位
            //          k 合并集合的插入位置
            int i = low;
            int j = mid + 1;
            int k = 0;

            int[] temp = new int[high - low + 1];  //合并集合的存放容器

            //指针直到某个集合超限,因为双个都为有序集合,arr[i]<arr[j]的话,i必为所有比较元素中的最小元素,反之亦然
            while (i <= mid && j <= high)
            {
                if (arr[i] < arr[j])
                {
                    temp[k++] = arr[i++];
                }
                else
                {
                    temp[k++] = arr[j++];
                }
            }

            //上个步骤结束时如果某个集合中还有数,必定为更大值,依此放入合并集合中即可
            while (i <= mid)
            {
                temp[k++] = arr[i++];
            }

            while (j <= high)
            {
                temp[k++] = arr[j++];
            }
            //将合并后的集合更新到原arr中
            for (i = low, k = 0; i <= high; i++, k++)
            {
                arr[i] = temp[k];
            }
        }

        public static void MergeSort(int[] arr, int low, int high, int depth)
        {
            //新加一个参数,depth用于看递归深度
            int mid;

            //递归的退出条件
            if (low < high)
            {

                //每次递归要做的事是取中间值,明确下个递归深度的参数条件,本次递归调用方法合并两个数据集合
                mid = (low + high) / 2;

                Console.WriteLine("左:" + low + "  中:" + mid + "  右:" + high + "  当前深度:" + depth);

                MergeSort(arr, low, mid, depth + 1);
                MergeSort(arr, mid + 1, high, depth + 1);
                MergeMethod(arr, low, mid, high);
            }

        }

        public static void SelectSort(int[] arr)
        {

            //选择排序 每次找到一个最小的数 按次序放在相应位置
            for (int i = 0; i < arr.Length; i++)
            {
                //标量 的值和小标
                int temp = arr[i];
                int index = i;

                //在i+1到结尾的元素中找比标量小的,找到了设置新的标量,记录下标
                //循环结束即找到本次循环的最小值和下标
                for (int j = i + 1; j < arr.Length; j++)
                {
                    if (arr[j] < temp)
                    {
                        temp = arr[j];
                        index = j;
                    }
                }

                //将本次找到的元素和原始标量交换位置
                temp = arr[i];
                arr[i] = arr[index];
                arr[index] = temp;
            }



        }

        public static void HeapAdjust(int[] arr, int parentIndex, int length)
        {

            //堆排序 利用数据结构转换,转为平衡二叉树
            //平衡二叉树的特点
            //父节点n    左节点2n+1    右节点2n+2    索引最大的第一个非叶子节点arr.length/2-1

            int temp = arr[parentIndex];   //父节点
            int child = parentIndex * 2 + 1;    //子节点

            while (child < length)    //至末尾节点
            {
                //如果右孩子节点大于左孩子节点则取右节点
                if (child + 1 < length && arr[child + 1] > arr[child])
                {
                    child = child + 1;
                }

                //如果父节点已经比双子节点大那么本次节点调整结束
                //这是建立在从第一个非叶子节点开始循环调用堆调整方法,所以底部的节点都符合父节点都比子节点大的规则
                if (arr[parentIndex] > arr[child])
                {
                    break;
                }
                else
                {
                    //子节点和父节点交换
                    arr[parentIndex] = arr[child];
                    arr[child] = temp;
                }

                //交换后 原父节点仍可能比下级节点小,所以重新赋值向下测探 直到while结束 本次堆单元调整结束
                parentIndex = child;
                child = parentIndex * 2 + 1;
                temp = arr[parentIndex];
            }

        }

        static void CreateHeapWithDesc(int[] arr)
        {
            //建立大根堆,从索引下标最大的非叶子节点开始,至头节点
            for (int i = arr.Length / 2 - 1; i >= 0; i--)
            {
                HeapAdjust(arr, i, arr.Length);
            }
        }

        public static void HeapSort(int[] arr)
        {
            //将数组转换成大根堆,如果要数组降序转成小根堆
            CreateHeapWithDesc(arr);

            int temp;

            //每次头节点最大值和最小值交换,重新整理大根堆,参与整理的长度排除掉在尾部的最大值
            //最后一次无需整理
            for (int i = arr.Length - 1; i > 0; i--)
            {
                temp = arr[0];
                arr[0] = arr[i];
                arr[i] = temp;

                HeapAdjust(arr, 0, i);  //无需i-1,循环头已减
            }

        }

        public static void radixSort(int[] list, int begin, int end, int digit)
        {
            int radix = 10;
            int i = 0, j = 0;
            int[] count = new int[radix];   //基数表 0,1,2..9
            int[] bucket = new int[end - begin + 1];

            //循环位数次数
            for (int d = 1; d <= digit; d++)
            {
                //清空
                for (i = 0; i < radix; i++)
                {
                    count[i] = 0;
                }

                //得到0-9基数表相应有几个元素
                for (i = begin; i <= end; i++)
                {
                    j = getDigit(list[i], d);
                    count[j]++;
                }

                //累加计数,得到某个基数槽位内的元素和桶的分配关系
                //例如    基数      原count表     后count表
                //          0           1              1
                //          1           0              1
                //          2           3              4
                //          3           0              4
                //基数2有3个计数, 加之前总共有4个计数,对应是1-4号位桶,2-4 3个桶属于
                //后count表的数字代表 基数N 应该分配的最后一个桶,分配了一个桶位同步
                //数组作桶,桶索引号-1
                for (i = 1; i < radix; i++)
                {
                    count[i] = count[i] + count[i - 1];
                }

                for (i = end; i >= begin; i--)
                {
                    j = getDigit(list[i], d);
                    bucket[count[j] - 1] = list[i];
                    count[j]--;
                }

                for (i = 0, j = 0; i < bucket.Length; i++, j++)
                {
                    list[i] = bucket[j];
                }
            }
        }

        public static int getDigit(int x, int d)
        {
            int[] a = { 1, 1, 10, 100 };

            return ((x / (int)Math.Pow(10, d - 1)) % 10);
        }
    }