七种常用排序算法
Posted nobcaup
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了七种常用排序算法相关的知识,希望对你有一定的参考价值。
七种常用排序算法
一、常见排序算法一览:
时间复杂度: 是一个函数,它定量描述了该算法的运行时间。
空间复杂度:一个算法在运行过程中临时占用存储空间大小的量度。
稳定性:保证排序前2个相等的数其在序列的前后位置顺序和排序后它们两个的前后位置顺序相同就稳定,反之不稳定。
二、算法C#实现:
1、 直接插入排序:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace csharpconsole
{
class Program
{
/*
具体算法描述如下:
1.从第一个元素开始,该元素可以认为已经被排序
2.取出下一个元素,在已经排序的元素序列中从后向前扫描
3.如果该元素(已排序)大于新元素,将该元素移到下一位置
4.重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
5.将新元素插入到该位置后
6.重复步骤2~5
*/
public static void InsertSort(int[] List)
{
int tmp = 0;
int len = List.Length;
int i = 0;
int j = 0;
for (i = 1; i < len; i++)
{
tmp = List[i];
for (j = i - 1; j >= 0; j--)
{
if (tmp < List[j])
{
List[j + 1] = List[j];
}
else if (tmp > List[j])
{
break;
}
}
List[j + 1] = tmp;
}
return;
}
static void Main(string[] args)
{
int[] intArr = {10, 2, 56, 12, 6, 78, 34, 23, 9, 18, 7};
InsertSort(intArr);
for (int k = 0; k < intArr.Length; k++)
Console.WriteLine(intArr[k]);
Console.ReadKey();
}
}
}
2、 希尔排序:
实际上是分组的插入排序。缩小增量排序。先取定一个小于n的整数d1作为第一个增量,把表的全部记录分成d1个组,所有距离为d1的倍数的记录放在同一个组中,在各组内进行直接插入排序;然后,取第二个增量d2(<d1),重复上述的分组和排序,直至所取的增量dt=1。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace csharpconsole
{
class Program
{
public static void ShellSort(int[] List)
{
int tmp = 0;
int len = List.Length;
int i = 0;
int j = 0;
int d = len / 2; /* 初始步长取数组长度的一半 */
/* 观察看如果d=1的话,即是普通的插入排序算法 */
while (d >= 1)
{
/* 把距离为 d 的元素编为一个组,扫描所有组 */
for (i = d; i < len; i++)
{
tmp = List[i];
for (j = i - d; j >= 0; j = j - d)
{
if (tmp < List[j])
{
List[j + d] = List[j];
}
else if (tmp > List[j])
{
break;
}
}
List[j + d] = tmp;
}
d = d / 2;
}
return;
}
static void Main(string[] args)
{
int[] intArr = {10, 2, 56, 12, 6, 78, 34, 23, 9, 18, 7};
ShellSort(intArr);
for (int k = 0; k < intArr.Length; k++)
Console.WriteLine(intArr[k]);
Console.ReadKey();
}
}
}
3、冒泡排序(交换排序):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace csharpconsole
{
class Program
{
public static void BubbleSort(int[] List)
{
int i = 0;
int j = 0;
int len = List.Length;
int swap = 0;
/*
第一趟排序:通过两两比较,找到第一小的数值 1 ,将其放在序列的第一位。
第二趟排序:通过两两比较,找到第二小的数值 2 ,将其放在序列的第二位。
第三趟排序:通过两两比较,找到第三小的数值 3 ,将其放在序列的第三位。
至此,所有元素已经有序,排序结束。
*/
for (i = len - 1; i >= 0; i--)
{
for (j = len - 1; j >= len - i; j--)
{
if (List[j] < List[j - 1])
{
swap = List[j];
List[j] = List[j - 1];
List[j - 1] = swap;
}
}
}
return;
}
static void Main(string[] args)
{
int[] intArr = {10, 2, 56, 12, 6, 78, 34, 23, 9, 18, 7};
BubbleSort(intArr);
for (int k = 0; k < intArr.Length; k++)
Console.WriteLine(intArr[k]);
Console.ReadKey();
}
}
}
4、 快速排序(交换排序):
步骤:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace csharpconsole
{
class Program
{
public static void QuickSort(int[] List, int left, int right)
{
int baseNum = 0;
int low = 0;
int high = 0;
if (left < right)
{
baseNum = List[left];
low = left;
high = right;
while (low < high)
{
/* 从右往左扫描 */
while ((high > low) && (baseNum < List[high]))
{
high--;
}
List[low] = List[high];
/* 从左往右扫描 */
while ((low < high) && (baseNum > List[high]))
{
low++;
}
List[high] = List[low];
}
List[low] = baseNum;
QuickSort(List, left, low - 1);
QuickSort(List, low + 1, right);
}
return;
}
static void Main(string[] args)
{
int[] intArr = {10, 2, 56, 12, 6, 78, 34, 23, 9, 18, 7};
QuickSort(intArr, 0, intArr.Length - 1);
for (int k = 0; k < intArr.Length; k++)
Console.WriteLine(intArr[k]);
Console.ReadKey();
}
}
}
5、简单选择排序(直接选择排序):
(1) 从待排序序列中,找到关键字最小的元素;
(2) 如果最小元素不是待排序序列的第一个元素,将其和第一个元素互换;
(3) 从余下的 N - 1 个元素中,找出关键字最小的元素,重复(1)、(2)步,直到排序结束。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace csharpconsole
{
class Program
{
public static void SelectionSort(int[] List)
{
int index = 0;
int swap = 0;
int len = List.Length;
int i = 0;
int j = 0;
for (; i < len; i++)
{
/* 找到这一趟循环最小的值,记录下标,默认下标为i */
index = i;
for (j = i + 1; j < len; j++)
{
if (List[j] < List[index])
{
index = j;
}
}
/* 如果下标有改变,就交换数值 */
if (index != i)
{
swap = List[i];
List[i] = List[index];
List[index] = swap;
}
}
return;
}
static void Main(string[] args)
{
int[] intArr = {10, 2, 56, 12, 6, 78, 34, 23, 9, 18, 7};
SelectionSort(intArr);
for (int k = 0; k < intArr.Length; k++)
Console.WriteLine(intArr[k]);
Console.ReadKey();
}
}
}
6、 堆排序:
步骤:
(1)根据初始数组去构造初始堆(构建一个完全二叉树,保证所有的父结点都比它的孩子结点数值大)。
(2)每次交换第一个和最后一个元素,输出最后一个元素(最大值),然后把剩下元素重新调整为大根堆。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace csharpconsole
{
class Program
{
public static void HeapAdjust(int[] array, int parent, int length)
{
int temp = array[parent]; // temp保存当前父节点
int child = 2 * parent + 1; // 先获得左孩子
while (child < length)
{
// 如果有右孩子结点,并且右孩子结点的值大于左孩子结点,则选取右孩子结点
if (child + 1 < length && array[child] < array[child + 1])
{
child++;
}
// 如果父结点的值已经大于孩子结点的值,则直接结束
if (temp >= array[child])
{
break;
}
// 把孩子结点的值赋给父结点
array[parent] = array[child];
// 选取孩子结点的左孩子结点,继续向下筛选
parent = child;
child = 2 * child + 1;
}
array[parent] = temp;
}
public static void HeapSort(int[] list)
{
// 循环建立初始堆
for (int i = list.Length / 2; i >= 0; i--)
{
HeapAdjust(list, i, list.Length - 1);
}
// 进行n-1次循环,完成排序
for (int i = list.Length - 1; i > 0; i--)
{
// 最后一个元素和第一元素进行交换
int temp = list[i];
list[i] = list[0];
list[0] = temp;
// 筛选 R[0] 结点,得到i-1个结点的堆
HeapAdjust(list, 0, i);
}
}
static void Main(string[] args)
{
int[] intArr = {10, 2, 56, 12, 6, 78, 34, 23, 9, 18, 7};
HeapSort(intArr);
for (int k = 0; k < intArr.Length; k++)
Console.WriteLine(intArr[k]);
Console.ReadKey();
}
}
}
7、 归并排序:
步骤:
(1)“分解”——将序列每次折半划分。
(2)“合并”——将划分后的序列段两两合并后排序。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace csharpconsole
{
class Program
{
public static void Merge(int[] array, int low, int mid, int high)
{
int i = low; // i是第一段序列的下标
int j = mid + 1; // j是第二段序列的下标
int k = 0; // k是临时存放合并序列的下标
int[] array2 = new int[high - low + 1]; // array2是临时合并序列
// 扫描第一段和第二段序列,直到有一个扫描结束
while (i <= mid && j <= high)
{
// 判断第一段和第二段取出的数哪个更小,将其存入合并序列,并继续向下扫描
if (array[i] <= array[j])
{
array2[k] = array[i];
i++;
k++;
}
else
{
array2[k] = array[j];
j++;
k++;
}
}
// 若第一段序列还没扫描完,将其全部复制到合并序列
while (i <= mid)
{
array2[k] = array[i];
i++;
k++;
}
// 若第二段序列还没扫描完,将其全部复制到合并序列
while (j <= high)
{
array2[k] = array[j];
j++;
k++;
}
// 将合并序列复制到原始序列中
for (k = 0, i = low; i <= high; i++, k++)
{
array[i] = array2[k];
}
}
public static void MergePass(int[] array, int gap, int length)
{
int i = 0;
// 归并gap长度的两个相邻子表
for (i = 0; i + 2 * gap - 1 < length; i = i + 2 * gap)
{
Merge(array, i, i + gap - 1, i + 2 * gap - 1);
}
// 余下两个子表,后者长度小于gap
if (i + gap - 1 < length)
{
Merge(array, i, i + gap - 1, length - 1);
}
}
public static int[] MergeSort(int[] list)
{
for (int gap = 1; gap < list.Length; gap = 2 * gap)
{
MergePass(list, gap, list.Length);
}
return list;
}
static void Main(string[] args)
{
int[] intArr = {10, 2, 56, 12, 6, 78, 34, 23, 9, 18, 7};
MergeSort(intArr);
for (int k = 0; k < intArr.Length; k++)
Console.WriteLine(intArr[k]);
Console.ReadKey();
}
}
}
以上是关于七种常用排序算法的主要内容,如果未能解决你的问题,请参考以下文章