C# 交换排序 | 冒泡排序 | 快速排序 的原理和代码实现

题外话: 加油!!


1.什么是交换排序?

  • 回想一下初中时期,上学第一天,班主任让所有的同学按高矮站成2排,男生1排,女生1排;
  • 如果身高差大还好,对于身高差不大的同学来说,很容易排错位置,全班只有A和B同学的位置错了
  • 此时班主任会过来说:“A,你和B换一下位置”
  • 此刻,整个班级的队伍,遵循从高到矮的顺序了。
  • 过程中,两个同学互相交换位置,不会影响到第三个同学的操作,就是交换排序。

2.冒泡排序

  • 什么是冒泡排序?
    • 相邻两个元素比较大小,并根据大小关系互相交换位置;
    • 整个过程像一个泡泡,逐渐浮向水面一样。
  • 代码实现(普通版本)
/// <summary>
/// 普通的冒泡排序
/// </summary>
/// <param name="pArray">普通一数组</param>
static public void NBubbleSort(int[] pArray)
{
    
    
    int temp;
    //本层循环只是确保循环够次数,i本身不做元素索引用
    for (int i = 1; i < pArray.Length; i++)
    {
    
    
        //本层循环每次都会减少上限;
        //因为每次循环结束后,最后n个元素,一定是最大的,不需要再遍历到了。
        for (int j = 0; j < pArray.Length - i; j++)
        {
    
    
            if (pArray[j] > pArray[j + 1])
            {
    
    
                temp = pArray[j];
                pArray[j] = pArray[j + 1];
                pArray[j + 1] = temp;
            }
        }
    }
}

普通版本:
冒泡排序有一个特点,即在“浮出”一个又一个相对较大的元素时,也会一定程度上理顺其他元素的大小关系
优化思路: 如果在某一次“浮出”元素的过程中,没有任何一个元素发生交换,就说明整个队列的排序已经完成,可以结束循环了

  • 优化版代码
/// <summary>
/// 优化后的冒泡排序
/// </summary>
/// <param name="pArray">普通一数组</param>
static public void BBubbleSort(int[] pArray)
{
    
    
    int temp;
    bool flag;
    //本层循环只是确保循环够次数,i本身不做元素索引用
    for (int i = 1; i < pArray.Length; i++)
    {
    
    
        flag = false;
        //本层循环每次都会减少上限;
        //因为每次循环结束后,最后n个元素,一定是最大的,不需要再遍历到了。
        for (int j = 0; j < pArray.Length - i; j++)
        {
    
    
            if (pArray[j] > pArray[j + 1])
            {
    
    
                flag= true;
                temp = pArray[j];
                pArray[j] = pArray[j + 1];
                pArray[j + 1] = temp;
            }
        }
        if (!flag)
        {
    
    
            break;
        }
    }
}

  • 时间复杂度:
    • 最好的情况:O(n)
    • 最差的情况:O(n^2)
    • 平均:O(n^2)
  • 空间复杂度:
    • O(1)
  • 算法稳定性:
    • 稳定

3.快速排序

  • 什么是快速排序?
    • 从数据中随便拿出一个元素x,其他所有元素与x做比较;
    • 比x小的,统统放到x左边,比x大的,放到x右边;
    • 由x又分割了两个数据表,再对左右两边做步骤1、2;
    • 递归,完成整个数据表的排序。
  • 代码实现
/// <summary>
/// 快速排序
/// </summary>
/// <param name="pArray">索引从1开始有效的数组</param>
/// <param name="start"></param>
/// <param name="end"></param>
static public void QKSort(int[] pArray, int low, int high)
{
    
    
    if (low < high)
    {
    
    
        //确定中心点位置
        int pivot = Partition(pArray, low, high);
        //对左右子集递归
        QKSort(pArray, low, pivot - 1);
        QKSort(pArray, pivot+1, high);
    }
}

static public int Partition(int[] pArray, int low, int high)
{
    
    
    //设置哨兵元素
    pArray[0] = pArray[low];
    //双指针法
    while (low < high)
    {
    
    
        //从后向前遍历,寻找小于中心点的元素,并给到low
        while (high > low && pArray[high] >= pArray[0])
            high--;
        pArray[low] = pArray[high];
        //从前向后遍历,寻找大于中心点的元素,给到high
        while (low < high && pArray[low] < pArray[0])
            low++;
        pArray[high] = pArray[low];
    }
    //复位哨兵元素
    pArray[low] = pArray[0];
    return low;
}

  • 时间复杂度:
    • 最好的情况:O(nlogn)
    • 最坏的情况:O(n^2)
    • 平均:O(nlogn)
  • 空间复杂度:
    • 最好:O(logn)
    • 最坏:O(n)
  • 算法稳定性:
    • 不稳定。


结束语: 加油!!

猜你喜欢

转载自blog.csdn.net/Liyager/article/details/129207740
今日推荐