zoukankan      html  css  js  c++  java
  • 排序算法总结

    1、冒泡排序

         

    //冒泡排序
          void bubbleSort(int A[], int n)
          {
              bool flag = false;
              for (int i = n - 1; i > 0; i--)
              {
                  //注意i,j的终止条件
                  for (int j = 0; j < i; j++)
                  {
                      if (A[j]>A[j + 1])swap(A[j], A[j + 1]);
                      flag = true;
                  }
    
                  if (flag == false)return;
              }
    
          }
    View Code

        (上面代码有误,交换和改变flag值应有大括号)

    最差时间复杂度 O(n²) 记录是反序的,需要n-1次扫描,每趟扫描进行n-i次比较,每次比较都要移动3次

    最优时间复杂度 O(n) 记录是正序的,一趟扫描即可完成,比较n-1次

    平均时间复杂度 O(n²)

    虽然冒泡排序不一定进行n-1趟,但记录移动次数多,故平均时间性能比直接插入排序差

    最差空间复杂度 O(1)

    优点:稳定;

    缺点:慢,每次只能移动相邻两个数据

     

    2、插入排序

         

    //插入排序
          void insertSort(int A[], int n)
          {
              for (int i = 1; i < n; i++)
              {
                  //注意j从i-1开始
                  for (int j = i - 1; j >= 0;j--)
                  if (A[i] < A[j])
                      swap(A[i], A[j]);
              }
          }
    View Code

    最差时间复杂度 O(n²)最优时间复杂度 O(n)平均时间复杂度 O(n²)最差空间复杂度 O(n) total, O(1) auxiliary

     

    3、希尔排序

     

    //希尔排序
          void shellSort(int A[], int n)
          {
              int incrment = n;
              do{
                  incrment = n / 3 + 1;
                  shellPass(A, n, incrment);
              } while (n >= 1);
          }
          void shellPass(int A[], int n, int d)
          {
              for (int i = d; i < n;i++)
              for (int j = i - d; j >= 0 && A[j]>A[i]; j -= d)//注意j每次自减d,A[j]>A[i]放在判断条件效率更高
              {
                  swap(A[i], A[j]);
              }
          }
    View Code

    希尔排序实际上是一种插入排序, 它的时间复杂度和数组初始排序有关。

    平均时间复杂度:O(nlogn)

    空间复杂度:O(1)

    优点:快,数据移动少;

    缺点:不稳定,d的取值是多少,应取多少个不同的值,都无法确切知道,只能凭经验来取。

     4、选择排序

     

    //选择排序
          void selectSort(int A[], int n)
          {
              for (int i = 0; i < n - 1;i++)
              for (int j = i + 1; j < n; j++)
              {
                  if (A[i]>A[j])
                      swap(A[i], A[j]);
              }
          }
    View Code

    和冒泡排序的思想类似。

    最差时间复杂度 О(n²)最优时间复杂度 О(n²)平均时间复杂度 О(n²)最差空间复杂度 О(n) total, O(1) auxiliary

    5、归并排序

    //归并排序
    
          void merge(int A[], int first, int mid, int last, int temp[])
          {
              int i = first, j = mid + 1;
              int m = mid, int n = last;
              int k = 0;
              while (i <= m&&j <= n)
              {
                  if (A[i] < A[j])
                      temp[k++] = A[i++];
                  else
                      temp[k++] = A[j++];
              }
    
              while (i <= m)
                  temp[k++] = A[i++];
    
              while (j <= n)
                  temp[k++] = A[j++];
    
              for (i = 0; i < k; i++)//注意起始位置
                  A[first + i] = temp[k++];
          }
    
          void mSort(int A[], int first, int last, int temp[])
          {
              int mid = (first + last) / 2;
              mSort(A, first, mid, temp);
              mSort(A, mid + 1, last, temp);
    
              merge(A, first, mid, last, temp);
          }
    
          bool mergeSort(int A[], int n)
          {
              //统一接口,只在开始声明数组,提高效率
              int *p = new int[n];
              if (p == nullptr)return false;
              mSort(A, 0, n - 1, p);
              delete[] p;
              return true;
          }
    View Code

    平均时间复杂度:O(nlogn),效率较高

    6、堆排序

    堆排序包含两个过程:

    (1)初建堆

    (2)调整堆

    初建堆:从非终端结点开始一直到根结点,执行调整堆的过程。这样,就会建立一个大顶堆。

    调整堆:对于第二个过程,描述如下,第一次,取出堆顶元素与R[n]进行交换,然后从根结点开始调整堆,根结点与左右孩子中较大者交换,这样,

    左右子树的堆会被破坏,继续进行上述操作,直到叶子结点为止。第二次,取出堆顶元素与R[n-1]交换,然后调整堆。

    如果排序过程中,是按照从小到大正序,那么建立一个大顶堆。如果是逆序就建立一个小顶堆。

     //堆排序
    
          void adjustHeap(int A[], int i, int n)
          {
              //调整为最大堆
              int temp = A[i];
              for (int j = 2 * i + 1; j < n; j=2*j+1)
              {
                  //在子结点中找最大的
                  if (j + 1 < n&&A[j + 1] > A[j])
                      j++;
                  //如果已经是最大,无需调整
                  if (temp >= A[j])break;
                  //把较大值往上移
                  A[i] = A[j];
                  i = j;//调整i
              }
              A[i] = temp;
          }
    
          void heapSort(int A[], int n)
          {
              //建最大堆
              //从最后一个非叶子结点开始调整,分别调整成最大堆
              for (int i = (n - 1) / 2; i >= 0; i--)
                  adjustHeap(A, i, n);
    
              //排序 
              for (int i = n - 1; i >= 0; i--)
              {
                  swap(A[0], A[n - 1]);
                  //对剩下n-1个结点进行调整
                  adjustHeap(A, 0, n - 1);
              }
          }
    View Code

    7、快速排序

    它采用了分治的思想:先保证列表的前半部分都小于后半部分,然后分别对前半部分和后半部分排序,这样整个列表就有序了。快速排序的基本算法是:
    1. 从数列中挑出一个元素,称为 "基准"(pivot),
    2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分割之后,该基准是它的最后位置。这个称为分割(partition)操作。
    3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。递回的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递回下去,但是这个算法总会结束,

    因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。

    具体做法:

    (1)初始化,设置两个指针ij,初值为区间的上下界,即i=low, j=high;选择无序区的第一个记录R[i]作为基准记录,并将它保存在变量pivot中。

    (2)另j从high起向左扫描,直到找到第1个关键字小于pivot.key的记录R[j].将R[j]与基准R[i]交换,是关键字小于pivot.key的记录都移到基准的左边,交换后R[j]中是pivot;然后,令i自i+1位置开始向右扫描,

    直到找到第1个关键字大于pivot.key的记录R[i],将R[i]与R[j]交换,交换后,R[i]中存的是pivot,将关键字大于pivot.key的都移动到基准的右边;接着继续扫描,两端往中间靠拢,直到i=j,i就为pivot最终位置。

     

    快速排序的时间复杂度是O(nlogn),

    最坏情况下时间复杂度是O(n²)。

    平均时间复杂度 Θ(nlogn)

    最好的情况是枢纽元选取得当,每次都能均匀的划分序列。 时间复杂度O(nlogn)
    最坏情况是枢纽元为最大或者最小数字,那么所有数都划分到一个序列去了,即为有序的情况 时间复杂度为O(n^2)

    就空间复杂度来说,主要是递归造成的栈空间的使用,最好情况,递归树的深度为log2n,其空间复杂度也就为O(logn),最坏情况,需要进行n‐1递归调用,其空间复杂度为O(n),平均情况,空间复杂度也为O(logn)。

    优点: 快速,数据移动少

    缺点:不稳定

    快速排序被认为是目前基于比较的内部排序中较好的方法,当待排序的关键字随机分布时,快速排序的平均时间最短。

     

    堆排序所需的辅助空间少于快速排序,并且不会出现快速排序可能出现的最坏情况,但这两种排序都是不稳定的,归并排序是稳定的。

    //快速排序
    
    
          int median3(int A[], int left, int right)
          {
              //取主元:取首个,中间,最后元素的中位数
              int mid = (left + right) / 2;
              if (A[left] > A[mid])swap(&A[left], &A[mid]);
              if (A[left] > A[right-1])swap(&A[left], &A[right-1]);
              if (A[mid] > A[right-1])swap(&A[mid], &A[right-1]);
              //同时将主元藏在倒数第二个位置上,只需考虑个[left+1,right-3];
              swap(&A[mid], &A[right - 2]);
              return A[right - 2];
          }
    
          void quick_sort(int A[], int left, int right)
          {
              int pivot = median3(A, left, right);
    
              int i = left, j = right - 2;
              for (;;)
              {
                  while (A[++i] < pivot);
                  while (A[--j] > pivot);
    
                  if (i < j)swap(&A[i], &A[j]);
                  else break;
              }
    
              swap(&A[i], &A[right - 2]);//将pivot交换至正确位置
              quick_sort(A, left, i - 1);
              quick_sort(A, i + 1, right);
    
          }
    
          void quickSort(int A[], int n)
          {
              quick_sort(A, 0, n);
          }
    View Code
    void quick_sort(vector<int>& a, int start, int end)
    {
    	if (a.size() == 0 || end - start <= 1 || start < 0)
    		return;
    
    	int pivot_pos = start;
    	int pivot = a[start];
    	int temp;
    
    	for (int i = start + 1; i < end; i++)
    	{
    		if (a[i] < pivot)
    		{
    			if (++pivot_pos != i)
    			{
    				swap(a[pivot_pos], a[i]);
    			}
    		}
    	}
    	a[start] = a[pivot_pos];
    	a[pivot_pos] = pivot;
    	quick_sort(a, start, pivot_pos - 1);
    	quick_sort(a, pivot_pos + 1, end);
    
    }
    

      

  • 相关阅读:
    iOS9 News 应用
    swift中,Optional、?与!之间的关系
    [翻译] CotEditor
    [book] iOS 8 Swift Programming Cookbook
    便利的操作plist文件
    消除 Xcode7 中 directory not found for option 'xxxx' 警告
    点击单个cell高度变化的动画效果
    [翻译] LiquidFloatingActionButton
    一脸懵逼学习Zookeeper(动物园管理员)---》高度可靠的分布式协调服务
    一脸懵逼学习基于CentOs的Hadoop集群安装与配置(三台机器跑集群)
  • 原文地址:https://www.cnblogs.com/573177885qq/p/5666252.html
Copyright © 2011-2022 走看看