必备的几种排序算法

本文详细介绍了四种常见的排序算法:快速排序、直接插入排序、归并排序和堆排序。针对每种算法的特点进行了阐述,并提供了选择排序方法的一般规则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/*
 (一).快速排序
 是对起泡排序的一种改进,通过一趟排序将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键
 字小,则可分别对这两部分继续进行排序,以达到整个序列有序.
 交换顺序表L中子表L.r[low..high]的记录,使枢轴记录到位,并返回其所在位置,此时在它之前(后)的记录均不大(小)于它
 时间复杂度为 n*logn,其平均性能最好,若初始记录序列按关键字有序或基本有序,快速排序将锐化为起泡排序
 */
int  Partition(int SortData[], int low, int high)
{
     int tmpData = SortData[low];//用于子表的第一个记录作枢轴记录
     int temp=0;
 
     while ( low<high )
     {
         //从表的两端交替的向中间扫描
         while (low<high && SortData[high]>=tmpData)
         {
             high--;
         }
         //将比枢轴记录小的记录移到低端
         SortData[low] =SortData[high];
 
         while (low<high && SortData[low]<=tmpData)
         {
             low++;
         }
         //将比枢轴记录大的记录移到高端
         SortData[high] =SortData[low];
     }
     //枢轴记录到位
     SortData[low] =tmpData;
 
     return low;//返回枢轴所在位置
 }
 
 void QuickSortData(int SortData[], int low, int high)
 {
     int offset;
 
     if ( low<high )
     {
         offset = Partition(SortData, low, high);
         QuickSortData(SortData, low, offset-1);//对前半个子表递归排序
         QuickSortData(SortData, offset+1, high);//对后半个子表递归排序
     }
 }

/*
 (二).直接插入排序
 算法:经过i-1遍处理后,L[1..i-1]己排好序。第i遍处理仅将L[i]插入L[1..i-1]的适当位置,
 使得L[1..i]又是排好序的序列。要达到这个目的,我们可以用顺序比较的方法。
 首先比较L[i]和L[i-1],如果L[i-1]<=L[i],则L[1..i]已排好序,第i遍处理就结束了;
 否则交换L[i]与L[i-1]的位置,继续比较L[i-1]和L[i-2],直到找到某一个位置j(1≤j≤i-1),
 使得L[j] ≤L[j+1]时为止
 优点:移动元素次数少,只需要一个辅助空间
 时间复杂度n*n
 当待排序记录的数量n很小时,这是一种很好的排序方法。但是n很大时,则不适合
 */
void InsertSortData(int SortData[], int Length)
 {
     int tmpData =0;
     int i=0;
     int j=0;
 
     for(i=1; i<Length; i++)
     {
         if ( SortData[i] <SortData[i-1])
         {
             tmpData =SortData[i];
             //数据往后移动
             for (j=i-1; j>=0 && tmpData<SortData[j]; j--)
             {
                 SortData[j+1] =SortData[j];
             }
             //将数据插入到j+1位置
             SortData[j+1] =tmpData;
         }
     }
     return;
 }

/*
(三).归并排序
左边小左边,左边++;右边小取右边,右边++*/
template<typename T>
void merge(T array[], int low, int mid, int high)
{
	int k;
	T *temp = new T[high-low+1]; //申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
	int begin1 = low;
	int end1 = mid;
	int begin2 = mid + 1;
	int end2 = high;
	
	for (k = 0; begin1 <= end1 && begin2 <= end2; ++k)  //比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
	{
		if(array[begin1]<=array[begin2])
			temp[k] = array[begin1++];
		else
			temp[k] = array[begin2++];   
	}
		
    if(begin1 <= end1) //若第一个序列有剩余,直接拷贝出来粘到合并序列尾
		memcpy(temp+k, array+begin1, (end1-begin1+1)*sizeof(T));
    if(begin2 <= end2) //若第二个序列有剩余,直接拷贝出来粘到合并序列尾
		memcpy(temp+k, array+begin2, (end2-begin2+1)*sizeof(T));
    memcpy(array+low, temp, (high-low+1)*sizeof(T));//将排序好的序列拷贝回数组中

    delete temp;
}

template<typename T>
void merge_sort(T array[], unsigned int first, unsigned int last)
{
	int mid = 0;
	if(first<last)
	{
		mid = first/2 + last/2;
		merge_sort(array, first, mid);
		merge_sort(array, mid+1,last);
		merge(array,first,mid,last);
	}
}

/*
(四).堆排序
a[s]>=a[2*s] && a[s]>=a[2*s+1]*/
template<typename T>
void Max_heap(T a[],int S,int len)
{
	int l = 2*S;
	int r = 2*S+1;
	int maxI = S;
	T elem;
	if (l < len && a[l] > a[maxI])
	{
		maxI = l;
	}
	if (r < len && a[r] > a[maxI])
	{
		maxI = r;
	}
	if (maxI != S)
	{
		elem = a[S];
		a[S] = a[maxI];
		a[maxI] = elem;
		Max_heap(a,maxI,len);
	}
}

template<typename T>
void HeapSort(T a[],int n)
{
	int i;
	T elem;
	for (i = n/2;i>=0;i--)
	{
		Max_heap(a,i,n);
	}
	for (i= n-1;i>=1;i--)
	{
		elem = a[0];
		a[0] = a[i];
		a[i] = elem;
		n = n-1;
		Max_heap(a,0,n);
	}
}


各种内排序方法的选择

1.从时间复杂度选择:

对元素个数较多的排序,可以选快速排序、堆排序、归并排序,元素个数较少时,可以选简单的排序方法。

2.从空间复杂度选择:

尽量选空间复杂度为O1)的排序方法,其次选空间复杂度为O(log2n)的快速排序方法,

最后才选空间复杂度为On)二路归并排序的排序方法。 

3.一般选择规则:

(1)当待排序元素的个数n较大,排序码分布是随机,而对稳定性不做要求时,则采用快速排序为宜。

(2)当待排序元素的个数n大,内存空间允许,且要求排序稳定时,则采用二路归并排序为宜。

(3)当待排序元素的个数n大,排序码分布可能会出现正序或逆序的情形,且对稳定性不做要求时,

则采用堆排序或二路归并排序为宜。

(4)当待排序元素的个数n小,元素基本有序或分布较随机,且要求稳定时,则采用直接插入排序为宜。

(5)当待排序元素的个数n小,对稳定性不做要求时,则采用直接选择排序为宜,若排序码不接近逆序,

也可以采用直接插入排序。冒泡排序一般很少采用。 


各种排序方法的比较


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值