排序算法 C#

默认为从小到大排序

1. 冒泡排序

每一轮,相邻两个比较,一轮结束,最大值排在末尾

int n = arr.Length;
for (int i = 0; i < n; i++)
{
    for (int j = 0; j < n - i - 1; j++) 
    {
        if (arr[j] > arr[j + 1])
        {
            Swap(j, j + 1);
        }
    }
}

优化:

  1. 有序边界,确定最后有序边界 swapPos 边界后面是排序完成的
  2. 鸡尾酒排序,正向->反向->正向
int n = arr.Length;
int swapPos = 0;
int left = 0;
int right = n - 1;
while (left < right)
{
    for (int i = left; i < right; i++)
    {
        if (arr[i] > arr[i + 1])
        {
            swapPos = i;
            Swap(i, i + 1);
        }
    }
    right = swapPos;
    for (int i = right; i > left; i--)
    {
        if (arr[i] < arr[i - 1])
        {
            swapPos = i;
            Swap(i, i - 1);
        }
    }
    left = swapPos;
}

2. 选择排序

每一轮找出最小值坐标,和当前位置更换

int n = arr.Length;
int min;
for (int i = 0; i < n - 1; i++) 
{
    min = i;
    for (int j = i + 1; j < n; j++) 
    {
        if (arr[j] < arr[min])
            min = j;
    }
    if (min != i)
        Swap(min, i);
}

优化

  1. 一次遍历找出一个最大值和一个最小值
int n = arr.Length;
int min,max;
for (int left = 0, right = n - 1; left < right; left++, right--)
{
    min = left;
    max = right;
    for (int j = left; j <= right; j++) 
    {
        if (arr[j] < arr[min])
            min = j;
        if (arr[j] > arr[max])
            max = j;
    }
    Swap(min, left);
    if (left == max)
    {
        max = min;
    }
    Swap(right,max);
}

3. 插入排序

每次循环向前遍历,将大于自己的向后移,最后插入进去

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

4. 希尔排序

一种插入排序,比较相距一定间隔的元素,各趟比较所用的距离随着算法的进行而减小,直到只比较相邻元素的最后一趟排序为止

int n = arr.Length;
int temp, j;
for (int h = n / 2; h > 0; h /= 2)
{
    for (int i = h; i < n; i++)
    {
        for (j = i - h, temp = arr[i]; j >= 0 && arr[j] > temp; j -= h)
        {
            arr[j + h] = arr[j];
        }
        arr[j + h] = temp;
    }
}

5. 归并排序

分治思想,将已有序的子序列合并,得到完全有序的序列。

递归法

private int[] temp;
private void MergeSort()
{
    temp = new int[arr.Length];
    Merge(0, arr.Length - 1);
}
private void Merge(int l, int r)
{
    if (l >= r)
        return;
    int mid = (r + l) / 2;
    Merge(l, mid);
    Merge(mid + 1, r);
    Merge(l, mid, r);
}
private void Merge(int l, int mid, int r)
{
    int i = l;
    int j = mid + 1;
    int index = l;
    while (i <= mid && j <= r) 
    {
        if (arr[i] <= arr[j])
        {
            temp[index++] = arr[i];
            i++;
        }
        else
        {
            temp[index++] = arr[j];
            j++;
        }
    }
    while (i <= mid) 
        temp[index++] = arr[i++];
    while (j <= r) 
        temp[index++] = arr[j++];
    for (int k = l; k <= r; k++)
        arr[k] = temp[k];
}

非递归法

int n = arr.Length;
int[] temp = new int[n];
int gap = 1;
int lstart, lend, rstart, rend, index;
while (gap < n)
{
    for (int i = 0; i < n; i += gap * 2)
    {
        lstart = index = i;
        lend = Math.Min(i + gap - 1, n - 1);
        rstart = lend + 1;
        rend = Math.Min(i + 2 * gap - 1, n - 1);
        if (lstart >= rend)
            continue;
        while (lstart <= lend && rstart <= rend)
        {
            if (arr[lstart] <= arr[rstart])
                temp[index++] = arr[lstart++];
            else
                temp[index++] = arr[rstart++];
        }
        while (lstart <= lend)
            temp[index++] = arr[lstart++];
        while (rstart <= rend)
            temp[index++] = arr[rstart++];
        for (int j = i; j <= rend; j++)
            arr[j] = temp[j];
    }
    gap *= 2;
}

6. 快速排序

  1. 选择基准:在待排序列中,按照某种方式挑出一个元素,作为“基准”(pivot);
  2. 分割操作:以该基准在序列中的实际位置,把序列分成两个子序列。此时,在基准左边的元素都比该基准小,在基准右边的元素都比基准大;
  3. 递归地对两个序列进行快速排序,直到序列为空或者只有一个元素。

优化:

  1. 当数量较少时,使用插入排序,性能更好
  2. 选择基准
    • 选择最左边的值
    • 取最左边,最右边,正中间的值,找出中间值,当做基准移到最左边
    • 随机取一个位置,当做基准移到最左边
private const int MAX_INSERT = 10;
private void Quick(int low, int high)
{
    if (low >= high)
        return;
    if (high - low <= MAX_INSERT)
    {
        Insert(low, high);
        return;
    }
    int point = SelectPoint(low, high);
    int l = low + 1, r = high;
    while (l <= r)
    {
        while (l <= r && arr[l] < point) l++;
        while (l <= r && arr[r] >= point) r--;
        if (l >= r) break;
        Swap(l++, r--);
    }
    Swap(low, r);
    Quick(low, r - 1);
    Quick(r + 1, high);
}
private void Insert(int low, int high)
{
    int temp;
    int j;
    for (int i = low + 1; i <= high; i++)
    {
        j = i - 1;
        temp = arr[i];
        for (; j >= low && arr[j] > temp; j--) 
        {
            arr[j + 1] = arr[j];
        }
        arr[j + 1] = temp;
    }
}
private int SelectPoint(int low,int high)
{
    /// 取最左边的值
    return arr[low];
    /// 随机取基准
    int random = new Random().Next(low, high + 1);
    Swap(low,random);
    return arr[low];
    /// 取中间值
    int mid = (high - low) / 2 + low;
    if (arr[mid] > arr[high])
        Swap(mid, high);
    if (arr[low] > arr[high])
        Swap(low, high);
    if (arr[mid] > arr[low])
        Swap(low, mid);
    return arr[low];
}

7. 堆排序

  1. 构建最大堆
  2. 将最大值和末尾替换,然后将剩余的调整为最大堆
  3. 重复第2步,直到只剩1个数,排序成功
protected override void Sort()
{
    int n = arr.Length;
    // 构建最大堆
    int i = n / 2 - 1;
    for (; i >= 0; i--) 
        DownAdjust(i, n);
    i = n - 1;
    for (; i >= 1; i--)
    {
        Swap(0, i);
        DownAdjust(0, i);
    }
}
private void DownAdjust(int parent, int n)
{
    int temp = arr[parent];
    int child = 2 * parent + 1;
    while (child < n)
    {
        // 判断左右子节点 取节点值最大的节点
        if (child + 1 < n && arr[child] < arr[child + 1])
            child++;
        if (arr[child] <= temp)
            break;
        arr[parent] = arr[child];
        parent = child;
        child = 2 * parent + 1;
    }
    arr[parent] = temp;
}

8. 基数排序

按照个十百千位排序

int n = arr.Length;
int max = arr[0];
for (int i = 1; i < n; i++)
{
    if (arr[i] > max)
        max = arr[i];
}
List<int>[] buckets = new List<int>[10];
for (int i = 0; i < 10; i++)
    buckets[i] = new List<int>();
int num = 1;
// 最大数位数
while (max / 10 > 0) 
{
    max /= 10;
    num++;
}
int bit = 1;
while (num > 0) 
{
    for (int i = 0; i < n; i++)
        buckets[arr[i] / bit % 10].Add(arr[i]);
    int count;
    int k = 0;
    for (int i = 0; i < 10; i++)
    {
        count = buckets[i].Count;
        for (int j = 0; j < count; j++)
            arr[k++] = buckets[i][j];
        buckets[i].Clear();
    }
    num--;
    bit *= 10;
}

9. 计数排序

计数排序是一种非比较排序,其核心是将序列中的元素作为键存储在额外的数组空间中,而该元素的个数作为值存储在数组空间中,通过遍历该数组排序

  1. 找出最大最小两个值
  2. 构建 max-min+1 数组 temp
  3. 遍历数组 arr,存入 temp 数组 temp[arr[i]-min]++
int n = arr.Length;
int min = arr[0];
int max = min;
for (int i = 1; i < n; i++)
{
    if (min > arr[i])
        min = arr[i];
    else if (max < arr[i])
        max = arr[i];
}
if (min == max)
    return;
int d = max - min + 1;
int[] temp = new int[d];
for (int i = 0; i < n; i++)
    temp[arr[i] - min]++;
int j;
int k = 0;
for (int i = 0; i < d; i++)
{
    j = temp[i];
    while (j > 0)
    {
        arr[k++] = min + i;
        j--;
    }
}

辅助函数

protected void Swap(int i, int j)
{
    Swap(arr, i, j);
}
protected void Swap(int[] arr, int i, int j)
{
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}
public void PrintArr()
{
    string str = "";
    for (int i = 0; i < arr.Length; i++)
    {
        str += arr[i];
        if (i != arr.Length - 1)
            str += ',';
    }
    Console.WriteLine(str);
}
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值