Chinaunix首页 | 论坛 | 博客
  • 博客访问: 496171
  • 博文数量: 80
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1916
  • 用 户 组: 普通用户
  • 注册时间: 2013-07-11 22:01
个人简介

从事实时计算多年,熟悉jstorm/spark/flink/kafka/rocketMq, 热衷于开源,希望在这里和前辈们一起学习与分享,得到长足的进步!邮箱:hustfxj@gmail.com 我的githup地址是:https://github.com/hustfxj。欢迎和大家一起交流探讨问题。

文章分类

全部博文(80)

文章存档

2017年(11)

2015年(3)

2014年(33)

2013年(33)

分类: 高性能计算

2013-10-27 21:54:03

注意: 快速排序是排序大数组的最常用算法
 

排序算法

平均时间

最差时间

稳定度

额外空间

备注说明

冒泡排序

O(n2)

O(n2)

稳定

O(1)

n小时较好

选择排序

O(n2)

O(n2)

不稳定

O(1)

n小时较好

插入排序

O(n2)

O(n2)

稳定

O(1)

n小时较好

归并排序

O(nlogn)

O(nlogn)

稳定

O(n)

n大时较好

快速排序

O(nlogn)

O(n2)

不稳定

O(logn)

n大时较好

堆排序

O(nlogn)

O(nlogn)

不稳定

O(1)

n大时较好

计数排序

O(n)

O(n)

稳定

O(n+k)

输入序列限制

基数排序

O(n)

O(n)

稳定

O(n+k)

输入序列限制

桶排序

O(n)

O(n)

稳定

O(n)

输入序列限制

下表是各个排序算法的比较说明


















 

插入排序:

是一个对少量元素进行排序的有效算法。实现比较简单。时间复杂度:O(n^2),空间复杂度:O(1)。是稳定的排序方法。

点击(此处)折叠或打开

  1. void InsertionSort(int *a,int n)
  2. {
  3.     int temp;
  4.     for(int i = 1;i < n;++i)
  5.     {
  6.         temp = *(a + i);
  7.         int j = i - 1;
  8.         while(j >= 0 && *(a + j) > temp)
  9.         {
  10.             *(a + j + 1) = *(a + j);
  11.             --j;
  12.         }
  13.         *(a + j + 1) = temp;
  14.     }
  15. }

合并排序
采用分治法。将n个元素分成各含n/2个元素的子序列,用合并排序法对两个子序列递归的排序(子序列长度为1时递归结束),最后合并两个已排序的子序列得到结果。时间复杂度:O(nlogn),空间复杂度:O(n)。是稳定的排序方法。

点击(此处)折叠或打开

//合并排序

  1. #include <iostream>
  2. using namespace std;

  3. #define MAX_VALUE 100000//用于设置哨兵,避免检查是否每一个堆都是空的

  4. //合并两个子数组的函数
  5. void Merge(int *a,int p,int q,int r)
  6. {
  7.     int num1,num2;
  8.     num1 = q - p + 1;
  9.     num2 = r - q;
  10.     int *a1 = (int*)malloc((num1 + 1) * sizeof(int));
  11.     int *a2 = (int*)malloc((num2 + 1) * sizeof(int));
  12.     for(int i = 0;i < num1;++i)
  13.         *(a1 + i) = *(a + p + i);
  14.     *(a1 + num1) = MAX_VALUE;//设置哨兵元素
  15.     for(int i = 0;i < num2;++i)
  16.         *(a2 + i) = *(a + q + 1 + i);
  17.     *(a2 + num2) = MAX_VALUE;//设置哨兵元素
  18.     
  19.     //进行排序
  20.     int index1 = 0;
  21.     int index2 = 0;
  22.     for(int i = p;i <= r;++i)
  23.     {
  24.         if(*(a1 + index1) < *(a2 + index2))
  25.         {
  26.             *(a + i) = *(a1 + index1);
  27.             ++index1;
  28.         }
  29.         else
  30.         {
  31.             *(a + i) = *(a2 + index2);
  32.             ++index2;
  33.         }
  34.     }
  35.     free(a1);
  36. free(a2);
  37. }

冒泡排序

每一趟都比较相邻两个元素,若是逆序的,则交换。结束的条件应该是“在一趟排序过程中没有进行过交换元素的操作”。时间复杂度:O(n^2),空间复杂度O(1)。是稳定的排序。

点击(此处)折叠或打开

  1. void BubbleSort(int *a,int n)
  2. {
  3.     int flag,temp;//标记是否进行过交换操作
  4.     for(int i = 0;i < n - 1;++i)
  5.     {
  6.         flag = 0;
  7.         for(int j = 0;j < n - 1 - i;++j)
  8.         {
  9.             if(*(a + j) > *(a + j + 1))
  10.             {
  11.                 temp = *(a + j);
  12.                  *(a + j) = *(a + j + 1);
  13.                  *(a + j + 1) = temp;
  14.                  flag = 1;
  15.             }
  16.         }
  17.         if(flag == 0)break;
  18.     }
  19. }

快速排序

它是对冒泡排序的一种改进。它的基本思想是:通过一趟排序将待排序元素分成两个部分,其中一部分元素比另一部分元素小。再分别对这两部分元素进行排序。以达到整个元素序列有序。时间复杂度:O(nlogn),空间复杂度O(logn),是不稳定的算法。

点击(此处)折叠或打开

  1. int Partition(int *a,int low,int high)
  2. {
  3.     int pivotKey = *(a + high);
  4.     int i = low - 1;
  5.     for(int j = low;j <= high - 1;++j)
  6.     {
  7.         if (*(a + j) < pivotKey)
  8.         {
  9.             ++i;
  10.             int tmp = *(a + i);
  11.             *(a + i) = *(a + j);
  12.             *(a + j) = tmp;
  13.         }
  14.     }
  15.   
  16.     int tmp = *(a + i + 1);
  17.     *(a + i + 1) = *(a + high);
  18.     *(a + high) = tmp;
  19.   
  20.     return (i + 1);
  21. }
  22.   
  23. void QuickSort(int *a,int low,int high)
  24. {
  25.     if(low < high)
  26.     {
  27.         int PivotLoc = Partition(a,low,high);
  28.         QuickSort(a,low,PivotLoc - 1);
  29.         QuickSort(a,PivotLoc + 1,high);
  30.     }
  31. }

堆排序:
一种原地排序算法,即在任何时刻数组中只有常数个元素存储在输入数组以外


点击(此处)折叠或打开

  1. //注意:下表都以1开始,而不是0
  2. //得到父节点索引
  3. int getParent(int i)
  4. {
  5.     return i>>1;
  6. }
  7.   
  8. //得到左子树索引
  9. int getLeftSon(int i)
  10. {
  11.     return i<<1;
  12. }
  13.   
  14. //得到右子树索引
  15. int getRightSon(int i)
  16. {
  17.     return ((i<<1) + 1);
  18. }
  19.   
  20. //调整以某个节点i为根节点的子树为大根堆
  21. void MaxHeapify(int A[],int i,int HeapSize)
  22. {
  23.     int left = getLeftSon(i);
  24.     int right = getRightSon(i);
  25.     int largest = i;//记录值最大的元素的索引
  26.   
  27.     if (left <= HeapSize && A[left] > A[i])
  28.     {
  29.         largest = left;
  30.     }
  31.   
  32.     if (right <= HeapSize && A[right] > A[largest])
  33.     {
  34.         largest = right;
  35.     }
  36.   
  37.     if (largest != i)//此子树不满足大根堆的性质,需要进行调整
  38.     {
  39.         //进行交换
  40.         int temp = A[i];
  41.         A[i] = A[largest];
  42.         A[largest] = temp;
  43.           
  44.         MaxHeapify(A,largest,HeapSize);//递归调用,继续调整子树
  45.     }
  46. }
  47.   
  48. //输出数组元素
  49. void printHeap(int A[],int HeapSize)
  50. {
  51.     for(int i = 1;i <= HeapSize;++i)
  52.     {
  53.         cout << A[i] << " ";
  54.     }
  55.     cout << endl;
  56. }
  57.   
  58. //建堆
  59. void buildMaxHeap(int A[],int HeapSize)
  60. {
  61.     for (int i = (int)floor((float)HeapSize / 2);i > 0;--i)
  62.     {
  63.         MaxHeapify(A,i,HeapSize);
  64.     }
  65.   
  66.     cout << "建成的大根堆:" << endl;
  67.     printHeap(A,HeapSize);
  68. }
  69.   
  70. //堆排序
  71. void heapSort(int A[],int HeapSize)
  72. {
  73.     buildMaxHeap(A,HeapSize);
  74.     for (int i = HeapSize;i > 0;--i)
  75.     {
  76.         int temp = A[1];
  77.         A[1] = A[i];
  78.         A[i] = temp;
  79.         MaxHeapify(A,1,i - 1);
  80.     }
  81. }

计数排序

思想是对每一个输入元素x,确定出小于x的元素的个数。然后我们就可以直接把它放在嘴中输出数组中相应的位置上。 但是计数排序基于这样一个假设:n个输入元素的每一个大小范围都是[0,k]。

点击(此处)折叠或打开

  1. void CountintSort(int A[],int *B,int n,int k,int *C)
  2. {
  3.     //初始化C数组
  4.     for (int i = 0;i <= k;++i)
  5.     {
  6.         C[i] = 0;
  7.     }
  8.   
  9.     for (int i = 0;i < n;++i)
  10.     {
  11.         ++C[A[i]];//C[i]:值等于i的元素的个数
  12.     }
  13.   
  14.     for (int i = 1;i <= k;++i)
  15.     {
  16.         C[i] += C[i - 1];//C[i]:值小于等于i的元素的个数
  17.     }
  18.       
  19.     for (int i = n - 1;i >= 0;--i)
  20.     {
  21.         B[C[A[i]] - 1] = A[i];//注意:下标索引从0开始!
  22.         --C[A[i]];
  23.     }
  24. }

时间复杂度是O(k + n)。一般,当k = O(n)时,常常采用计数排序。这时候的运行时间为O(n)。计数排序是稳定的排序。

基数排序

算法思想

基数排序是从低位到高位依次对所有的数进行排序。如果所有的数最高位数是d,那么先按最低有效位数字进行排序,得到一个结果。然后往高位重复这个过程。需要注意的是,按位排序必须是稳定的排序算法。经常采用的是计数排序。


点击(此处)折叠或打开

  1. /********************************************************
  2. *函数名称:GetNumInPos
  3. *参数说明:num 一个整形数据
  4. *         pos 表示要获得的整形的第pos位数据
  5. *说明: 找到num的从低到高的第pos位的数据
  6. *********************************************************/
  7. int GetNumInPos(int num,int pos)
  8. {
  9.     int temp = 1;
  10.     for (int i = 0; i < pos - 1; i++)
  11.         temp *= 10;

  12.     return (num / temp) % 10;
  13. }

  14. /********************************************************
  15. *函数名称:RadixSort
  16. *参数说明:pDataArray 无序数组;
  17. *         iDataNum为无序数据个数
  18. *说明: 基数排序
  19. *********************************************************/
  20. #define RADIX_10 10 //整形排序
  21. #define KEYNUM_31 10 //关键字个数,这里为整形位数
  22. void RadixSort(int* pDataArray, int iDataNum)
  23. {
  24.     int *radixArrays[RADIX_10]; //分别为0~9的序列空间
  25.     for (int i = 0; i < 10; i++)
  26.     {
  27.         radixArrays[i] = (int*)malloc((iDataNum + 1)*sizeof(int));
  28.         radixArrays[i][0] = 0; //index为0处记录这组数据的个数
  29.     }
  30.     
  31.     for (int pos = 1; pos <=KEYNUM_31; pos++) //从个位开始到KEYNUM_31位
  32.     {
  33.         for (int i = 0; i < iDataNum; i++) //分配过程
  34.         {
  35.             int num = GetNumInPos(pDataArray[i], pos);
  36.             int index = ++radixArrays[num][0];
  37.             radixArrays[num][index] = pDataArray[i];
  38.         }

  39.         int j;
  40.         for (i = 0, j =0; i < RADIX_10; i++) //收集
  41.         {
  42.             for (int k = 1; k <= radixArrays[i][0]; k++)
  43.                 pDataArray[j++] = radixArrays[i][k];
  44.             radixArrays[i][0] = 0; //复位
  45.         }
  46.     }
  47. }


桶排序

当输入数据符合均匀分布时,即可以以线性期望时间运行。即使输入不满足线性关系,桶排序也仍然可以以线性时间运行。只要输入满足这样一个性质,即各个桶尺寸的平方和与总的元素数呈线性关系。

桶排序的思想:
将区间[0,1)分成n个相同大小的子区间,或称为桶。然后将n个输入元素分布到各个桶中去。每个桶中的元素用一个链表来存储


点击(此处)折叠或打开

  1. #include <iostream>
  2. #include <cstdlib>
  3. #include <ctime>
  4. #include <cmath>
  5.   
  6. using namespace std;
  7.   
  8. //桶中链表节点数据结构
  9. typedef struct StructLinkNode{
  10.     double elem;
  11.     struct StructLinkNode *next;
  12. }LinkNode,*LinkNodePtr;
  13.   
  14. //桶排序
  15. void BucketSort(double *a,int n);
  16. //删除一条链表
  17. void deleteLinkList(LinkNodePtr head);
  18.   
  19. int main()
  20. {
  21.     srand(time(NULL));
  22.     int n = 8;
  23.     double *a = new double[n];
  24.     for(int i = 0;i < n;++i)
  25.         *(a + i) = rand() * 1.0 / RAND_MAX;
  26.   
  27.     cout << "Before sort : " << endl;
  28.     for(int i = 0;i < n;++i)
  29.         cout << *(a + i) << " ";
  30.     cout << endl;
  31.   
  32.     BucketSort(a,n);
  33.   
  34.     cout << "After sort : " << endl;
  35.     for(int i = 0;i < n;++i)
  36.         cout << *(a + i) << " ";
  37.     cout << endl;
  38. }
  39.   
  40. //桶排序
  41. void BucketSort(double *a,int n)
  42. {
  43.     //存放链表的数组
  44.     LinkNodePtr *linkListArr = new LinkNodePtr[n];
  45.     //初始化
  46.     for (int i = 0;i < n;++i)
  47.     {
  48.         linkListArr[i] = new LinkNode;
  49.         linkListArr[i]->elem = -1;
  50.         linkListArr[i]->next = NULL;
  51.     }
  52.   
  53.     //将n个输入元素依次放入n个桶中
  54.     for (int i = 0;i < n;++i)
  55.     {
  56.         LinkNodePtr newNode = new LinkNode;
  57.         newNode->elem = *(a + i);
  58.         newNode->next = NULL;
  59.   
  60.         //将新元素插入对应桶的链表的正确位置
  61.         int index = floor(n * *(a + i));
  62.         LinkNodePtr loopPtr = linkListArr[index]->next;
  63.         LinkNodePtr prevPtr = linkListArr[index];
  64.         while(loopPtr != NULL && *(a + i) > loopPtr->elem)
  65.         {
  66.             prevPtr = loopPtr;
  67.             loopPtr = loopPtr->next;
  68.         }
  69.         newNode->next = loopPtr;
  70.         prevPtr->next = newNode;
  71.     }
  72.   
  73.     int count = 0;
  74.     for (int i = 0;i < n;++i)
  75.     {
  76.         LinkNodePtr loopPtr = linkListArr[i]->next;
  77.         while(loopPtr != NULL)
  78.         {
  79.             *(a + count) = loopPtr->elem;
  80.             ++count;
  81.             loopPtr = loopPtr->next;
  82.         }
  83.     }
  84.   
  85.     for (int i = 0;i < n;++i)
  86.         deleteLinkList(linkListArr[i]);
  87. }
  88.   
  89. //删除一条链表
  90. void deleteLinkList(LinkNodePtr head)
  91. {
  92.     if (NULL == head)
  93.     {
  94.         return;
  95.     }
  96.     deleteLinkList(head->next);
  97.     delete head;
  98. }












 


阅读(1162) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~