c/c++各种排序

原创 2012年03月29日 11:51:28

一、各种排序方法的时间、空间复杂度情况

1、  直接插入排序:比较次数 最少n-1次;最多(n-1)(n+2)/2 ;移动次数 最少0; 最多(n-1)(n+4)/2 使用一个辅助存储空间,是稳定的排序;

2 、 折半插入排序:比较次数 最少与最多同,都是n*log2n(其中2为底,下边表示同), 移动次数 最少0,最多时间复杂度为O(n2);(n的平方,以下也如此表示); 使用一个辅助

        存储空间,是稳定的排序;

3 、冒泡排序: 比较最少为:n-1次,最多时间复杂度表示为o(n2); 移动次数最少为0,最多时间复杂度表示为O(n2); 使用一个辅存空间,是稳定的排序;

4 、简单选择排序: 比较次数没有多少之分,均是n(n-1)/2; 移动次数最少为0,最多为3(n-1); 使用一个辅存空间,是稳定的排序;

5 、快速排序:比较和移动次数最少时间复杂度表示为O(n*log2n); 比较和移动次数最多的时间复杂度表示为O(n2); 使用的辅助存储空间最少为log2n,最多为n的平方;是不稳定

       的排序;

6 、堆排序: 比较和移动次数没有好坏之分,都是O(n*log2n); 使用一个辅存空间,是不稳定的排序;

7、 2-路归并排序:比较和移动次数没有好坏之分,都是O(n*log2n); 需要n个辅助存储空间,是稳定的排序;

二、各种排序的c/c++实现

#include <cstdlib>
#include <iostream> 
#include <cstring>
#include <ctime>
using namespace std;
const int SIZE = 100000;
//打印数组元素 
void print(const int * const t);
//交换两元素 
void swap(int *p,int *q);
/*
  插入排序
  基本思想:
           1、从第一个元素开始,该元素可以认为已经被排序
           2、取出下一个元素,在已经排序的元素序列中从后向前扫描
           3、如果该元素(已排序)大于新元素,将该元素移到下一位置
           4、重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
           5、将新元素插入到该位置中
           6、重复步骤2~5         
*/ 
void InsertSort(int* const t);
/*
  折半插入排序
  基本思想:  利用前i个元素为已经排序的特点;进行折半查找插入位置
           1、取序列的t[midd]中间位置元素与目标元素t[i]比较,如果
              t[i]>t[midd],则在[midd+1,high]查找,否则在[low,midd-1]
           2、重复1,直至找到该位置 
           3、将high到i的元素右移
           4、将t[i]元素插入high+1位置
           5、重复1-4,直到i=size-1 
*/
 
void BInsertSort(int* const t); 
/*
  希尔排序 
  基本思想:

          1、先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。
             所有距离为dl的倍数的记录放在同一个组中
          2、先在各组内进行直接插入排序;
          3、然后,取第二个增量d2<d1重复上述的分组和排序,
          4、重复1-3,直至所取的增量dt=1(dt<dt-l<…<d2<d1)
          5、最后的进行dt=1的插入排序,结果即为顺序的 
*/
void ShellSort(int * const t,int dk=1);

//一次希尔插入排序 
void ShellInsert(int * const t,int dk=1);

/*
  冒泡排序
  基本思想:对相邻的两个数进行比较交换,将比较大的那个数右移。 
           
          1、第一轮将t[0]、t[1]进行比较,若t[i]>t[i+1],则交换,
             直到第n-1个记录和第n个记录比较过为止 
          2、重复1,直至第n-i-1个记录和第n-i个记录比较过为止
*/
void BuddleSort(int * const t);
/*
  快速排序
  基本思想:
  1、分治法的基本思想: 
     将原问题分解为若干个规模更小但结构与原问题相似的子问题。
     递归地解这些子问题,然后将这些子问题的解组合为原问题的解。

  2、快速排序的基本思想
        设当前待排序的无序区为R[low..high],利用分治法可将快速排序的基本思想描述为:
     ①分解: 
     在R[low..high]中任选一个记录作为基准(Pivot),以此基准将当前无序区划分为左、右
      两个较小的子区间R[low..pivotpos-1)和R[pivotpos+1..high],并使左边子区间中所有
      记录的关键字均小于等于基准记录(不妨记为pivot)的关键字pivot.key,
      右边的子区间中所有记录的关键字均大于等于pivot.key,
      而基准记录pivot则位于正确的位置(pivotpos)上,它无须参加后续的排序。
      注意:
     划分的关键是要求出基准记录所在的位置pivotpos。
      划分的结果可以简单地表示为(注意pivot=R[pivotpos]):
     R[low..pivotpos-1].keys≤R[pivotpos].key≤R[pivotpos+1..high].keys
                  其中low≤pivotpos≤high。
     ②求解: 
     通过递归调用快速排序对左、右子区间R[low..pivotpos-1]和R[pivotpos+1..high]快速排序。
     
     ③组合: 
     因为当"求解"步骤中的两个递归调用结束时,其左、右两个子区间已有序。
      对快速排序而言,"组合"步骤无须做什么,可看作是空操作。 

*/
void QuickSort(int *const t,int low,int high); 
/*
  选择排序
  基本思想:
           每一趟在n-i+1 (i=0,1,2,...,n-1)个记录中选取最小的记录作为有序序列中的第i个记录
           
            

*/
void SelectSort(int *const t); 
/*
  堆排序
  基本思想:
          堆的定义:满足如下约束的 n 个关键字序列 Kl,K2,…,Kn 称为堆,1 ≤ i ≤ n/2,
                   (1) ki ≤ K2i 且 ki ≤ K2i+1 (小根堆)   或
                   (2) Ki ≥ K2i 且 ki ≥ K2i+1 (大根堆)

*/
void HeapSort(int *const t);
//将序列建为一个堆 
void HeapAdjust(int *const t,int s,int m); 
/*
	归并排序
	基本思想:
					假设初始序列为n个记录,则可将序列看成n个有序的序列,每个序列的长度为1,
					然后进行两两归并,得到n/2个长度为2或者1的序列;再两两归并。。。,直到
					得到一个长度为n的序列为止 
*/
void MergeSort(int * const sr,int left,int right);
//将有序的sr[i..m]和sr[m+1..n]归并为有序的tr[i..n] 
void Merge(int * const sr,int left,int midd,int right); 

int main() 
{ 
    int a[SIZE];
    srand((unsigned) time(0));
    for(int i=1;i<SIZE;i++){
         a[i] = rand()%SIZE;            
    }
    a[0] = SIZE-1;
  /*
    cout<<"排序前,SIZE:"<<SIZE<<endl;
    print(a);

    InsertSort(a);
    cout<<endl<<"选择排序后:"; 
    cout<<"比较次数:"<<count1<<endl;
    print(a);
    
    BInsertSort(a); 
    cout<<endl<<"则半插入排序后:"; 
    cout<<"比较次数:"<<count2<<endl;
    print(a);
    
    
    ShellSort(a);
    cout<<endl<<"希尔排序排序后:"; 
    print(a);
    cout<<"比较次数:"<<count3<<endl;
  
    BuddleSort(a); 
    cout<<endl<<"冒泡排序后:"<<endl;
     
    QuickSort(a,0,SIZE-1);
    cout<<endl<<"快速排序后:"<<endl;
    print(a);
    cout<<"比较次数:"<<count5<<endl;
  */
    clock_t start,end;       
    start = clock();       
    //QuickSort(a,0,SIZE-1);
    //BuddleSort(a);
   // ShellSort(a);
    //InsertSort(a);
    //BInsertSort(a);
   // SelectSort(a);
    //HeapSort(a);
    MergeSort(a,0,SIZE-1);
		end = clock();  
    //cout<<endl<<"快速排序后:"<<endl;
       
    cout<<"程序运行时间:"<<end-start<<endl;
    //print(a);
    system("pause");
    return 0; 
}  
//插入排序 

void InsertSort(int * const t){
     //要插入的元素 
     int temp = 0;
     for(int i=1;i<SIZE;i++)
     {
          temp = t[i];
          int j=i-1;
          //寻址插入位置,同时将元素后移 
          for(;j>=0&&temp<t[j];j--)
          {
               t[j+1]=t[j];
          }
          //插入 
          t[j+1]=temp;
     }
}
//则半插入排序 
void BInsertSort(int* const t)
{
     int temp = 0;//要插入的元素 
     int low = 0;//查找范围的开端 
     int high = 0; //末端
     int midd = 0;//中部 
     for(int i=1;i<SIZE;i++)
     {
          
          high = i-1;
          temp = t[i];
          while(low<=high)
          {
             midd = (high+low)/2;
             if(t[i]<=t[midd])
             {
                 high = midd-1;
             }
             else{
                 low = midd+1;     
             }
            
          }
          for(int j=i-1;j>high+1;j--)
          {
              t[j+1] = t[j];
              
          }
          t[high+1] = temp;
     } 
 
} 
//希尔排序,也称增量递减排序 
void ShellSort(int * const t,int dk)
{
     //进行不同增量的的希尔插入排序 
     for(dk=SIZE/2;dk>2;dk/=2)
     {
           ShellInsert(t,dk);
     }   
     //最后进行增量为1的排序 
     ShellInsert(t,1); 
 
}
//一趟希尔插入排序 
void ShellInsert(int * const t,int dk)
{
     int temp = 0;//目标值 
     for(int i = dk;i<SIZE;i++)
     {
             temp = t[i];
             int j = i-dk;
             //找到要插入的位置,并将序列右移 
             for(;j>=0&&temp<t[j];j-=dk)
             {
                t[j+dk]=t[j]; 
             }
             //插入 
             t[j+dk] = temp;      
     } 

} 
//冒泡排序 
void BuddleSort(int * const t)
{
     for(int i=0;i<SIZE;i++)
     {
	       //设置一个标志,当这一轮没有元素交互时,代表序列已经排序好,不用继续比较交换了 
	       bool flag = false;
	       for(int j=0;j<SIZE-i-1;j++)
	       {
	               if(t[j]>t[j+1])
	               {
	                    //将两个元素进行交换                     
	                    swap(&t[j],&t[j+1]);  
	                    flag = true;
	               }
	        
	       }
	       //已经排好序 
	       if(!flag){
	           break;      
	       }
      
     }
}
//快速排序 
void QuickSort(int *const t,int low,int high)
{
     int i=low;
     int j=high;
     int pivotkey=t[low];//将第一个值作为枢纽 
     if(i<j)
     {     
          while(i<j)
          {
              //查找高端比枢纽小的值位置j 
              while(i<j&&t[j]>=pivotkey)
              {
                   --j;
              } 
              //将小于枢纽的值与低端交换 
              swap(&t[i],&t[j]);
              //查找低端比枢纽大的值位置i 
              while(i<j&&t[i]<=pivotkey)
              {
                   ++i;
              }
              //将小于枢纽的值与低端交换
              swap(&t[i],&t[j]);   
          }
          //对低子表进行递归排序 
          QuickSort(t,low,i-1);
          //对高子表进行递归排序 
          QuickSort(t,i+1,high); 
     }
}
//简单选择排序
void SelectSort(int *const t)
{
     //最小值索引 
     int minIndex = 0;
     for(int i=0;i<SIZE;i++)
     {
         //将目标值索引设置为最小 
         minIndex = i;
         //查找剩下序列的最小值索引 
         for(int j=i;j<SIZE;j++)
         {
                 if(t[j]<t[minIndex])
                 {
                    //找到比原来最小值小的,则重新改变最小值索引 
                    minIndex = j;   
                 } 
          
         } 
         //交换两个记录 
         swap(&t[i],&t[minIndex]);
     } 
} 
//堆排序 
void HeapSort(int *const t)
{
		 int LEN = t[0];
    	 //从最后一个不是叶子节点的节点开始构造 
		 for(int i=LEN/2;i>0;i--)
		 {
		 		HeapAdjust(t,i,LEN);
		 } 
		 for(int j=LEN;j>1;j--)
		 {
				//将根节点与最后一个节点交换 
		 		swap(&t[1],&t[j]);
		 		//重新调整 
				HeapAdjust(t,1,j-1);
     } 
}
//将序列建为一个堆 
void HeapAdjust(int *const t,int s,int m)
{
     //子树根节点值 
		 int temp = t[s];
  	 //将子树进行调整 
		 for(int j=2*s;j<m;j*=2)
     {
			 
				if(j<m&&t[j]<t[j+1]) 
				{
					  j++;		
				}		
				//子树已经排序,则跳出循环 
				if(t[j]<temp)
				{
					break;	
				}
				//交换子节点与根节点的值 
				swap(&t[s],&t[j]);
				//将该子节点作为根节点,再次进行调整 
				s=j;
		 }
} 

//将sr[left..right]归并排序为tr[left..right] 
void MergeSort(int * const sr,int left,int right)
{
		int midd = 0;
		if(left<right)
		{
				//将序列从中点分割为两个子序列 
				midd = (left+right)/2;
				//归并排序左序列 
				MergeSort(sr,left,midd);
				//归并排序右序列 
				MergeSort(sr,midd+1,right);
				//将两个序列合并 
				Merge(sr,left,midd,right);
		} 
}

//将有序的sr[i..m]和sr[m+1..n]归并为有序的tr[i..n] 
void Merge(int * const sr,int left,int midd,int right)
{
			int len = right-left+1; 
			int *tr = new int[len];
			int k = 0;
			int j = midd+1;
			int i = left;
			while(i<=midd&&j<=right)
			{
				tr[k++]=(sr[j]>sr[i])?sr[i++]:sr[j++];
			}
			//将剩余的sr[i..m]复制到tr 
			while(i<=midd)
			{
				tr[k++]=sr[i++];
			}
			//将剩余的sr[j..m]复制到tr 
			while(j<=right)
			{
				tr[k++]=sr[j++];	
			}
			//将合并好的序列值拷贝回原序列中 
			for(int p=0,i=left;p<len;p++,i++)
			{
				sr[i] = tr[p];
			}
			delete[] tr;
}
//打印 
void print(const int* const t)
{
  int i=0;
  while(i<SIZE)
  {
     cout<<"  "<<t[i++]; 
     if(i%15==0)
     {
      cout<<endl;
     }
  } 
  cout<<endl;
} 
//交换两元素 
void swap(int *p,int *q)
{
     int tem = 0;
     tem = *p;
     *p = *q;
     *q = tem;
}


C/C++ 排序

  • 2013年06月05日 21:51
  • 2.93MB
  • 下载

十二之再续:快速排序算法之所有版本的c/c++实现

十二之再续、快速排序算法所有版本的c/c++实现作者:July、二零一一年三月二十日。出处:http://blog.csdn.net/v_JULY_v。------------------------...
  • v_JULY_v
  • v_JULY_v
  • 2011年03月20日 15:52
  • 78998

C-C++排序算法总结

  • 2010年03月27日 13:06
  • 3KB
  • 下载

c/c++各种排序

  • 2012年10月12日 11:47
  • 7KB
  • 下载

由PAT 1015德才论(C/C++)引发的关于快速排序qsort的使用注意事项

通过PAT平台的一道题目,结合自身的解题过程,来解释快速排序qsort的使用及其注意事项...

c、c++ 数据结构排序

  • 2011年07月08日 17:03
  • 85KB
  • 下载

[C/C++基础知识] 一篇就让你彻底搞懂qsort快速排序的文章

最近在做LeetCode的题目、面试和笔试后发现经常考察快速排序的知识。通过这篇文章介绍,能让你彻底的了解和学习快排,主要从一下三个部分进行介绍: 一.C语言实现qsort快速排序 ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:c/c++各种排序
举报原因:
原因补充:

(最多只允许输入30个字)