算法
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); } }