排序:归并排序、堆排序、快速排序

1.归并排序

归并排序(Merging Sort)就是利用归并思想实现的排序方法。它的原理就是假设初始序列含有n个记录,则可以看成n个有序的子序列,每个子序列的长度为1,然后两两归并,得到[n/2]个长度为2或1的有序子序列;再两两归并,...如此重复,直至得到一个长度为n的有序序列为止。

递归方法的归并排序,代码如下:

void Merge(int* dest, int* src, int left, int mid, int right)//合并
{
	int i = left, j = mid + 1;
	int k = left;
	while (i <= mid && j <= right)
	{
		dest[k++] = src[i] < src[j] ? src[i++] : src[j++];
	}
	while (i <= mid)
	{
		dest[k++] = src[i++];
	}
	while (j <= right)
	{
		dest[k++] = src[j++];
	}
}
void Copy(int* dest, int* src, int left, int right)//复制
{
	for (int i = left; i <= right; ++i)
	{
		dest[i] = src[i];
	}
}
void MergePass(int* tmp, int* nums, int left, int right)//排序
{
	if (left < right)
	{
		int mid = (right - left) / 2 + left;
		MergePass(tmp, nums, left, mid);
		MergePass(tmp, nums, mid + 1, right);
		Merge(tmp, nums, left, mid, right);
		Copy(nums, tmp, left, right);
	}
}
void MergeSort(int* nums, int n)//归并排序
{
	if (nums == nullptr || n < 2)
		return;
	int* tmp = new int[n];
	MergePass(tmp,nums, 0, n - 1);
	delete[]tmp;
}
int main()
{
	int ar[] = { 56,23,78,45,99,85,12,34,67,99,100 };
	int n = sizeof(ar) / sizeof(ar[0]);
	MergeSort(ar, n);
	for (int i = 0; i < n; ++i)
	{
		cout << ar[i] << " ";
	}
	cout << endl;
}

运行结果:

归并算法的非递归实现

void Merge(int* dest, int* src, int left, int mid, int right)//合并函数
{
	int i = left, j = mid + 1;
	int k = left;
	while (i <= mid && j <= right)
	{
		dest[k++] = src[i] < src[j] ? src[i++] : src[j++];
	}
	while (i <= mid)
	{
		dest[k++] = src[i++];
	}
	while (j <= right)
	{
		dest[k++] = src[j++];
	}
}
void MergePass(int* dest, int* src, int n, int s)//排序实现
{
	int i = 0;
	while (i + 2 * s - 1 <= n - 1)//合并的每一组数据都是2的幂次方
	{
		Merge(dest, src, i, i + s - 1, i + 2 * s - 1);
		i = i + 2 * s;
	}
	if (n - 1 >= i + s)//合并的两组数据不是2的幂次方
	{
		Merge(dest, src, i, i + s - 1, n - 1);
	}
	else//合并的两组数据一组为空
	{
		for (int j = i; j < n; j++)//for循环把无法参与并轨的数据放到dest中
		{
			dest[j] = src[j];
		}
	}
}
void MergeSort(int* nums, int n)//合并排序
{
	int* tmp = new int[n];
	int s = 1;
	while (s < n)
	{
		MergePass(tmp, nums, n, s);//nums数组合并排序后放到tmp数组中
		s += s;//2
		MergePass(nums, tmp, n, s);//tmp数组合并排序后放到nums数组中
		s += s;//4
	}
	delete[]tmp;
}
int main()
{
	int ar[] = { 56,23,78,45,99,85,12,34,67,99,100 };
	int n = sizeof(ar) / sizeof(ar[0]);
	MergeSort(ar, n);
	for (int i = 0; i < n; ++i)
	{
		cout << ar[i] << " ";
	}
	cout << endl;
}

2.堆排序

1.创建堆:(大根堆)从中间结点开始,中间结点一定在倒数第二层,提高效率
2.排序:把第一个结点和最后一个结点交换,结点个数减一 

代码如下:

void CH(int* arr, int root, int n)//创建大根堆
{
	int i = 2 * root;//root*2==n此节点只要一个孩子且是左孩子,root*2>n此节点是叶子结点,root*2<n此节点有两个孩子
	int t = arr[root];
	while (i <= n)
	{
		if (i < n)
		{
			if (arr[i] < arr[i + 1])//先比较左右孩子的大小,找到最大的孩子
			{
				i++;
			}
		}
		if (t >= arr[i]) break;//如果根结点比两个孩子大,已经是大根堆,不用变了
		else//如果根结点没有孩子大,就交换
		{
			arr[i / 2] = arr[i];
			i = 2 * i;
		}
	}
	arr[i / 2] = t;//根结点
}
void Heapsort(int* arr, int n)//堆排序
{
	int i, t;
	for (i = n / 2; i >= 1; i--)//从中间结点,开始创建大根堆
	{
		CH(arr, i, n);
	}
	for (i = n; i >= 1; --i)//最后一个结点和第一个结点交换
	{
		t = arr[1];
		arr[1] = arr[i];
		arr[i] = t;
		CH(arr, 1, i - 1);//交换完去掉最后一个结点,再创建大根堆
	}
}
void main()
{
	int arr[] = { 0,6,5,7,8,9,0,1,2,3,4,5,6,7 };
	int n = sizeof(arr) / sizeof(arr[0]) - 1;
	Heapsort(arr, n);
	for (int i = 0; i < n; i++)
	{
		cout << arr[i] << " ";
	}
}

运行结果:

3.快速排序

递归形式下的快排

void printfint(char* nums, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%5d ", nums[i]);
	}
	printf("\n");
}
int partition(char*nums,int left,int right)//划分
{
	int i = left;
	int j = right;
	int temp = nums[i];
	while (i < j)
	{
		while (i<j && nums[j]>temp)
			--j;
		if (i < j)
			nums[i] = nums[j];
		while (i < j && nums[i] <= temp)
			i++;
		if (i < j)
			nums[j] = nums[i];
	}
	nums[i] = temp;
	return i;
}
int Randompartition(char* nums,int left,int right)//随机划分方案
{
	srand(time(NULL));
	int rapos = rand() % (right - left + 1)+ left;
	std::swap(nums[left],nums[rapos]);
	return partition(nums, left, right);
}
void QuickSort(char*nums,int left,int right)//排序
{
	if (left < right)
	{
		int mid = partition(nums, left, right);
		
	}
}
int main()
{
	char nums[] = { 56,12,23,45,56,67,78,89,90,24 };
	int n = sizeof(nums) / sizeof(nums[0]);
	printfint(nums, n);
	QuickSort(nums, 0,n-1);
	printfint(nums, n);
}

 运行结果:

 非递归的快排

void printfint(char* nums, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%5d ", nums[i]);
	}
	printf("\n");
}
void onewaysort(char* nums, int left,int right)//排序
{
	int i = left + 1;
	int j = left;
	int tmp = nums[left];
	while (i <= right)
	{
		if (nums[i] <= tmp)
		{
			j++;
			std::swap(nums[i], nums[j]);
		}
		i++;
	}
	std::swap(nums[j], nums[left]);
}
int main()
{
	char nums[] = { 56,12,23,45,67,78,89,90,24 };
	int n = sizeof(nums) / sizeof(nums[0]);
	int left = 0;
	int right = n - 1;
	printfint(nums, n);
	onewaysort(nums, left, right);
	printfint(nums, n);
}

运行结果:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秉麟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值