【C语言】快速排序+归并排序+计数排序

文章详细介绍了三种排序算法:快速排序使用了Hoare版本的递归实现,并提到了三数取中法的优化;归并排序基于分治法,通过递归和二路归并将两个有序序列合并;计数排序则适用于整数排序,通过统计每个元素出现次数来排序。此外,还讨论了在不同情况下对这些排序算法的优化策略。
摘要由CSDN通过智能技术生成

目录

1.快速排序

1.1快速排序的基本思想

 1.2代码实现(hoare版本递归):

2.归并排序

2.1归并排序的思想

2.2递归实现

2.3小优化一下

3计数排序

3.1计数排序的思想

 3.2代码实现


1.快速排序

1.1快速排序的基本思想

快速排序是一种二叉树交换结构的排序法,首先取序列中的某个元素作为基准值,用这个基准值把整个序列分割成两个序列。例如升序就是把小于基准值的元素放在左子序列,大于基准值的数放在右子序列,最后左右子序列重复这个过程直到完成排序。

图片演示:

动图

 1.2代码实现(hoare版本递归):

void swap(int* p1, int *p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

int PartQuickSort(int* a, int left, int right)
{
	int keyi = left;
	int begin = left;
	int end = right;
	while (begin < end)
	{
		while (begin < end && a[end] >= a[keyi])
		{
			end--;
		}
		while (begin < end && a[begin] <= a[keyi])
		{
			begin++;
		}
		swap(&a[begin], &a[end]);

	}
	swap(&a[keyi], &a[end]);
	keyi = end;
	return keyi;
}

void QuickSort(int* a, int begin, int end)
{
	if (begin >= end)
	{
		return;
	}

	int keyi = PartQuickSort(a, begin, end);

	QuickSort(a, begin, keyi - 1);
	QuickSort(a, keyi + 1 , end);
	
}

上面的代码基准值是取数组的第一个元素,其实还可以用三数取中法优化一下,找到数组第一个元素、中间的元素和最后一个元素中间大的那个数。

例如:

int GetMidIndex(int* a, int left, int right)
{
	int mid = (left + right) / 2;
	if (a[left] < a[mid])
	{
		if (a[mid] < a[right])
		{
			return mid;
		}
		else if (a[left] < a[right])
		{
			return right;
		}
		else
		{
			return left;
		}
	}
	else 
	{
		if (a[mid] > a[right])
		{
			return mid;
		}
		else if (a[left] > a[right])
		{
			return right;
		}
		else
		{
			return left;
		}
	}
}


int PartQuickSort(int* a, int left, int right)
{
	int mid = GetMidIndex(a, left, right);
	swap(&a[mid], &a[left]);
	int keyi = left;
	int begin = left;
	int end = right;
	while (begin < end)
	{
		while (begin < end && a[end] >= a[keyi])
		{
			end--;
		}
		while (begin < end && a[begin] <= a[keyi])
		{
			begin++;
		}
		swap(&a[begin], &a[end]);

	}
	swap(&a[keyi], &a[end]);
	keyi = end;
	return keyi;
}

void QuickSort(int* a, int begin, int end)
{
	if (begin >= end)
	{
		return;
	}

	int keyi = PartQuickSort(a, begin, end);

	QuickSort(a, begin, keyi - 1);
	QuickSort(a, keyi + 1 , end);
	
}

2.归并排序

2.1归并排序的思想

归并排序的算法是采用分治法(Divide and Conquer)的一个非常典型的应用,且各层分治递归可以同时进行。先使每个子序列有序,再使子序列段间有序。将两个有序序列合成一个有序序列称为二路归并。

现将序列平均分成两个序用二路归并法对两个子序列递归的排序。当递归到每个序列只有一个元素时,我们称之为序列有序就开始归并,搞一个临时数组,把两个有序序列合成一个有序序列。

 

2.2递归实现

void _MergeSort(int* a, int begin, int end, int* tmp)
{
	if (begin == end)
	{
		return;
	}

	int mid = (begin + end) / 2;
	_MergeSort(a, begin, mid, tmp);
	_MergeSort(a, mid+1,end, tmp);

	

	int begin1 = begin;
	int end1 = mid;
	int begin2 = mid + 1;
	int end2 = end;
	int i = begin;
	while ( begin1 <= end1 && begin2 <= end2)
	{
		if (a[begin1] < a[begin2])
		{
			tmp[i++] = a[begin1++];
		}
		else
		{
			tmp[i++] = a[begin2++];
		}
	}
	while (begin1 <= end1)
	{
		tmp[i++] = a[begin1++];
	}
	while (begin2 <= end2)
	{
		tmp[i++] = a[begin2++];
	}
	memcpy(a + begin, tmp + begin, sizeof(int) * (end - begin + 1));
}

2.3小优化一下

当序列递归到小于10个元素时可以用插入排序进行直接排序 可以减少80%多的递归

void _MergeSort(int* a, int begin, int end, int* tmp)
{
	if (begin == end)
	{
		return;
	}


    //小区间优化
	if (end - begin + 1 < 10)
	{
		InsertSort(a + begin, end - begin + 1);
		return;
	}



	int mid = (begin + end) / 2;
	_MergeSort(a, begin, mid, tmp);
	_MergeSort(a, mid+1,end, tmp);

	

	int begin1 = begin;
	int end1 = mid;
	int begin2 = mid + 1;
	int end2 = end;
	int i = begin;
	while ( begin1 <= end1 && begin2 <= end2)
	{
		if (a[begin1] < a[begin2])
		{
			tmp[i++] = a[begin1++];
		}
		else
		{
			tmp[i++] = a[begin2++];
		}
	}
	while (begin1 <= end1)
	{
		tmp[i++] = a[begin1++];
	}
	while (begin2 <= end2)
	{
		tmp[i++] = a[begin2++];
	}
	memcpy(a + begin, tmp + begin, sizeof(int) * (end - begin + 1));
}

3计数排序

计数排序适用于一定范围的整数排序在取值范围不是很大的情况下,它的性能在某些情况甚至快过那些O(nlogn)的排序,例如快速排序、归并排序。

3.1计数排序的思想

计数排序需要搞一个数组来对应序列中的元素,例如序列:112233405566就开一个数组下标0~6

遍历序列,元素出现就在数组对应位置+1

最后按照数组的计数还原序列 

动图示例:

 3.2代码实现

为了防止序列最小值为100或者10000,造成开数组时的空间浪费,可以先遍历一次要排序的序列找出序列最小的元素,所有元素在技术时减去这个最小值,还原序列时再加回来。

void CountSort(int* a, int n)
{
	int min = a[0];
	int max = a[0];
	
	for (int i = 0; i < n; i++)
	{
		if (a[i] < min)
		{
			min = a[i];
		}
		if (a[i] > max)
		{
			max = a[i];
		}
	}

	int range = max - min + 1;

	int* count = (int*)malloc(sizeof(int) * range);
	if (count == NULL)
	{
		perror("malloc fail");
	}
	memset(count, 0, sizeof(int) * range);
	for (int i = 0; i < n; i++)
	{
		count[a[i] - min]++;
	}
	int k = 0;
	for (int i = 0; i < range; i++)
	{
		while (count[i]--)
		{
			
			a[k++] = i+min;
		}
	}
	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值