常见的排序算法

今天计划整理一下常见的几种排序算法

冒泡法:

第p次冒泡,会在剩下的n-p个数字钟找到最小的min值,将其放在剩下的n-p个数字的最前面。

我的方法是找剩下中的最小值放到开头,而不是两个相邻值互相交换

代码如下:

template<typename comparable>
void maopaosort(vector<comparable>& a)
{
    comparab tmp;
    int pos;
    for(int i=0;i<a.size()-1;i++)
    {   
        tmp=a[i];
        pos=i;
        for(int j=i+1;j<a.szie();j++)
        {   
            if(a[j]<tmp)
            {
                tmp=a[j];
                pos=j;  
            }   
        }
        a[i]=a[pos];
        a[pos]=tmp;    
    }
}

标准的排序算法是,每一轮都会有一个最大值沉到数组的底部。

标准的冒泡算法如下:

void bubble_sort(int a[], int n)
{
    int i, j, temp;
    for (j = 0; j < n - 1; j++)
        for (i = 0; i < n - 1 - j; i++)
        {
            if(a[i] > a[i + 1])
            {
                temp = a[i];
                a[i] = a[i + 1];
                a[i + 1] = temp;
            }
        }
}


插入排序

算法思想:

第p次时,将位于p的元素插入到前面p个已经排序好的元素序列的适当位置。

代码如下:

template<typename com>
void insertsort(vector<com>& a)
{
        int j;
        for(int p=1;p<a.size();p++){
            com tmp=a[p];
            for(j=p;j>0&&tmp<a[j-1];j--)
                       a[j]=a[j-1];
                a[j]=tmp;
         }
}

这里容易出错:for语句结束后j会自动减去1,将tmp赋值给a[j]即可,j是位于for(j)循环之外定义的。


谢尔排序(shell sort)

缩减增量排序

谢尔排序的性能在实践中是完全可以接受的。编程的简单特点是的她称为对适度的大量输入数据经常选用的算法。o(n的3/2次幂)的边界适用于广泛的增量序列。

shell排序推荐的增量序列为h=【n/2】。每次排序都是一次插入排序。

代码如下:

template<typename com>
void shellSort(vector<com>& a)
{
    for(int gap=a.size()/2;gap>0;gap=/2)
    {   
        for(int i=gap;i<a.size();i++)
        {
            int j=gap;
            com temp=a[gap];
            for(;j>0&&temp<a[j-gap];j=-gap)
                a[j]=a[j-gap]
            a[j]=temp;
        }
    }   
}
可以看到第二层的for循环就是插入排序。

归并排序(mergesort)

时间复杂度:O(nlogn)

空间复杂度:虽然归并排序运行时间为O(nlogn),但是很难用于主存排序,主要问题在于合并两个排序的表时,需要线性附加内存,在整个算法排序过程中还要花费将数据复制到临时数组,再复制回来泽阳一些附加操作,结果就是严重减慢了算法速度

算法思想:基本操作是合并两个已经排序的表。

递归编写的归并排序如下:

template<typename comparable>
void mergesort(vector<comparable>& a)
{
         vector<comparable> temp(a.size());
         mergesort(a,temp,0,a.size()-1);
}

template<typename comparable>
void mergesort(vector<comparable>& a,vector<comparable>& tempArry,int left,int right)
{
      if(left<right)
      {
             int center=(left+right)/2;
             mergesort(a,tempArry,left,center-1);
             mergesort(a,tempArry,center,right);
             merge(a,tempArry,left,cneter,right);
      }
}
template<comparable>
void merge(vector<comparable>& a,vector<comparable>& tempArry,int leftPos,int rightPos,int rightEnd)
{
           int leftEnd=rightPos-1;
           int tempPos=leftPos;
           int numElements=rightPos-leftPos+1;
           while(leftPos<=leftEnd&&rightPos<=rightEnd)
                    if(a[leftPos]<a[rightPos])
                            tempArry[tempPos++]=a[leftPos++];
                    else
                          tempArry[tempPos++]=a[rightPos++];
                  while(leftPos<=leftEnd)
                           tempArry[tempPos++]=a[leftPos++];
                 while(rightPOs<rightEnd)
                          tempArry[tempPos++]=a[rightPos++];
            for(int i=0;i<numElements;i++,rightEnd--)
                   a[rightEnd]=tempArry[rightEnd]; 
}

归并排序非递归代码如下:

思想:分为两个步骤,两两合并,onePass:在数组上将亮亮合并应用一下,步长每次翻倍。

void mergeTwo(vector<int>& a,vector<int>& b,int leftPos,int len,int rightEnd)
{
	int rightPos=leftPos+len;
	int leftEnd=leftPos+len-1;
	int bPos=leftPos;
	int numElements=rightEnd-leftPos+1;
	while(rightPos<=rightEnd&&leftPos<=leftEnd)
	{
		if(a[leftPos]<a[rightPos])
			b[bPos++]=a[leftPos++];
		else
			b[bPos++]=a[rightPos++]
	}
	while(rightPos<=rightEnd) 
		b[bPos++]=a[rightPos++];
	while(leftPos<=leftEnd)
		b[bPos++]=a[leftPos++];
	for(int i=0;i<numElements;i++)
		a[rightEnd--]=b[rightEnd--];
}

void mergeOnePass(vector<int>& a,vector<int>& b)
{
	for(int len=1;len<=a.size()/2;len*=2)
	{
		int i=0;
		for(;i+2*len<=a.size();i=i+len*2)
			mergeTwo(a,b,i,len,i+2*len);
		if(i+len<a.size())
			mergeTwo(a,b,i,len,.size()-1);
		else
			;
	}
}


快速排序(quicksort)

思想:

1、找到枢纽元素(下面代码中的枢纽元素选取为i,开头、中间、结尾三个中的中值)

2、将大于和小于枢纽值的元素分成两拨

3、递归对分成的两拨元素进行快排;

无额外空间消耗,时间复杂度为O(nlogn)

代码如下:

const int median(vector<int>& a,int left,int right)
{
	int mid=(left+right)/2;
	if(a[mid]<a[left])
		swap(a[left],a[right]);
	if(a[right]<a[left])
		swap(a[left],a[right]);
	if(a[mid]<a[right])
		swap(a[mid],a[right]);
	swap(a[right-1],a[mid]);
	return a[right-1];
}

void quicksort(vector<int>& a,int left,int right)
{
	if(left+10<=right)
	{
		int midval=midan(a,left,right);
		int leftPos=left,rightPos=right-1;
		for(;;)
		{
			while(a[++leftPos]<a[right-1]){}
			while(a[right-1]<a[--rightPos]){}
			if(leftPos<rightPos)
				swap(a[leftPos],a[rightPos]);
			else
				break;
		}
		swap(a[right-1],a[leftPos]);
		quicksort(a,left,leftPos-1);
		quicksort(a,leftPos+1;right);
	}
	else
		;	//shell sort
}

算法在取中值时多了一些额外步骤节省了一次对比,再有就是for(;;)中,while(a[++leftPos])会自动跳过等于中值的情况而不会无限循环。


堆排序(heapsort)

使用了堆的性质:

最大堆:根节点比任何一个儿子节点的值都大。堆的下滤操作可以处理。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值