五种常用排序

       最近在看数据结构,想把几个简单的排序在过一遍,发现还没那么容易,最简单的冒泡排序代码没那么容易敲出来。下面把5种排序复习一下:

1. 冒泡排序:

   冒泡排序是最简单也是最常用的排序方法。其基本思想是(以升序为例):将序列看成一排竖着的气泡。最后一个元素与倒数第二个元素进行比较,小的往前拱,再将倒数第二个元素与倒数第三个元素比较,小的往前拱,...这样一次外循环后,第一个元素就是序列最小的元素。n次外循环后就将序列排列好了。具体的程序如下:

 int temp;

 int num=0;

 int a[10]={13,2,5,18,7,12,9,10,15,6};

 for(int i=0;i<10;i++)

  for(int j=9;j>=i;j--)

  {

   num++;

   if (a[j]<a[j-1])

   {

    temp=a[j];

    a[j]=a[j-1];

    a[j-1]=temp;

   }

  }

  

 for (i=0;i<10;i++)

 {

  printf("%d  ",a[i]);

 }

 printf("\n");

 printf("%d\n",num);

  


 

改进后的冒泡排序算法:

 冒泡排序是每次将最小的数往上推(通过由下往上的两两比较),但有的时候序列已经有一定顺序了,每次再去比较就会浪费时间。所以可以设立一个flag,当某一次比较没有数据发生交换时,证明已经排好了,后面的就不去用再继续了。具体程序如下:

 

int temp;

 int num=0;

 bool flag=false;

 int a[10]={13,2,5,18,7,12,9,10,15,6};

 for(int i=0;i<10 && !flag;i++)

 {

  flag=true;

  for(int j=9;j>=i;j--)

  {

   flag=false;

   num++;

   if (a[j]<a[j-1])

   {

    temp=a[j];

    a[j]=a[j-1];

    a[j-1]=temp;

   }

  }

 }  

     for (i=0;i<10;i++)

  {

   printf("%d  ",a[i]);

  }

 printf("\n");

 printf("%d\n",num);


 

 

2.直接插入排序:

    直接插入排序的思想是:把一个数插入到一个有序序列中,原先的序列已经是排好的了,所以要先要找到该元素的位置,将原先的序列移动,然后再将数字插入。代码如下:

 

if(Is_Full(pArr))

  return false;

 if(pos<1 || pos>pArr->cnt+1)

  return false;

 for (int i=pArr->cnt-1;i>=pos-1;i--)

     pArr->pBase[i+1]=pArr->pBase[i];

 pArr->pBase[pos-1]=val;

 pArr->cnt++;


 

 直接插入也可以改进,改进后的插入排序时边比较边移动的,当找到合适的位置时就直接插入。代码如下:

if(Is_Full(pArr))

  return false;

 int pos=pArr->cnt-1;

 for (int i=pos;i>=0;i--)
 {

  if (val<pArr->pBase[i])

  {

   pArr->pBase[i+1]=pArr->pBase[i];

  }

  else

  {

   pArr->pBase[i+1]=val;

   pArr->cnt++;

         return true; 

  }

 }

 pArr->cnt++;


 

3.快速排序:

    快速排序是效率比较高的排序算法,其又细分为几种,不过基本思想是一样的。只要思想是:选定序列的第一个数,先找到该数的真实位置,然后将序列以这个数分为两个部分,左边又选定第一个数,找到该数的真实位置,右边也选定第一个数,找到该数的真实位置,....不断找到子序列第一个数的真实位置,实际上是一个递归的过程。至于第一个数的真实位置时如何确定的,是同过两个标记来实现的,每次都与这个数比较进行移动或者赋值,具体见代码:

#include <stdio.h>

void QuickSort(int* a,int low,int high); //数组名和指针可以互用

int FindPos(int* a,int low,int high); //找到第一个元素的真实位置

int main()

{

 int a[6]={1,3,0,2,5,4};

 QuickSort(a,0,5); //low 为 0,high 为 5

 for(int i=0;i<6;i++)

  printf("%d ",a[i]);

 printf("\n");

 return 0;

}

//递归实现

//快速排序的思想:先找到第一个元素的真实位置,在将其左右两部分分成两个序列,继续查找序列的第一个元素的真实位置

void QuickSort(int* a,int low,int high)

{

 int pos;

 if (low<high)

 {

  pos=FindPos(a,low,high);

  QuickSort(a,low,pos-1);

  QuickSort(a,pos+1,high);

 }

}

int FindPos(int*a,int low,int high)

{

 int val=a[low]; //临时变量val存储第一个元素的值,用来比较

 while (low<high)

 {

  while (low<high && a[high]>val) //右部分比val大就移动

   high--; 

  a[low]=a[high]; //否则就把值赋给a[low]

  while(low<high && a[low]<val) //左半部分比val小就移动

   low++;

  a[high]=a[low]; //否则就赋给a[high]

 }

 a[low]=val; //最后low于high就指向了第一个元素的真实位置

 return low;

}


 4.选择排序

     选择排序与冒泡排序类似;其基本思想是:假设开始有0个有序数和n个无序数,经过一次排序后就变成了1个有序数和n-1个有序数了...,每一次排序都使有序数的个数+1,无序数的个数减一。主要代码如下:

int temp,b;
 int num=0;
 int a[10]={13,2,5,18,7,12,9,10,15,6};
    for(int i=0;i<10;i++)
 {
  temp=i;
  for(int j=i+1;j<10;j++)
   if(a[temp]>a[j])
   {
       temp=j;
   }
  if (i!=temp)
  {
   num++; //当n较小时,num的次数比冒泡排序小
   b=a[temp];
   a[temp]=a[i];
   a[i]=b;
  }
    }

*当n的次数较小时,选择排序比冒泡排序快。

 

5.归并排序

    归并排序相对来说比较复杂,也没有多研究,就看一下大概的思想和代码。主要的思想是:将序列等分排序,将序列分为两个子序列,再排好两个子序列后将其合并起来。子序列的排序有和主序列类似,也是将其分为两个子序列,...最后将所有序列归并起来即可(也是利用了递归的方法)。主要代码:

#include<stdio.h>
// 一个递归函数
void mergesort(int *num,int start,int end);
// 这个函数用来将两个排好序的数组进行合并
void merge(int *num,int start,int middle,int end);
int main(){	
	// 测试数组    
	int num[10]= {12,54,23,67,86,45,97,32,14,65};	
	int i;
	// 排序之前	
	printf("Before sorting:\n");	
	for (i=0; i<10; i++)    
	{		
		printf("%3d",num[i]);	
	}	
	printf("\n");	
	// 进行合并排序	
	mergesort(num,0,9);	

	printf("After sorting:\n");	
	// 排序之后	
	for (i=0; i<10; i++)    
	{		
		printf("%3d",num[i]);
	}	
	printf("\n");	
	return 0;
}
//这个函数用来将问题细分
void mergesort(int *num,int start,int end)
{	
	int middle;	
	if(start<end)   
	{		
		middle=(start+end)/2;	
		// 归并的基本思想		
		// 排左边		
		mergesort(num,start,middle);		
		// 排右边	
		mergesort(num,middle+1,end);		
		// 合并	
		merge(num,start,middle,end);	
	}
}
//这个函数用于将两个已排好序的子序列合并
void merge(int *num,int start,int middle,int end)
{	
	int n1=middle-start+1; 	
	int n2=end-middle;	
	// 动态分配内存,声明两个数组容纳左右两边的数组	
	int *L=new int[n1+1];	
	int *R=new int[n2+1];	
	int i,j=0,k;	
	//将新建的两个数组赋值	
	for (i=0; i<n1; i++)    
	{		
		*(L+i)=*(num+start+i);
	}
	// 哨兵元素   
	*(L+n1)=1000000;	
	for (i=0; i<n2; i++)   
	{		
		*(R+i)=*(num+middle+i+1);	
	}	
	*(R+n2)=1000000;	
	i=0;	
	// 进行合并	
	for (k=start; k<=end; k++)    
	{		
		if(L[i]<=R[j])        
		{			
			num[k]=L[i];			
			i++;	
		}		
		else        
		{			
			num[k]=R[j];		
			j++;		
		}	
	}	
	delete [] L;	
	delete [] R;
}


 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值