常见的几种算法排序(C#)

总结下常见的几种排序及其实现,帮助自己加深记忆。

一、冒泡排序

1、原理: 通过依次比较相邻的元素,将较大(或较小)的元素交换到右侧,直到整个序列有序。

csharp 复制代码
 public static int[] BuddleSort(int[] arry)
    { 
        int n= arry.Length;
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n - 1 - i; j++)
            {
                if (arry[j] < arry[j + 1])
                { 
                    int temp = arry[j];
                    arry[j] = arry[j + 1];
                    arry[j + 1]= temp;
                }
            }
        }
        return arry;
    }

2、算法步骤:

冒泡排序的基本步骤:

(1)遍历数组: 从第一个元素开始,依次比较相邻的两个元素。

(2)比较相邻元素: 比较当前元素和下一个元素的大小关系。

(3)交换位置: 如果当前元素大于下一个元素(升序排序),则交换它们的位置,否则不做任何操作。

(4)遍历次数: 完成一轮遍历后,最大(或最小)的元素就会沉到数组的最后一个位置。

(5)重复步骤: 重复执行以上步骤,直到数组中的所有元素都已经排序完成。

3、举例:

冒泡排序的每个步骤涉及多次比较和可能的交换操作。这里是对数组 [65, 24, 12, 32, 4, 15] 进行冒泡排序时的每个步骤的输出:

初始数组:[65, 24, 12, 32, 4, 15]

第1次内循环执行后:[24, 12, 32, 4, 15, 65]

第2次内循环执行后:[12, 24, 4, 15, 32, 65]

第3次内循环执行后:[12, 4, 15, 24, 32, 65]

第4次内循环执行后:[4, 12, 15, 24, 32, 65]

第5次内循环执行后:[4, 12, 15, 24, 32, 65]

因此,经过选择排序算法的执行后,数组变为 [4, 12, 15, 24, 32, 65]。
4、时间复杂度

冒泡排序的时间复杂度为 O(n^2)。

二、选择排序

1、原理: 每次从未排序的部分选择最小(或最大)的元素,放到已排序部分的末尾,直到整个序列有序。

csharp 复制代码
public static int[] SelectSort(int[] arry)
    {
        int n = arry.Length;
        int temp;
        for (int i = 0; i < n - 1; i++)
        {
            int minIndex = i;
            for (int j = i+1; j < n - 1 ; j++)
            {
                if(arry[j]<arry[minIndex])
                    minIndex = j;                     
            }
            temp = arry[i];
            arry[i] = arry[minIndex];
            arry[minIndex] = temp;
        }

        return arry;
    }

2、算法步骤:

首先,找到数组中最小的元素,并将其与数组的第一个元素交换位置。

接下来,在剩余的未排序部分中找到最小的元素,并将其与数组的第二个元素交换位置。

以此类推,直到所有元素都被排序。

3、举例

比如我有个数组[65, 24, 12, 32, 4, 15],使用选择排序每次内循环执行后的输出内容如下:

初始状态:[65, 24, 12, 32, 4, 15]

第1次内循环执行后:[4, 24, 12, 32, 65, 15]

第2次内循环执行后:[4, 12, 24, 32, 65, 15]

第3次内循环执行后:[4, 12, 15, 32, 65, 24]

第4次内循环执行后:[4, 12, 15, 24, 65, 32]

第5次内循环执行后:[4, 12, 15, 24, 32, 65]

因此,经过选择排序算法的执行后,数组变为 [4, 12, 15, 24, 32, 65]。

4、时间复杂度

选择排序的时间复杂度为 O(n^2)。

三、插入排序

1、原理: 将数组分为已排序和未排序两部分,每次从未排序部分取出一个元素,插入到已排序部分的合适位置。

方法一:

csharp 复制代码
 public static int[] InsertSort(int[] arry)
    {
        int n=arry.Length;
        for (int i = 1; i < n; i++)
        {
            int key = arry[i];
            int j = i - 1;
            while (j >= 0 && key > arry[j]) 
            {
                arry[j+1]=arry[j];
                j--;
            }
            arry[j+ 1] = key;
        }
        return arry;
    }

插入排序方法二,我把方法一中内循环结束把key赋值的地方修改到内循环中了,感觉这种更好理解,类似于交换数据,但可能效率没有方法一好。

csharp 复制代码
 public static int[] InsertSort2(int[] arry)
    {
        int n = arry.Length;
        for (int i = 1; i < n; i++)
        {
            int key = arry[i];
            int j = i - 1;
            while (j >= 0 && key > arry[j])
            {
                arry[j+1] = arry[j];
                arry[j]= key;
                j--;
            }
        }
        return arry;
    }

2、算法步骤:

(1)从第一个元素开始,将该元素视为已排序部分。

(2)取出下一个元素,在已排序部分从后往前扫描。

(3)如果已排序部分的元素大于新元素,将该元素向右移动一个位置。

(4)重复步骤3,直到找到已排序部分的元素小于或等于新元素的位置。

(5)将新元素插入到找到的位置。

(6)重复步骤2到步骤5,直到所有元素都被插入到已排序部分。

3、举例

比如我有个数组[65, 24, 12, 32, 4, 15],使用插入排序每次内循环执行后的输出内容如下:

初始序列:[65, 24, 12, 32, 4, 15]

第一次循环后:[24, 65, 12, 32, 4, 15]

第二次循环后:[12, 24, 65, 32, 4, 15]

第三次循环后:[12, 24, 32, 65, 4, 15]

第四次循环后:[4, 12, 24, 32, 65, 15]

第五次循环后:[4, 12, 15, 24, 32, 65]

最终排序完成的序列为:[4, 12, 15, 24, 32, 65]

四、快速排序

1、原理

选择一个基准元素,将数组分成两部分,左边的部分小于基准,右边的部分大于基准,然后对左右两部分递归进行排序,直到整个数组有序。

csharp 复制代码
public static int[] QuickSort(int[] arry,int low, int high)
    {
        if (low < high)
        { 
            int pivot =Partition(arry,low,high);
            QuickSort(arry,low,pivot-1);
            QuickSort(arry, pivot+1, high);
        }
        return arry;
    }

 public static int Partition(int[] arry, int low, int high)
    {
        int pivot = arry[low]; // 将第一个元素作为基准元素

        while (low < high)
        {
            // 从右向左找到一个小于基准元素的值
            while (low < high && arry[high] >= pivot)
            {
                high--;
            }
            // 将这个小于基准元素的值放到左侧
            arry[low] = arry[high];

            // 从左向右找到一个大于基准元素的值
            while (low < high && arry[low] <= pivot)
            {
                low++;
            }
            // 将这个大于基准元素的值放到右侧
            arry[high] = arry[low];
        }

        // 将基准元素放到正确的位置上
        arry[low] = pivot;

        // 返回基准元素的索引
        return low;
    }

2、算法步骤:

(1)选择基准元素 : 从数组中选择一个基准元素,通常是数组的第一个元素、最后一个元素或者中间的元素。

(2)分区操作 : 将数组中的元素按照基准元素的大小分成两部分,小于基准元素的放在基准元素的左边,大于基准元素的放在右边。分区操作完成后,基准元素的位置就确定了。

Partition函数中的While循环解释如下:选择arry[0]作为基准元素。

  • 双指针移动: 使用两个指针分别指向数组的起始位置和结束位置。左指针从左向右移动,直到找到一个大于或等于基准元素的值;右指针从右向左移动,直到找到一个小于或等于基准元素的值。
  • 交换元素: 一旦找到了左侧大于基准元素和右侧小于基准元素的值对,就交换它们的位置。这样,就保证了左侧的元素都小于等于基准元素,右侧的元素都大于等于基准元素。
  • 重复操作: 继续移动双指针,直到它们相遇为止。此时,所有小于基准元素的值都在基准元素的左侧,所有大于基准元素的值都在基准元素的右侧。
  • 基准元素归位: 将基准元素放置在正确的位置上,一般是与相遇点进行交换。
    (3)递归排序 : 递归地对基准元素左右两边的子数组进行快速排序,直到子数组的大小为 0 或 1,即已经有序。
    (4)合并结果 : 当所有的子数组都有序时,整个数组也就有序了。
    说明:网上有很多视频可以很好的解释这个算法的排序规则,可以在B站搜索看下。

3、时间复杂度

快速排序的平均时间复杂度是O(nlogn),但是在实际排序中,时间复杂度和基准元素(枢轴)的选择有关。如果枢轴选取不好,那么快速排序有可能就会退化为冒泡排序,时间复杂度为O(n*n)。

相关推荐
AI街潜水的八角6 分钟前
基于C++的决策树C4.5机器学习算法(不调包)
c++·算法·决策树·机器学习
白榆maple31 分钟前
(蓝桥杯C/C++)——基础算法(下)
算法
JSU_曾是此间年少35 分钟前
数据结构——线性表与链表
数据结构·c++·算法
此生只爱蛋1 小时前
【手撕排序2】快速排序
c语言·c++·算法·排序算法
咕咕吖2 小时前
对称二叉树(力扣101)
算法·leetcode·职场和发展
Envyᥫᩣ2 小时前
C#语言:从入门到精通
开发语言·c#
九圣残炎3 小时前
【从零开始的LeetCode-算法】1456. 定长子串中元音的最大数目
java·算法·leetcode
lulu_gh_yu3 小时前
数据结构之排序补充
c语言·开发语言·数据结构·c++·学习·算法·排序算法
丫头,冲鸭!!!3 小时前
B树(B-Tree)和B+树(B+ Tree)
笔记·算法
Re.不晚3 小时前
Java入门15——抽象类
java·开发语言·学习·算法·intellij-idea