1冒泡排序
思路:把大数依次放在数组后面,最后实现排序,每次交换都是把大数放在数组后面
优点:稳定
确定:慢,每次只移动相邻两个元素
时间复杂度:最好O(n),最坏(数组反序)O(n2)。平均O(n2)
public static void Sort(int[] array)
{
for (int i = 0; i < array.Length; i++)
{
for (int j = 0; j < array.Length - 1 - i; j++)
{
if (array[j] > array[j + 1])
{
int temp = array[j + 1];
array[j + 1] = array[j];
array[j] = temp;
}
}
}
}
2快速排序
分治思想:先保证前半部分都小于后半部分,然后分别对前半部分和后半部分排序。
优点:高效极快,数据移动少
缺点:不稳定
时间复杂度:最坏O(n2)。平均O(nlogn)。
public static void QuickSort(int[] array, int left, int right)
{
if (left < right)
{
//取中间元素作为基准,小于的左移 大于的右移
int middle = array[(left + right) / 2];
int i = left - 1;
int j = right + 1;
while (true)
{
//移动下标 左边的右移 右边的左移
while (array[++i] < middle && i < right) ;
while (array[--j] > middle && j >0);
if (i > j) break;
//交换位置
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
QuickSort(array, left, i - 1);
QuickSort(array, j + 1, right);
}
}
3插入排序
思想:从索引1开始遍历,不断与前一个数进行比较,如果前一个数比自己大则换位置
优点:稳定,快
缺点:比较次数不一定,比较次数越少,插入点后的数据移动越多,特别是当数据总量庞大的时候,但用链表可以解决这一问题。
时间复杂度:O(n2)
public static void InsertSort(int[] array)
{
//将带比较的数值与它的前一数值进行比较,所以外层循环从第二个数值开始
for (int i = 0; i < array.Length; i++)
{
//如果当前元素小于其前面的元素
if (array[i] < array[i - 1])
{
//一趟完成时 将带比较数值置入比他小的数值的后一位
int temp = array[i];
int j = 0;
for (j = i - 1;j>=0&& temp < array[j]; j--)
{
array[j + 1] = array[j];
}
array[j+1] = temp;
}
}
}
4希尔排序
public static void ShellSort(int[] array){
int length = array.Length;
for (int h = length / 2; h > 0; h = h / 2) {
//hear is insert sort
for(int i = h;i<length;i++){
int temp = array [i];
if (temp < array [i - h]) {
for (int j = 0; j < i; j += h) {
if (temp < array [j]) {
temp = array [j];
array [j] = array [i];
array [i] = temp;
}
}
}
}
}
}
5选择排序
进行比较操作的时间复杂度为O(n^2),进行移动操作的时间复杂度为O(n)。
public static void SimpleSelectSort(int[] array){
int temp = 0;
int min = 0;//最小数标记
for (int i = 0 ;i<array.Length;i++){
min = i;
for (int j = i + 1; j < array.Length; j++) {
if (array [temp] > array [j]) {
min = j;
}
}
temp = array [i];
array [i] = array [min];
array [min] = temp;
}
}
6堆排序(选择排序)
利用数组特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i]。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。
//堆排序
public static void HeapSort(this int[] array,int top){
List<int> topNode = new List<int> ();
for (int i = array.Length / 2 - 1; i >= 0; i--) {
HeapAdjust (array, i, array.Length);
}
for (int i = array.Length - 1; i >= array.Length - top; i--) {
int temp = array [0];
array [0] = array [i];
array [i] = temp;
HeapAdjust (array, 0, i);
}
}
//构建堆
private static void HeapAdjust(int[] array,int parent,int length){
int temp = array [parent];
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 * parent + 1;
}
array [parent] = temp;
}
7归并排序
分治法:将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
归并操作(merge),也叫归并算法,指的是将两个顺序序列合并成一个顺序序列的方法。
如 设有数列{6,202,100,301,38,8,1}
初始状态:6,202,100,301,38,8,1
第一次归并后:{6,202},{100,301},{8,38},{1},比较次数:3;
第二次归并后:{6,100,202,301},{1,8,38},比较次数:4;
第三次归并后:{1,6,8,38,100,202,301},比较次数:4;
总的比较次数为:3+4+4=11,;
逆序数为14;
归并操作的工作原理如下:
第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置
第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针超出序列尾
将另一序列剩下的所有元素直接复制到合并序列尾
//归并排序
public static void MergeSort(this int[] array,int frist,int last){
if (frist < last) {
int middle = (frist + last) / 2;
MergeSort (array, frist, middle);
MergeSort (array, middle, last);
Merger (array, frist, middle, last);
}
}
public static void Merger(int[] array,int frist,int middle,int last){
Queue<int> tempV = new Queue<int> ();
int indexA, indexB;
//设置indexA 并扫描subArray1[frist,middle]
//设置indexB 并扫描subArray1[middle,last]
indexA = frist;
indexB = middle;
//在灭有比较完两个子标的情况下,比较v[indexA]和v[indexB]
//将其中小的放到临时变量tempV中
while(indexA<middle&&indexB <last){
if (array [indexA] < array [indexB]) {
tempV.Enqueue (array [indexA]);
indexA++;
} else {
tempV.Enqueue (array [indexB]);
indexB++;
}
}
//复制没有比较完字表中的元素
while(indexA<indexB){
tempV.Enqueue (array [indexA]);
indexA++;
}
while(indexA<last){
tempV.Enqueue (array [indexB]);
indexB++;
}
int index = 0;
while (tempV.Count > 0) {
array [frist + index] = tempV.Dequeue ();
index++;
}
}
8基数排序
时间复杂度O (nlog(r)m),r为所采取的基数,m为堆数
// 基数排序 约定:待排数字中没有0,如果某桶内数字为0则表示该桶未被使用,输出时跳过即可
// 待排数组 桶数组第一维长度 桶属猪第二维长度
public static void RadixSort(this int[] array,int array_x=10,int array_y = 100){
//最大数字不超过999999999...(array_x个9)
for(int i =0;i<array_x;i++){
int[,] bucket = new int[array_x, array_y];
foreach (var item in array) {
int temp = (item / (int)Math.Pow (10, i)) % 10;
for (int m = 0; m < array_y; m++) {
if (bucket [temp, m] == 0) {
bucket [temp, i] = item;
break;
}
}
}
for (int n = 0, x = 0; x < array_x; x++) {
for (int y = 0; y < array_y; y++) {
if (bucket [x, y] == 0)
continue;
array [n++] = bucket [x,y];
}
}
}
}