常用排序及性能分析(未完)

本文详细介绍了五种经典的排序算法:插入排序、归并排序、堆排序、快速排序和冒泡排序。每种算法都提供了具体的实现代码,并通过实验对比了它们在不同数据规模下的性能表现。

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

(代码基于linux环境,完整代码工程附下载链接,仅供学习,如有错误,欢迎指正。)

一、插入排序

        插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序,时间复杂度为O(n^2)。插入算法把要排序的数组分成两部分:第一部分包含已排好序的数,第二部分为未排好的,每次将未排序部分的第一个数插入到已排序部分合适的位置,直到第二部分没有数据。插入排序在数目较少时性能比较好。

/* 将未排序部分第一个数iValue插入到已排序数组[0,iCurrentCnt-1] */
static void insert_one(int *pArray, int iCurrentCnt, int iValue)
{
	int iLoop0 = 0;
	int iLoop1 = 0;
	
	/* 找到插入位置 */	
	iLoop0 = iCurrentCnt;
	while(iLoop0>0 && iValue<pArray[iLoop0-1])
	{
		iLoop0--;
	}

	/* 将插入位置后的数据后移一个数*/
	for(iLoop1=iCurrentCnt; iLoop1>iLoop0; iLoop1--)
	{
		pArray[iLoop1] = pArray[iLoop1-1];
	}

	pArray[iLoop0] = iValue;

	return;
}

/* pArray:待排序数组,iCnt:待排序数据数量*/
int insert_sort(int *pArray, int iCnt)
{
	int iKey = 0;
	int iLoop0 = 0;
	
	for(iLoop0 = 1; iLoop0 < iCnt; iLoop0++)
	{
		iKey = pArray[iLoop0];		
		insert_one(pArray, iLoop0, iKey);	
	}
	return 1;

}

 

二、归并排序

        归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。时间复杂度O(nlgn)。归并排序是非原地排序,需要额外内存。

 

void merge(int *pArray, int p, int q, int r)
{
	unsigned int sentinel = 99999999;//哨兵
	int *pArrayl = NULL;
	int *pArrayr = NULL;
	int iLoop0 = 0;
	int iLoop1 = 0;
	int iLoop2 = 0;	

	pArrayl = (int *)malloc(sizeof(int)*(q-p+1));//sentinel card add 1
	if (NULL == pArrayl)
	{
		printf("malloc pArrayl fail\n");
		exit(0);
	}
	for(iLoop0 = 0; iLoop0 < q-p; iLoop0++)
	{
		pArrayl[iLoop0] = pArray[p+iLoop0];
	}	
	pArrayl[q-p] = sentinel;	


	pArrayr = (int *)malloc(sizeof(int)*(r-q+1));//sentinel card add 1
	if (NULL == pArrayr)
	{ 
		free(pArrayl);
		printf("malloc pArrayr fail\n");
		exit(0);
	}
	for(iLoop0 = 0; iLoop0 < r-q; iLoop0++)
	{
		pArrayr[iLoop0] = pArray[q+iLoop0];	
	}
	pArrayr[r-q] = sentinel;

	iLoop0 = 0;
	iLoop1 = 0;
	for(iLoop2 = p; iLoop2 < r; iLoop2++)
	{
		if(pArrayl[iLoop0] < pArrayr[iLoop1])
		{
			pArray[iLoop2] = pArrayl[iLoop0];
			iLoop0++;	
		}
		else
		{
			pArray[iLoop2] = pArrayr[iLoop1];
			iLoop1++;
		}

	}

	return;
}

int merge_sort(int *pArray, int p, int iCnt)
{
	int q=0;
	if (p<iCnt-1)
	{
		q = floor((p+iCnt)/2);
		merge_sort(pArray, p, q);
		merge_sort(pArray, q, iCnt);
		merge(pArray, p, q, iCnt);
	}
	return;
}



 

三、堆排序


void Exchange(int *a, int *b)
{
	int iTemp = 0;

	iTemp = *a;
	*a = *b;
	*b = iTemp;

	return;	
}


void max_heapify(int *pArray, int i, int iCnt)
{
	int l = 0;
	int r = 0;
	int largest = 0;

	l = LEFT(i);
	r = RIGHT(i);
	
	//compare left
	if (l <= iCnt && pArray[l-1] > pArray[i])
	{
		largest = l - 1;
	}
	else
	{
		largest = i;
	}
	
	//compare right
	if (r <= iCnt && pArray[r-1] > pArray[largest])
	{
		largest = r - 1;
	}

	if (largest != i)
	{
		Exchange(&pArray[i], &pArray[largest]);
		
		max_heapify(pArray, largest, iCnt);

	}
	
	return;

}

void build_max_heap(int *pArray, int iCnt)
{
	int iLoop0 = 0;
	int iLoopCnt = 0;

	iLoopCnt = floor(iCnt/2);

	for(iLoop0 = iLoopCnt; iLoop0 > 0; iLoop0--)
	{
		max_heapify(pArray, iLoop0-1, iCnt);
	}

	return;
	
}

int heap_sort(int *pArray, int iCnt)
{ 
	int iLoop0 = 0;
	int heapsize = iCnt;

	build_max_heap(pArray, iCnt);
	
	for(iLoop0 = 0; iLoop0 < iCnt - 1; iLoop0++)
	{
		Exchange(&pArray[0], &pArray[heapsize-1]);
		heapsize -= 1;
		max_heapify(pArray, 0, heapsize);		
	}	

	return;

}


四、快速排序

快速排序属于原地排序,时间复杂度O(nlgn),性能非常好。快速排序分两步,首先选择主元,把原数组分为两部分,前面的比主元小,后面比主元大,然后对两部分进行递归处理,递归完了也就是排好序的数组。下面代码实现主元选择数组的第一个元素,称为朴素的快速排序,当数组已经是正排序或逆排序为最坏情况,时间复杂度为O(n^2),类似插入排序。通常避免这种情况采用随机选择主元方法,采用随机数生成器产生主元。递归到后面的时候,待排序数比较少,可以不使用递归而使用其他排序,例如插入排序(在排序数目少时性能较好),这种优化叫做尾递归优化。

int partition(int *pArray, int p, int r)
{
	int iLoop0 = 0;
	int iLoop1 = p;
	int iKey = 0;

	iKey = pArray[r-1];
	for(iLoop0 = p; iLoop0 < r-1; iLoop0++)
	{
		if (pArray[iLoop0] > iKey)
		{
			iLoop0++;
		}
		else
		{
			Exchange(&pArray[iLoop0], &pArray[iLoop1]);		
			iLoop1++;
		}
	}
	Exchange(&pArray[iLoop1], &pArray[r-1]);

	return iLoop1;

}

int quick_sort(int *pArray, int p, int iCnt)
{
	int iLoop;
	int iPartition;

	if (p < iCnt-1)
	{
		iPartition = partition(pArray, p, iCnt);
	
		quick_sort(pArray, p, iPartition);
		quick_sort(pArray, iPartition+1, iCnt);
	}
	else
	{
		return 0;
	}


}



五、冒泡排序

 

int bubble_sort(int *pArray, int iCnt)
{
	int iLoop0 = 0;
	int iLoop1 = 0;
	
	for(iLoop0 = iCnt-1; iLoop0 > 0; iLoop0--)
	{
		for(iLoop1 = 0; iLoop1 < iLoop0; iLoop1++)
		{
			if (pArray[iLoop1] > pArray[iLoop1+1])
			{
				Exchange(&pArray[iLoop1], &pArray[iLoop1+1]);
			}
		}
	}
}



 

代码及性能分析


cnt\time(s)插入排序归并排序堆排序快速排序冒泡排序
100.0000020.0000070.0000020.0000010.000001
1000.0000340.0000420.0000280.0000160.000086
10000.0024530.0004110.0003340.0001820.007766
100000.2231870.0047610.0044950.0023390.761384
10000022.0251670.0541580.0580230.02855176.286659
10000002199.233890.6181930.8456960.3407997657.28906

代码下载:http://download.youkuaiyun.com/detail/dawan2008/5710221


内容概要:本文档为《400_IB Specification Vol 2-Release-2.0-Final-2025-07-31.pdf》,主要描述了InfiniBand架构2.0版本的物理层规范。文档详细规定了链路初始化、配置与训练流程,包括但不限于传输序列(TS1、TS2、TS3)、链路去偏斜、波特率、前向纠错(FEC)支持、链路速度协商及扩展速度选项等。此外,还介绍了链路状态机的不同状态(如禁用、轮询、配置等),以及各状态下应遵循的规则和命令。针对不同数据速率(从SDR到XDR)的链路格式化规则也有详细说明,确保数据包格式和控制符号在多条物理通道上的一致性和正确性。文档还涵盖了链路性能监控和错误检测机制。 适用人群:适用于从事网络硬件设计、开发及维护的技术人员,尤其是那些需要深入了解InfiniBand物理层细节的专业人士。 使用场景及目标:① 设计和实现支持多种数据速率和编码方式的InfiniBand设备;② 开发链路初始化和训练算法,确保链路两端设备能够正确配置并优化通信质量;③ 实现链路性能监控和错误检测,提高系统的可靠性和稳定性。 其他说明:本文档属于InfiniBand贸易协会所有,为专有信息,仅供内部参考和技术交流使用。文档内容详尽,对于理解和实施InfiniBand接口具有重要指导意义。读者应结合相关背景资料进行学习,以确保正确理解和应用规范中的各项技术要求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值