排序算法总结

1冒泡排序:

重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。重复地进行直到没有再需要交换的数据,也就是说该数列已经排序完成 ,这样,最小的元素会慢慢的浮到最前面

时间复杂度:O(n²)
空间复杂度:O(1)

代码:

		void MaoPao(int[] arr)
        {
     
            for(int i = 0; i < arr.Length; i++)
            {
     
                for(int j = 0; j < arr.Length - 1; j++)
                {
     
                    if (arr[j] > arr[j + 1])
                    {
     
                        int tem = arr[j];
                        arr[j] = arr[j + 1];
                        arr[j + 1] = tem;
                    }
                }
            }
        }

2选择排序:

首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

时间复杂度:O(n²)
空间复杂度:O(1)

代码:

		void XuanZe(int[] arr)
        {
     
            for(int i = 0; i < arr.Length; i++)
            {
     
                int index = i;
                for(int j = i + 1; j < arr.Length; j++)
                {
     
                    if (arr[j] < arr[index])
                    {
     
                        index = j;
                    }
                }
                int tem = arr[index];
                arr[index] = arr[i];
                arr[i] = tem;
            }
        }

3插入排序:

通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入

时间复杂度:O(n²)
空间复杂度:O(1)

代码:

		void ChaRu(int[] arr)
        {
     
            for(int i = 1; i < arr.Length; i++)
            {
     
                int preindex = i;
                int current = arr[i];
                while(preindex > 0 && current < arr[preindex-1])
                {
     
                    arr[preindex] = arr[preindex - 1];
                    preindex--;
                }
                arr[preindex] = current;
            }
        }

4希尔排序

希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序,

时间复杂度:< O(n²)
空间复杂度:O(1)

希尔排序的代码容易记的方法:
先写一遍正常的插入排序,外层加一个关于gap的for循环,吧里面的-1改成-gap

		void XiEr(int[] arr)
        {
     
            for(int gap = arr.Length / 2; gap > 0; gap /= 2)
            {
     
                for (int i = gap; i < arr.Length; i++)
                {
     
                    int preindex = i;
                    int current = arr[i];
                    while (preindex - gap >= 0 && current < arr[preindex - gap])
                    {
     
                        arr[preindex] = arr[preindex - gap];
                        preindex-= gap;
                    }
                    arr[preindex] = current;
                }
            }
        }

5归并排序

将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。

时间复杂度: O( n * log(n) )
空间复杂度:O(n)

代码:

		void GuiBing(int[] arr)
        {
     
            //先建立好一个辅助数组
            int[] _b = new int[arr.Length];
            MergeSort(arr, 0, arr.Length-1,_b);
        }
        void MergeSort(int[] arr,int left,int right,int[] _b)
        {
     
            if (left >= right)
                return;
            int mid = (left + right) / 2;
            MergeSort(arr,left, mid,_b);
            MergeSort(arr,mid + 1, right,_b);
            int i = left, j = mid + 1;
            int len = left;
            //合并
            while (i<=mid && j<=right)
            {
     
                if (arr[i] <= arr[j])
                {
     
                    _b[len++] = arr[i++];
                }
                else
                {
     
                    _b[len++] = arr[j++];
                }
            }
            //将左右边剩余元素填充
            while (i <= mid)
            {
     
                _b[len++] = arr[i++];
            }
            while (j <= right)
            {
     
                _b[len++] = arr[j++];
            }
            //拷贝
            for(int k = left; k <= right; k++)
            {
     
                arr[k] = _b[k];
            }
        }

6快速排序

通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。

时间复杂度:
最佳情况: O(n*log n)
最差情况:T(n) = O(n²)
空间复杂度:
O(1)

代码:

  		void KuaiSu(int[] arr)
        {
     
            QuickSort(arr, 0, arr.Length - 1);
        }
        void Swap(int[] arr,int i,int j)
        {
     
            int tem = arr[i];
        }
        void QuickSort(int[] arr,int left,int right)
        {
     
            if (left >= right)
                return;
            int key = arr[left];
            int i = left, j = right;
            while (i < j)
            {
     
                //从右向左找小于key的
                while (i < j && arr[j] >= key) j--;
                arr[i] = arr[j];
                //从左向右找大于key的
                while (i < j && arr[i] < key) i++;
                arr[j] = arr[i];
            }
            arr[i] = key;
            QuickSort(arr, left, i);
            QuickSort(arr, i + 1, right);
        }

7计数排序

计数排序不是基于比较的排序算法,其核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。 作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。
当输入的元素是n个0到k之间的整数时,它的运行时间是 O(n + k)。计数排序不是比较排序,排序的速度快于任何比较排序算法。由于用来计数的数组C的长度取决于待排序数组中数据的范围(等于待排序数组的最大值与最小值的差加上1),这使得计数排序对于数据范围很大的数组,需要大量时间和内存。

代码如下:

 		void JiShu(int[] arr)
        {
     
            //前提保证最大值和最小值的差不能太大
            int max=arr[0], min=arr[0];
            //统计最值
            for (int i = 0; i < arr.Length; i++)
            {
     
                if (arr[i] > max)
                    max = arr[i];
                if (arr[i] < min)
                    min = arr[i];
            }
            int len = max - min + 1;
            int[] _b = new int[len];
            for(int i = 0; i < len; i++)
            {
     
                _b[i] = 0;
            }
            for(int i = 0; i < arr.Length; i++)
            {
     
                _b[arr[i] - min]++;
            }
            int j = 0;
            for(int i = 0; i < len; i++)
            {
     
                while (_b[i] != 0)
                {
     
                    arr[j++] = i;
                    _b[i]--;
                }                    
            }
            
        }

8 桶排序

桶排序是将待排序集合中处于同一个值域的元素存入同一个桶中,也就是根据元素值特性将集合拆分为多个区域,则拆分后形成的多个桶,从值域上看是处于有序状态的。对每个桶中元素进行排序,则所有桶中元素构成的集合是已排序的。

相当于进化版的计数排序,只不过讲某个区间的值放在一个桶里,而计数排序是将一个相同的值放进一个桶里

		void Tong(int[] arr)
        {
     
            //找最值
            int max = arr[0], min = arr[0];
            for (int i = 0; i < arr.Length; i++)
            {
     
                if (arr[i] > max)
                    max = arr[i];
                if (arr[i] < min)
                    min = arr[i];
            }
            //划分一个区间的大小为5
            int gap = 5;
            List<int>[] tongs = new List<int>[(max-min+1) / gap + 1];
            for(int i = 0; i < tongs.Length; i++)
            {
     
                tongs[i] = new List<int>();
            }
            //f(x)= x/gap - min/gap
            //放到各自的桶里面
           for(int i = 0; i < arr.Length; i++)
            {
     
                int index = arr[i] / gap - min / gap;
                tongs[index].Add(arr[i]);
            }
            //对桶排序 对arr赋值
            int len = 0;
           foreach(List<int> t in tongs)
            {
     
                if (t.Count != 0)
                {
     
                    t.Sort();
                    foreach(int x in t)
                    {
     
                        arr[len++] = x;
                    }
                }                
            }

        }

9基数排序

这三种排序算法都利用了桶的概念,但对桶的使用方法上有明显差异:

  • 基数排序:根据键值的每位数字来分配桶;
  • 计数排序:每个桶只存储单一键值;
  • 桶排序:每个桶存储一定范围的数值;

所谓基数排序,思路也很简单,先按照个位排序,在按照十位排序,在按照百位排序。。。。。就行了

 		void RadixSort(int[] arr)
        {
     
            //获取数组最大值           
            int max = arr[0];
            for (int i = 0; i < arr.Length; i++)
            {
     
                if (arr[i] > max)
                    max = arr[i];               
            }
            int exp = 1;
            for (; max / exp > 0; exp *= 10)
            {
     
                CountSort(arr, exp);
            }
        }
        void CountSort(int[] arr,int exp)
        {
     
            int[] _output = new int[arr.Length];//临时数组
            int[] buckets = {
     0,0,0,0,0,0,0,0,0,0};
            for(int i = 0; i < arr.Length; i++)
            {
     
                buckets[(arr[i] / exp) % 10]++;
            }
            for(int i = 1; i < 10; i++)
            {
     
                buckets[i] += buckets[i - 1];
            }
            for(int i = 0; i < arr.Length; i++)
            {
     
                _output[buckets[(arr[i] / exp) % 10] - 1] = arr[i];
                buckets[(arr[i] / exp) % 10]--;
            }
            for(int i = 0; i < arr.Length; i++)
            {
     
                arr[i] = _output[i];
            }
        }

10 堆排序

堆排序这里写过思路:添加链接描述
至于怎么构建堆以及堆的各种操作,以后在专门写一篇

11二叉排序树

小的放左边大的放右边 ,但是当序列有序的时候会变成链表,比较耗时,解决办法是平衡二叉树或者红黑树

你可能感兴趣的:(算法)