文章目录

  • 1.冒泡排序
  • 2.插入排序
  • 3.选择排序
  • 4.快速排序
  • 5.希尔排序
  • 6.堆排序
  • 7.归并排序
  • 8.计数排序
  • 9.桶排序
  • 10.基数排序
  • 参考

1.冒泡排序


口诀:
外层循环 n-1;内层循环 n-1-i;两两比较做互换;

以下代码在控制台操作,输入数字以‘逗号’隔开

     Console.WriteLine("请输入一组数字:");string str = Console.ReadLine();string[] num = str.Split(','); // 获取到每个数int[] numlist=new int[num.Length];for (int i = 0; i < num.Length; i++){numlist[i] = int.Parse(num[i]); // 将每个数存储到numlist数组中}for (int i = 0; i < numlist.Length-1; i++){for (int j = 0; j < numlist.Length-1-i; j++){if (numlist[j]<numlist[j+1])  //此数小于后一个数,两个数交换,从大到小排列{int temp = numlist[j];numlist[j] = numlist[j + 1];numlist[j + 1] = temp;}}}Console.WriteLine("排序结果为:");for (int i = 0; i < numlist.Length; i++){Console.Write(numlist[i]+",");}Console.ReadLine();

程序执行结果:

2.插入排序

     int[] numlist = { 3, 6, 88, 35, 1, 45, 7 };Console.WriteLine("排列前一组数字:");for (int i = 0; i < numlist.Length; i++){Console.Write(" " + numlist[i]);}for (int i = 1; i < numlist.Length; i++){int temp = numlist[i];for (int j = i-1; j >=0; j--) // 遍历排在此数前面的数{if (numlist[j]>temp) // 如果前面的一个数大于此数,交换位置,知道前面数比此数小为止{numlist[j + 1] = numlist[j];numlist[j] = temp;}else{break;}}}Console.WriteLine("\r\n"+"排序结果为:");for (int i = 0; i < numlist.Length; i++){Console.Write(" "+numlist[i]);}Console.ReadLine();

程序执行结果:

3.选择排序

         int[] numlist = { 33, 2, 6, 89, 11 };Console.WriteLine("排列前一组数字:");for (int i = 0; i < numlist.Length; i++){Console.Write(" "+numlist[i]);}//总共要进行n-1轮比较for (int i = 0; i < numlist.Length-1; i++){int min =i;//每轮需要比较的次数n-ifor (int j = i+1; j < numlist.Length; j++){if (numlist[min]>numlist[j]) // 当此数大于后一个数{// 记录目前能找到的最小值元素的下标min = j;}}int temp = numlist[i];numlist[i] = numlist[min];numlist[min] = temp;}Console.WriteLine("\r\n"+"排序后结果为:");for (int i = 0; i < numlist.Length; i++){Console.Write(" "+numlist[i]);}Console.ReadLine();

程序执行结果:

4.快速排序


快速排序使用分治法(Divide and conquer)策略来把一个序列(list)分为两个子序列(sub-lists)。

步骤为:

  1. 从数列中挑出一个元素,称为 “基准”(pivot),
  2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆放在基准的后面(相同的数可以到任一边)。在这个分割结束之后,该基准就处于数列的中间位置。这个称为分割(partition)操作。
  3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个演算法总会结束,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace 快速排序    //***对相同元素, 不稳定的排序算法***
{//相对来说,快速排序数值越大速度越快 。  快速排序是所有排序里面最快的class Program{static void Main(string[] args){int[] arr = { 15, 22, 35, 9, 16, 33, 15, 23, 68, 1, 33, 25, 14 }; //待排序数组QuickSort(arr, 0, arr.Length - 1);  //调用快速排序函数。传值(要排序数组,基准值位置,数组长度)//控制台遍历输出Console.WriteLine("排序后的数列:");foreach (int item in arr)Console.WriteLine(item);}private static void QuickSort(int[] arr, int begin, int end){if (begin >= end) return;   //两个指针重合就返回,结束调用int pivotIndex = QuickSort_Once(arr, begin, end);  //会得到一个基准值下标QuickSort(arr, begin, pivotIndex - 1);  //对基准的左端进行排序  递归QuickSort(arr, pivotIndex + 1, end);   //对基准的右端进行排序  递归}private static int QuickSort_Once(int[] arr, int begin, int end){int pivot = arr[begin];   //将首元素作为基准int i = begin;int j = end;while (i < j){//从右到左,寻找第一个小于基准pivot的元素while (arr[j] >= pivot && i < j) j--; //指针向前移arr[i] = arr[j];  //执行到此,j已指向从右端起第一个小于基准pivot的元素,执行替换//从左到右,寻找首个大于基准pivot的元素while (arr[i] <= pivot && i < j) i++; //指针向后移arr[j] = arr[i];  //执行到此,i已指向从左端起首个大于基准pivot的元素,执行替换}//退出while循环,执行至此,必定是 i= j的情况(最后两个指针会碰头)//i(或j)所指向的既是基准位置,定位该趟的基准并将该基准位置返回arr[i] = pivot;return i;}}
}

5.希尔排序

插入排序的升级

 static void Main(string[] args){int[] numlist = { 33, 6, 89, 34, 63, 2, 7 };Console.WriteLine("排序前数组:");for (int i = 0; i < numlist.Length; i++){Console.Write(" "+numlist[i]);}// 将每组间隔为h的分组进行排序,刚开始h=数组长度的一半for (int h = numlist.Length/2; h >0; h/=2){//对每组进行插入排序for (int i = h; i < numlist.Length; i++){// 将numlist[i]插入到所在分组的正确位置上insertI(numlist, h, i);}}Console.WriteLine("\r\n排序后结果:");for (int i = 0; i < numlist.Length; i++){Console.Write(" "+numlist[i]);}Console.ReadLine();}// 插入排序的方法private static void insertI(int[] arr,int h, int i){int temp = arr[i];int k;for ( k= i-h; k>=0 && temp<arr[k]; k-=h){arr[k + h] = arr[k];}arr[k + h] = temp;}

程序执行结果:

6.堆排序

堆排序首先是构建最大堆或最小堆。最大堆是用来正序排序,最小堆是用来倒序排序。

最大堆是指二叉树中每个结点的值都比其左右子结点的值大。同理最小堆是指二叉树中每个结点的值都比其左右子结点的值小。

对于二叉树不了解,在这里可以只有一个印象就可以。二叉树就是一个结点最多只有两个左右子结点。至于什么是完全二叉树,这里就不在过多解释,以后有机会写数据结构的时候,会着重解释,但是有一点要知道,数列从上往下,从左往右,按照只有一个根结点,且每个结点有两个子结点这样构建二叉树,那么他就是一颗完全二叉树。

下面我用一张图,来表示上面的概念,并加深印象。

完全二叉树:
可以发现其实每个结点的下标和其左右子结点的下标是有一定关系的,即结点下标为n,左子结点下标为:2n+1,右子结点的下标为:2n+2。

最大堆:

上图为第一次构建最大堆的结果

可以看出因为根结点要比左右子结点数值大,而且其左右子结点要比其孙子结点数值大,以此类推,此时的根结点即为数列的最大值。

那么我们如何把一个无序构建成一个最大堆。首先看最大堆的最大特点就是:父结点的数值一定比左右结点数值大,我们依照这个规则不断的调整结点使其满足条件即可。

再仔细观察堆我们发现,由一半以上的结点是没有孩子结点的,这部分结点就称为叶子结点,那么也就是说,这部分结点是不需要向下调整的。我们选择从(length/2)-1的下标开始依次从0下标的方向进行调整。每次调整之后,调整的结点还要继续比较他的子结点看看是否仍然满足最大堆特点,一直调整到叶子结点。这样做的目的就是使数列的大值向上浮,小值向下沉。直到下标0结点(根结点)调整完成,此时就是一个最大堆。

此时根结点是一个最大值,我们把最大值排在无序数列最后,即把最大值与队尾交换位置。此时我们发现除了根结点,其他结点仍然是符合最大堆特点的(注意,从这个位置往后,我们讲述的情况都是排除了最后一个数,因为他已经排好了位置)。这时我们只用调整根结点就可以了,调整之后,就得到了数列的第二个最大值。依次调整,直到数列排好即可。

         public static void HeapSort(int[] arr){int length = arr.Length;if (length < 2){return;}//初次构建最大堆。从后往前第一个非叶子结点开始调整。for (int i = length / 2 - 1; i >= 0; i--){AdjustHeap(arr, i, length);}//将堆顶最大值移动到数组末端,再次从根结点开始调整构建最大堆。//注意长度要-1,因为队尾的元素已经是排好序的。for (int i = 0; i < length -1; i++){Swap(arr, 0, length - 1 - i);AdjustHeap(arr, 0, length - i - 1);}}/// <summary>/// 构建最大堆/// </summary>/// <param name="arr">需要构建的数组</param>/// <param name="index">需要开始调整的结点下标</param>/// <param name="length">需要构建的数组长度</param>private static void AdjustHeap(int[] arr, int index, int length){int leftIndex = index * 2 + 1;              //左孩子结点下标int rightIndex = index * 2 + 2;             //右孩子结点下标//如果左孩子下标大于等于数组长,则说明其为叶子结点,不需要调整if (leftIndex >= length)                    {return;}//找到左右结点最大值的下标int maxIndex = leftIndex;if (rightIndex < length){if (arr[leftIndex] < arr[rightIndex]){maxIndex = rightIndex;}}//如果孩子结点的值要大于父结点,则交换两个结点的值,//并且从交换后的子结点继续向下调整if (arr[maxIndex] > arr[index]){Swap(arr, maxIndex, index);AdjustHeap(arr, maxIndex, length);}}private static void Swap(int[] arr, int index1, int index2){int length = arr.Length;if (index1 >= length || index2 >= length){return;}int temp = arr[index1];arr[index1] = arr[index2];arr[index2] = temp;}

7.归并排序

归并排序是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。 将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。 若将两个有序表合并成一个有序表,称为二路归并。

作为一种典型的分而治之思想的算法应用,归并排序的实现由两种方法:

  • 自上而下的递归(所有递归的方法都可以用迭代重写,所以就有了第 2 种方法);
  • 自下而上的迭代;

算法步骤

  1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
  2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置;
  3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;
  4. 重复步骤 3 直到某一指针达到序列尾;
  5. 将另一序列剩下的所有元素直接复制到合并序列尾。
public static void MergeSort(int[] array1){int low = 0, heigh = array1.Length - 1;Mergesort(array1, low,  heigh);}private static void  Mergesort(int[] array1,int low,int heigh){if (low < heigh){int mid = (low+heigh) / 2;Mergesort(array1,low,mid);Mergesort(array1, mid + 1, heigh);BinaryMerge(array1,low,mid,heigh);}}public static void BinaryMerge(int[] array, int low,int mid,int height){int[] temparray = new int[array.Length];int left, right,index;//复制数组for (index = low; index <= height; index++){temparray[index] = array[index];}//二路归并for ( index= left = low,right=mid+1;left<=mid&& right <= height && index <=height; index++){if (temparray[left] <= temparray[right]) { array[index] = temparray[left++]; }else { array[index] = temparray[right++]; }}//检查那个部分没拷贝完成,将temparray剩余的部分拷贝到array数组中while (left<=mid) array[index++] = temparray[left++];while(right<=height) array[index++]=temparray[right++];}

8.计数排序

计数排序是一种适合于最大值和最小值的差值不是不是很大的排序。例如 temp[i] = m, 表示元素 i 一共出现了 m 次

       static void CountSort(int[] arr){//1.得到数列的最大值 和 最小值int Max = arr[0];int Min = arr[0];for (int i = 1; i < arr.Length; i++){if (arr[i] > Max) Max = arr[i];if (arr[i] < Min) Min = arr[i];}//2.根据数列最大值确定统计数组的长度int[] newArr = new int[Max -Min+ 1];//3.遍历数列,填充统计数组 记得加上 偏移量Minfor (int i = 0; i < arr.Length; i++){newArr[arr[i]-Min]++;}//4.遍历统计数组,输出结果 记得加上 偏移量Minint Index = 0;for (int i = 0; i < newArr.Length; i++){for (int j = 0; j < newArr[i]; j++){arr[Index++] = i+Min;}}}

9.桶排序

桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。桶排序 (Bucket sort)的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)。

算法步骤

  1. 设置一个定量的数组当作空桶;
  2. 遍历输入数据,并且把数据一个一个放到对应的桶里去;
  3. 对每个不是空的桶进行排序;
  4. 从不是空的桶里把排好序的数据拼接起来。

/// <summary>
/// 桶排序
/// </summary>
public class Program {public static void Main(string[] args) {double[] array = { 0.43, 0.69, 0.11, 0.72, 0.28, 0.21, 0.56, 0.80, 0.48, 0.94, 0.32, 0.08 };BucketSort(array, 10);ShowSord(array);Console.ReadKey();}private static void ShowSord(double[] array) {foreach (var num in array) {Console.Write($"{num} ");}Console.WriteLine();}public static void BucketSort(double[] array, int bucketNum) {//创建bucket时,在二维中增加一组标识位,其中bucket[x, 0]表示这一维所包含的数字的个数//通过这样的技巧可以少写很多代码double[,] bucket = new double[bucketNum, array.Length + 1];foreach (var num in array) {int bit = (int)(10 * num);bucket[bit, (int)++bucket[bit, 0]] = num;}//为桶里的每一行使用插入排序for (int j = 0; j < bucketNum; j++) {//为桶里的行创建新的数组后使用插入排序double[] insertion = new double[(int)bucket[j, 0]];for (int k = 0; k < insertion.Length; k++) {insertion[k] = bucket[j, k + 1];}//插入排序StraightInsertionSort(insertion);//把排好序的结果回写到桶里for (int k = 0; k < insertion.Length; k++) {bucket[j, k + 1] = insertion[k];}}//将所有桶里的数据回写到原数组中for (int count = 0, j = 0; j < bucketNum; j++) {for (int k = 1; k <= bucket[j, 0]; k++) {array[count++] = bucket[j, k];}}}public static void StraightInsertionSort(double[] array) {//插入排序for (int i = 1; i < array.Length; i++) {double sentinel = array[i];int j = i - 1;while (j >= 0 && sentinel < array[j]) {array[j + 1] = array[j];j--;}array[j + 1] = sentinel;}}}

10.基数排序

基数排序也是非比较的排序算法,对每一位进行排序,从最低位开始排序,复杂度为O(kn),为数组长度,k为数组中的数的最大的位数;

基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。基数排序基于分别排序,分别收集,所以是稳定的。

基数相对于其他排序,算法逻辑和代码都相对简单。
代码方面,也都是和另外两个排序的顺序一致。
与另外两个非比较排序不同的是:
计数排序和桶排序是基于数组索引来的,所以只能排序整数
但是基于数的计数而定,所以在改造后,理论上是也可以排序非整数

算法步骤

  1. 求最值,取得数组中的最大数,并取得位数;
  2. 初新组,此处新组是指新桶,桶大小为10(因为基数只有0-10);
  3. 正填充,将对应基数的数字放到对应的桶中
  4. 将桶中的数据反填充到array数组中

注:正反填充需要进行循环,循环次数为步骤一的位数

        public int[] RadixSort2(int[] array){//求最(大)值int max = array[0];foreach (var item in array){max = item > max ? item : max;}int maxDigit = 0;while(max!=0){max /= 10;maxDigit++;}//初新桶var bucket = new List<List<int>>();for (int i = 0; i < 10; i++){bucket.Add(new List<int>());}for (int i = 0; i < maxDigit; i++){//正填充int div = (int)Math.Pow(10, (i + 1));foreach (var item in array){//获取基数int radix = (item % div) / (div / 10);bucket[radix].Add(item);}//反填充(//反填充要注意顺序)int index = 0;foreach (var item in bucket){foreach (var it in item){array[index++] = it;                        }item.Clear();//清除数据}                }return array;}


参考

C#十大排序算法
C#快速排序详解
排序算法2|简单选择排序与堆排序(C#)
【C# 排序】归并排序 merge sort
C#计数排序
【愚公系列】2021年11月 C#版 数据结构与算法解析(桶排序)
C# 算法之基数排序排序(非比较排序之三)

【C#】十大排序算法(动图演示+代码实现)相关推荐

  1. 数据结构各大排序整理+动图演示+代码实现(Java)

    注: 以下部分动图来源于:http://www.west999.com/info/html/chengxusheji/Javajishu/20190217/4612849.html 以下两幅图来自马士 ...

  2. 算法 - 十大经典排序算法(动图演示)

    [TOC] 算法 - 十大经典排序算法(动图演示) ​ 在计算机科学与数学中,一个排序算法(英语:Sorting algorithm)是一种能将一串资料依照特定排序方式进行排列的一种算法.最常用到的排 ...

  3. 十大排序算法 导图总结

    以下为我们经常用到的十大典型排序算法导图,很多设计以及优化的思想值得去参考学习 因为代码较多,所以都添加到对应的实现注释中了,相关代码可以从Mind-mapping获取xmind源文件 参考文档: 基 ...

  4. 十大排序算法(C语言代码)

    排序算法介绍: 排序是计算机程序设计过程中的重要操作,它的功能是将一个数据元素的任意序列,重新排列成一个按关键字有序的序列. 它之所以重要是因为查找操作非常重要,而有序的顺序表可以采用效率较高二分查找 ...

  5. JS 实现十大排序算法

    文章目录 前言 零.十大排序 一.冒泡排序(bubbleSort) 二.选择排序(selectionSort) 三.插入排序(insertSort) 四.希尔排序(shellSort) 五.归并排序( ...

  6. 十大排序算法:冒泡排序、选择排序、插入排序、希尔排序、归并排序、快速排序、堆排序、计数排序、桶排序、基数排序

    冒泡排序.选择排序.插入排序.希尔排序.归并排序.快速排序.堆排序.计数排序.桶排序.基数排序的动图与源代码. 目录 关于时间复杂度 冒泡排序 选择排序 插入排序 希尔排序 归并排序 快速排序 堆排序 ...

  7. 十大排序算法JS实现以及复杂度分析

    文章目录 十大排序算法概述 应用场景 代码实现 一.冒泡排序 二.选择排序 三.插入排序 四.希尔排序 五.归并排序 六.快速排序 七.堆排序 八.计数排序 九.桶排序 十.基数排序 十大排序算法概述 ...

  8. c语言代码先来先服务算法_C语言十大经典排序算法(动态演示+代码,值得收藏)...

    以前也零零碎碎发过一些排序算法,但排版都不太好,又重新整理一次,排序算法是数据结构的重要部分,系统地学习很有必要. 时间.空间复杂度比较 排序算法 平均时间复杂度 最差时间复杂度 空间复杂度 数据对象 ...

  9. DSt:数据结构的简介、最强学习路线(逻辑结构【数组-链表-栈和队列/树-图-哈希】、物理结构、数据运算【十大排序/四大查找-图三大搜索-树三大遍历】、高级算法【贪心/分治/动态规划】之详细攻略

    DSt:数据结构的简介.最强学习路线(逻辑结构[数组-链表-栈和队列/树-图-哈希].物理结构[元素/关系].数据运算[十大排序/四大查找-图三大搜索-树三大遍历].高级算法[贪心/分治/动态规划]) ...

最新文章

  1. 构造 HDOJ 5400 Arithmetic Sequence
  2. c# load xml 中文报错
  3. 【渝粤教育】电大中专电商运营实操 (25)作业 题库
  4. winforms中限定上传文件类型
  5. 图上上传页面设计_无线端页面设计“三大雷区”
  6. 锋神教我数据库,吴大哥教我写文档——其一
  7. 一组经典测试思想观点
  8. Tomcat可以在eclipse里启动,可是不能訪问首页的问题
  9. 软件工程专业学python_笨办法学Python(0)
  10. al32utf8的日期格式_五分钟学会Oracle数据库字符集
  11. Android UI学习之---Button
  12. ps里面的css,PS图层样式详解(上)
  13. CAJ文件怎么转换成Word文档
  14. Win10系统程序图标上的盾牌怎么去除?
  15. origin里绘制横纵坐标都不一致的两条曲线
  16. 垃圾图像分类 ResNet34 python
  17. mysql数据库巡检工作内容_数据库巡检
  18. 数据治理系统解决方案浅析
  19. 条码用什么条码标签打印软件可以达到A级
  20. 如何设置电脑颜色保护眼睛

热门文章

  1. 网工知识角|华为网络工程师,华为、华三、思科设备三层交换机如何使用三层接口?命令敲起来
  2. Android探索之旅(第二十九篇)QRCode终极秘术之三码合一(微信,QQ,支付宝)
  3. PL/SQL 记录与集合
  4. 怎样设置Win7共享
  5. 第11章 大数据技术与实践
  6. 发现了更好的 MSIL编辑器,看来我的MSIL STUDIO来晚了~~
  7. python 窗口置顶_PyQt5 窗口置顶
  8. 放大电路的分析方法(以共射放大电路为例、交流通路、直流通路、三极管等效电路及其如何等效的)
  9. OidProducer保姆级铺码教程(教你如何自制点读书)
  10. 直播系统开发定制功能介绍