排序算法2

堆排序:
        把待排序数据当做完全二叉树看待,先把二叉树调整成大顶堆结构,把根节点的值与末尾节点的值交换,然后数量范围-1,重新从上到下调整回大顶堆,继续以上操作,直到数量为1结束,此时全部数据就从小到大排序了
        既可以顺序实现,也可以递归实现
        时间复杂度:O(N*logN)
        不稳定

代码实现:

//堆排序
void heap_sort(int* arr,int len)
{
	//把数组调整成堆结构
	for(int i=2; i<=len; i++)
	{
		int j = i;
		while(j>1)
		{
			if(arr[j/2-1] <arr[j-1])
			{
				SWAP(arr[j/2-1] , arr[j-1]);
					j /=2;
				continue;
			}
			break;
		}
	}
	//堆顶交换末尾 从堆顶到末尾-1 调整回调 直到全部调整
while(len > 1)
{
	SWAP(arr[0],arr[len-1]);
	len--;

	int i = 1;
	while(i-1 <len)
	{
		if(i*2 < len)
		{
			if(arr[i*2] >= arr[i*2-1] && arr[i*1] > arr[i-1])
			{
				SWAP(arr[i*2],arr[i-1]);
				i = i*2+1;
			}
			else if(arr[i*2-1] > arr[i*2] && arr[i*2-1] > arr[i-1])
			{
				SWAP(arr[i*2-1],arr[i*2]);
				i *= 2;
			}
			else break;
		}
			else if(i*2-1 < len)
			{
				if(arr[i*2-1] > arr[i-1])
				{
					SWAP(arr[i*2-1] , arr[i-1]);
						i *= 2;
				}
				else	break;
			}
			else	break;
		}	
	}	
}

2、归并排序:
        首先需要把数据拆分成单独的个体,然后按照从小到大的顺序比较后排序到一段临时空间中,把排序后的临时空间中的数据拷贝回原内存,然后依次把有序的个体继续以上操作合并成更大的有序部分
        归并排序不需要交换数据,减少了交换的耗时,但是需要额外的存储空间,是一种典型的以空间换时间的算法
        时间复杂度:O(N*logN)
        稳定的

代码实现:


//	合并 l左部分最左 p左部分最右 p+1右部分最左 r右部分最右 
void __merge(int* arr,int* temp,int l,int p,int r)
{
	//	合并前 左右部分各自有序
	if(arr[p] <= arr[p+1]) return;

	int s = l;
	int i = l, j = p+1;
	while(i<=p && j<=r)
	{
		//	左右部分从开头进行比较
		if(arr[i] <= arr[j])	// <=  确保是稳定的
			temp[s++] = arr[i++];
		else
			temp[s++] = arr[j++];
	}
	//	比完后,把多的部分剩余的数据依次存入temp
	while(i<=p) temp[s++] = arr[i++];
	while(j<=r) temp[s++] = arr[j++];
	//	把temp还原回对应位置的arr
	memcpy(arr+l,temp+l,sizeof(TYPE)*(r-l+1));
}

//	拆分
void _merge(int* arr,int* temp,int l,int r)
{
	if(l >= r) return;
	int p = (l+r)/2;
	_merge(arr,temp,l,p);
	_merge(arr,temp,p+1,r);
	//	合并
	__merge(arr,temp,l,p,r);
}

//	归并排序
void merge_sort(int* arr,size_t len)
{
	
	//	申请临时存储空间
	int* temp = malloc(sizeof(TYPE)*len);
	_merge(arr,temp,0,len-1);
	free(temp);
}

3、计数排序:
        找出待排序数据中的最大、最小值,创建长度为 
        最大值-最小值+1 的哈希表,根据哈希函数 数据-最小值 当做哈希表的下标并对所有数据做标记
        然后从头遍历哈希表,当某个位置的值大于0,把该位置的下标+最小值的到结果依次放回原数据内存中
        是一种典型的以空间换时间的算法
        理论上该算法的速度是非常快的,它不是基于比较的排序算法,在一定范围内的整数排序中快于任意一种基于比较的排序算法,但是有很大的局限性,只适合整型数据排序,数据的差值不宜太大,否则会非常浪费内存
        反之数据差值不大、重复数比较多的情况下性价比很高
        时间复杂度:Ο(n+k)(其中k是整数的范围)
        稳定的

代码实现:

//	计数排序
void count_sort(int* arr,size_t len)
{
	
	TYPE max = arr[0],min = arr[0];
	for(int i=1; i<len; i++)
	{
		if(arr[i] > max) max = arr[i];
		if(arr[i] < min) min = arr[i];
	}

	int* temp = calloc(sizeof(int),max-min+1);
	for(int i=0; i<len; i++)
	{
		temp[arr[i]-min]++;	
	}
	for(int i=0,j=0; i<max-min+1; i++)
	{
		while(temp[i]--) arr[j++] = i+min; 	
	}
	free(temp);
}

桶排序:
        一般是把数据根据数值分到不同的"桶",通过不同的、合适的其他排序算法对"桶"中的数据进行排序,然后再把各个"桶"的数据依次拷贝回原内存中
        桶排序是一种降低排序规模的排序思想,也是以空间换时间的算法
        缺点:如何分桶、桶如何定义,都需要针对具体待排序的数据进行分析后才能确定
        桶排序的稳定性取决于桶内排序使用的算法
        有些资料上认为桶排序可以做到稳定,所以认为桶排序稳定

代码实现:


// cnt桶数 range桶中数据的差值	
void _bucket(int* arr,size_t len,int cnt,int range)
{
	//	申请桶内存
	//	bucket_s指向桶的开头位置
	//	bucket_e指向桶的末尾 接下去要入桶的位置
	int* bucket_s[cnt],*bucket_e[cnt];
	for(int i=0; i<cnt; i++)
	{
		//	数据有可能全在一个桶内
		bucket_s[i] = malloc(sizeof(int)*len);
		bucket_e[i] = bucket_s[i];
	}

	//	把数据按照对应的范围放入对应的桶中
	for(int i=0; i<len; i++)
	{
		for(int j=0; j<cnt; j++)
		{
			if(j*range <= arr[i] && arr[i] < (j+1)*range)
			{
				*(bucket_e[j]) = arr[i];
				bucket_e[j] += 1;
				break;
			}
		}
	}

	//	通过其他排序对各个桶中的数据排序
	for(int i=0; i<cnt; i++)
	{
		//	计算桶中元素的数量
		int size = bucket_e[i] - bucket_s[i];
		//	其他排序
		if(1 < size)
			bubble_sort(bucket_s[i],size);
		//	按照先后顺序 放入原内存中
		memcpy(arr,bucket_s[i],size*sizeof(int));
		arr += size;
		free(bucket_s[i]);
	}
}

//	桶排序
void bucket_sort(int* arr,size_t len)
{
	_bucket(arr,len,4,25);
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值