各种经典排序算法汇总( 亲测调试运算通过)

来源:互联网 发布:用淘宝联盟招代理步骤 编辑:程序博客网 时间:2024/05/22 01:55

这几天好好学习了一下排序算法 查看了各种书籍和网络资源 挑着简单易懂的教程好好学习了一下  基本上算是过了一遍 之后几天 对排序算法好好地总结一下 整理一下,先把要整理的算法列举一下:

1,选择排序

对于一个a[0,n]的数组,依次遍历数组,每次选出最大或最小的一个数

[cpp] view plaincopyprint?
  1. void selectSort(int *a,int size) 
  2.     int min; 
  3.     for(int i=0;i<size;i++) 
  4.     { 
  5.         min=i;      //将当前下标定义为最小值下标 
  6.         for(int j=i+1;j<size;j++) 
  7.             if(a[min]>a[j]) 
  8.                 min=j;    // 记录当前最小下标 
  9.         if(i!=min) 
  10.             swap(a[i],a[min]);   // 如果i不是最小下标 则交换 
  11.     } 
  12.     print(a,size); 

2,冒泡排序

依次比较相邻的两个数,将小数放在前面,大数放在后面。即在第一趟:首先比较第1个和第2个数,将小数放前,大数放后。然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放前,大数放后。至此第一趟结束,将最大的数放到了最后。在第二趟:仍从第一对数开始比较(因为可能由于第2个数和第3个数的交换,使得第1个数不再小于第2个数),将小数放前,大数放后,一直比较到倒数第二个数(倒数第一的位置上已经是最大的),第二趟结束,在倒数第二的位置上得到一个新的最大数(其实在整个数列中是第二大的数)。如此下去,重复以上过程,直至最终完成排序。

[cpp] view plaincopyprint?
  1. void BubbleSort(int *a,int size) 
  2.     for(int i=0;i<size-1;i++) 
  3.         for(int j=0;j<size-1-i;j++) 
  4.         { 
  5.             if(a[j]>a[j+1]) 
  6.                 swap(a[j],a[j+1]); 
  7.         } 
  8.     print(a,size); 

优化:使用标志的冒泡排序, 因为当一次遍历时 没有发生任何的交换 事实上证明数组排序已经完成 函数可以退出

[cpp] view plaincopyprint?
  1. void BubbleSortWithFlag(int *a,int size) 
  2.     bool flag; 
  3. for(int i=0;i<size-1;i++) 
  4.     { 
  5.         flag=true
  6.     for(int j=0;j<size-1-i;j++) 
  7.         { 
  8.             if(a[j]>a[j+1]) 
  9.             { 
  10.                 swap(a[j],a[j+1]); 
  11.                 flag=false
  12.             } 
  13.         } 
  14.         if(flag==true
  15.         { 
  16.             print(a,size); 
  17.             return
  18.         } 
  19.     } 

鸡尾酒排序 :冒泡排序的变形 (转)

鸡尾酒排序等于冒泡排序的轻微变形,不同的地方在于从低到高然后从高到低,而冒泡排序则仅从低到高去比较序列里的每个元素。他可以得到比冒泡排序稍微好一点的效能,原因是冒泡排序只从一个方向进行比对(由低到高),每次循环只移动一个项目。以序列(2,3,4,5,1)为例,鸡尾酒排序只需要访问两次(升序降序各一次 )次序列就可以完成排序,但如果使用冒泡排序则需要四次。

(1)先对数组从左到右进行冒泡排序(升序),则最大的元素去到最右端;

(2)再对数组从右到左进行冒泡排序(降序),则最小的元素去到最左端。以此类推,依次改变冒泡的方向,并不断缩小未排序元素的范围。

[cpp] view plaincopyprint?
  1. void CockSort(int *a,int size) 
  2.     int low=0; 
  3.     int up=size-1; 
  4.     int index=0; 
  5.     while(low<up) 
  6.     { 
  7.         for(int i=low;i<up;i++) 
  8.             if(a[i]>a[i+1]) 
  9.             { 
  10.                 swap(a[i],a[i+1]); 
  11.                 index=i; 
  12.             } 
  13.         up=index; 
  14.         for(int i=up;i>low;i--) 
  15.             if(a[i]<a[i-1]) 
  16.             { 
  17.                 swap(a[i],a[i-1]); 
  18.                 index=i; 
  19.             } 
  20.          low=index; 
  21.     } 
  22.     print(a,size); 


3,插入排序 (直接,折半,路插入,表插入

依次取出便利每一项 将每一项temp=a[j]和其之前的数进行比较,如果发现了比自己大的数 就将其放在当前j的位置 同时j--,继续用temp和之前的数进行比较,直到没有比自己大的数时结束。

[cpp] view plaincopyprint?
  1. //直接插入排序 
  2. void insertSort(int *a,int size) 
  3.     if(size<2) 
  4.         return
  5.     int temp; 
  6.     int j; 
  7.     for(int i=1;i<size;i++) 
  8.     { 
  9.         temp=a[i]; 
  10.         for( j=i;j>0&&temp<a[j-1];j--) 
  11.         { 
  12.               a[j]=a[j-1]; 
  13.         } 
  14.         a[j]=temp; 
  15.     } 
  16.     print(a,size); 

折半插入排序:

 折半插入排序(binary insertion sort)是对插入排序算法的一种改进,由于排序算法过程中,就是不断的依次将元素插入前面已排好序的序列中。由于前半部分为已排好序的数列,这样我们不用按顺序依次寻找插入点,可以采用折半查找的方法来加快寻找插入点的速度。

折半插入排序算法的具体操作为:在将一个新元素插入已排好序的数组的过程中,寻找插入点时,将待插入区域的首元素设置为a[low],末元素设置为a[high],则轮比较时将待插入元素与a[m],其中m=(low+high)/2相比较,如果比参考元素小,则选择a[low]到a[m-1]为新的插入区域(即high=m-1),否则选择a[m+1]到a[high]为新的插入区域(即low=m+1),如此直至low<=high不成立,即将此位置之后所有元素后移一位,并将新元素插入a[high+1]。

额 网上的方法 不是从数组a[1]开始 就是结果不正确 试了老半天 总算对了

[cpp] view plaincopyprint?
  1. void binaryInsertSort(int *a,int size) 
  2.     int low,high,m,temp,j; 
  3.     for (int i=1;i<size;++i){ 
  4.        temp=a[i]; 
  5.        low=0; 
  6.        high=i-1; 
  7.       /* if(a[i]>a[i-1])   //这句话可以稍微优化一下下速度 不影响结果
  8.            continue;*/ 
  9.        while (low<=high){ 
  10.          m=(low+high)/2; 
  11.          if (temp<=a[m]) 
  12.              high=m-1;   //当程序跳出时 high指向的其实并不是 >=temp的值的位置 而是>=temp的值的左边的位置 所以.... 
  13.          else   
  14.              low=m+1; 
  15.        } 
  16.        for( j=i;j>high+1;--j)       //所以 这里的high要加一哇  
  17.            a[j]=a[j-1]; 
  18.        a[j]=temp; 
  19.      } 
  20.     print(a,size); 
路插入 和 表插入 过几天再说.......

4,希尔排序

希尔算法思想:将整个无序序列分割成若干小的子序列分别进行插入排序。

如 一个长度为13的数组

81  94 11  96  12  35  17  95 28  58  41  75 15

先以13/2=5为gap进行比较 即对(81 35 41)(94 17 75)(11 95 15)分别进行排序  即对数组进行一次间距为5的插入排序

之后以3 和 1为间距 对数组进行插入排序

[cpp] view plaincopyprint?
  1. void shellSort(int *a,int size)  // 代码取自 数据结构于问题求解(c++版) 
  2.     for(int gap=size/2;gap>0;gap=gap==2?1:static_cast<int>(gap/2.2)) // 这里计算出当前的 间距 
  3.     { 
  4.         for(int i=gap;i<size;i++) // 这里跟插入排序的代码一样 不过不在是每次与前一位比较 而是与前gap位进行比较 
  5.         { 
  6.             int  temp=a[i]; 
  7.             int j; 
  8.             for(j=i;j>=gap&&temp<a[j-1];j-=gap) 
  9.             { 
  10.                 a[j]=a[j-gap]; 
  11.             } 
  12.             a[j]=temp; 
  13.         } 
  14.     } 
  15.     print(a,size); 

5,归并排序

归并操作(merge),也叫归并算法,指的是将两个已经排序的序列合并成一个序列的操作。归并排序算法依赖归并操作。

归并操作的过程如下:

  1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
  2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置
  3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
  4. 重复步骤3直到某一指针达到序列尾
  5. 将另一序列剩下的所有元素直接复制到合并序列尾
[cpp] view plaincopyprint?
  1. void mergeSort(int* a,int size,int* temp,int left,int right) 
  2.     if(left<right) 
  3.     { 
  4.         int mid=(left+right)/2; 
  5.         mergeSort(a,size,temp,left,mid); 
  6.         mergeSort(a,size,temp,mid+1,right); 
  7.         merge(a,size,temp,left,mid+1,right); 
  8.     } 
  9. void merge(int *a,int size,int *temp,int leftPos ,int rightPos,int rightEnd) 
  10.     int leftEnd=rightPos-1; 
  11.     int tempPos=leftPos; 
  12.     int num=rightEnd-leftPos+1; 
  13.  
  14.     while(leftPos<=leftEnd && rightPos<=rightEnd) 
  15.         if(a[leftPos]<=a[rightPos]) 
  16.             temp[tempPos++]=a[leftPos++]; 
  17.         else 
  18.             temp[tempPos++]=a[rightPos++]; 
  19.     while(leftPos<=leftEnd) 
  20.     { 
  21.         temp[tempPos++]=a[leftPos++]; 
  22.     } 
  23.     while(rightPos<=rightEnd) 
  24.     { 
  25.         temp[tempPos++]=a[rightPos++]; 
  26.     } 
  27.     for(int i=0;i<num;i++,rightEnd--) 
  28.     { 
  29.         a[rightEnd]=temp[rightEnd]; 
  30.     } 

6,快速排序

一趟快速排序的算法是:

 1)设置两个变量I、J,排序开始的时候:I=0,J=N-1;
 2)以第一个数组元素作为关键数据,赋值给key,即 key=A[0];
 3)从J开始向前搜索,即由后开始向前搜索(J=J-1即J--),找到第一个小于key的值A[j],A[j]与A[i]交换;
 4)从I开始向后搜索,即由前开始向后搜索(I=I+1即I++),找到第一个大于key的A[i],A[i]与A[j]交换; 

 5)重复第3、4、5步,直到 I=J; (3,4步是在程序中没找到时候j=j-1,i=i+1,直至找到为止。找到并交换的时候i, j指针位置不

变。另外当i=j这过程一定正好是i+或j-完成的最后另循环结束。)

[cpp] view plaincopyprint?
  1. int partition(int *a,int low,int high) 
  2. <//这里从两端开始 没有考虑抽取支点的过程 支点可以选取第一个 中间点 和最后一个点 选取中间大的值 交换到数组的最后面 
  3.     int pivot=a[high]; 
  4.     int i,j; 
  5.     for( i=low-1,j=high;;){ 
  6.         while(a[++i]<pivot &&i<high){};//从前往后 找大于支点的 
  7.         while(a[--j]>pivot &&j>low){}; //从前往前 找小于支点的 
  8.         if(i<j){ 
  9.             swap(a[i],a[j]);   //若找到 则交换 
  10.         } 
  11.         else 
  12.             break
  13.     } 
  14.     swap(a[i],a[high]); // 将支点交换到小于与大于的分解处 
  15.     return i;  
  16. void qucikSort(int*a,int low,int high) 
  17.     if(low<high) 
  18.     { 
  19.         int mid=partition(a,low,high);  
  20.         qucikSort(a,low,mid-1);       //递归进行快排 
  21.         qucikSort(a,mid+1,high); 
  22.     } 

7,堆排序 

取自算法导论

[cpp] view plaincopyprint?
  1. int Left(int i)// 这里取左右和父节点 是以 顶节点index为0来考虑的 
  2.     return i*2+1; 
  3. int Right(int i) 
  4.     return i*2+2; 
  5. int Parent(int i) 
  6.     return (i-1)/2; 
  7. void max_heapify(int *a,int heapSize,int i)  
  8.     // 是对最大堆进行操作的重要子程序  用于保持堆的性质 
  9.     int left=Left(i); 
  10.     int right=Right(i); 
  11.     int largest; 
  12.     if(left<heapSize&&a[left]>a[i]) 
  13.         largest=left; 
  14.     else 
  15.         largest=i; 
  16.     if(right<heapSize&&a[right]>a[largest]) 
  17.         largest=right; 
  18.     if(largest!=i)   //如果该父节点不是最大 
  19.     {  
  20.         swap(a[i],a[largest]);  // 则将较大的子节点 与父节点交换 因为交换可能破坏之后的结构 
  21.             max_heapify(a,heapSize,largest); // 故 继续对交换的那个子节点做一次最大堆操作 
  22.     } 
  23. void build_max_heap(int *a,int size)  //构建最大堆     (堆的大小 小于等于 数组的大小 )   
  24. {  
  25.     int heapSize=size; 
  26.     for(int i=size/2-1;i>=0;i--) 
  27.     { 
  28.         max_heapify(a,heapSize,i); 
  29.     } 
  30.  
  31. void heapSort(int* a,int size) 
  32.     build_max_heap(a,size); 
  33.     int heapSize=size; 
  34.     for(int i=size-1;i>=1;i--) 
  35.     { 
  36.         swap(a[0],a[i]);   // 讲顶节点与最后一个交换 最后一个节点即存的最大值 
  37.         heapSize--;    //最大堆的节点个数减一 不考虑 最后点 
  38.         max_heapify(a,heapSize,0); // 交换后 重新保持最大堆的性质 
  39.     } 

8,计数排序

[cpp] view plaincopyprint?
  1. void countingSort(int *a,int size,int k) 
  2.     int *c=newint[k+1]; 
  3.     int *b=newint[size]; 
  4.     for(int i=0;i<=k;i++) 
  5.     { 
  6.         c[i]=0; 
  7.     } 
  8.     for(int j=0;j<size;j++) 
  9.     { 
  10.         b[j]=0; 
  11.         c[a[j]]++; 
  12.     } 
  13.     for(int t=1;t<k+1;t++) 
  14.     { 
  15.         c[t]=c[t]+c[t-1]; 
  16.     } 
  17.     for(int t=size-1;t>=0;t--) 
  18.     {  
  19.          b[c[a[t]]]=a[t]; 
  20.          c[a[t]]--; 
  21.     } 
  22.  
  23.     //int pos=0;    // 上面是算法导论的标准方法 下面的方式我觉得直观而且快一些 
  24.     //for(int i=0;i<=k;i++) 
  25.     //{ 
  26.     //  for(int t=0;t<c[i];t++) 
  27.     //      b[pos++]=i; 
  28.     //   
  29.     //} 
  30.     print(b,size); 


9,桶排序

[cpp] view plaincopyprint?
  1. class Node{ 
  2. public: int key; 
  3. public: Node* next; 
  4. }; 
  5.  
  6. void bucketSort(int a[],int size,int bucketSize) 
  7.     //Node **bucketNode1=(Node**)malloc(bucketSize*sizeof(Node *)); 
  8.     Node ** bucketTable=new Node*[bucketSize]; 
  9.     for(int i=0;i<bucketSize;i++) 
  10.     { 
  11.         //bucketNode1[i]=(Node *)malloc(sizeof(Node)); 
  12.         Node* node=new Node(); 
  13.         node->key=0; 
  14.         node->next=NULL; 
  15.         bucketTable[i]=node; 
  16.     } 
  17.     for(int j=0;j<size;j++) 
  18.     { 
  19.         Node* node=new Node(); 
  20.         node->key=a[j]; 
  21.         node->next=NULL; 
  22.         int index=a[j]/10; 
  23.          
  24.         Node *buketNode=bucketTable[index];  // 找到自己应当所在的桶 
  25.         if(buketNode->key==0) 
  26.         { 
  27.             buketNode->next=node; 
  28.             bucketTable[index]->key++; 
  29.         }else
  30.             while(buketNode->next!=NULL && buketNode->next->key<=node->key)// 在该桶中的链表中寻找自己的位置 
  31.                 buketNode=buketNode->next; 
  32.             node->next=buketNode->next;                    // 链表的插入操作 
  33.             buketNode->next=node; 
  34.             bucketTable[index]->key++; 
  35.         } 
  36.         int pos=0; 
  37.         for(int t=0;t<bucketSize;t++) 
  38.         { 
  39.             for(Node *p=bucketTable[t]->next;p!=NULL;p=p->next) 
  40.             { 
  41.                 a[pos++]=p->key; 
  42.             } 
  43.         } 
  44.     } 


10,基数排序

11,位图排序

今后几天 会详细总结。。。。。