10种排序算法笔记总结(二)选择排序、堆排序和冒泡排序及冒泡排序的改进

④选择排序:

以升序排序为例:刷吗在一组数据对象v[0]v[1]v[2]........v[n-1]中选择最小关键码的对象,若他不是对象序列中的第一个对象,则将它与第一个对象对调,然后在这组对象中剔除具有最小关键码的对象,在剩下的对象v[i+1]........v[n-1]中重复执行上述步骤,直到剩余对象只有一个为止。显然在这个过程中,具有相同关键码的对象可能会颠倒次序,因此直接选择排序算法是一种不稳定的排序方法。

#include<iostream>
using namespace std;
int* SelectSort(int*A, int n)
{
	int min;
	for (int i = 0; i < n; i++)
	{
		min = i;
		for (int j = i; j < n; j++)
		{
			if (A[min] > A[j])
				min = j;
		}
		swap(A[min], A[i]);
	}
	return A;
}
int main()
{
	int n;
	while (cin >> n)
	{
		int * arr = new int[n];
		for (int i = 0; i < n; i++)
			arr[i] = rand()%100;
		SelectSort(arr, n);
		for (int i = 0; i < n; i++)
			cout << arr[i] << " ";
		cout << endl;
	}
	system("pause");
	return 0;
}

⑤堆排序:

如果讲堆结构中的数据看做是一颗完全二叉树的各个节点,那么堆实质上就是满足以下性质的完全二叉树:树种任一非叶子节点的关键字均不大于(或不小于)其左右孩子节点(若存在)的关键字。利用堆的有序性及其运算,可以很容易的实现选择排序。这种排序方法称为堆排序。

假设欲对含有n个对象的序列v[0]、v[1]、v[2]......v[n-1]进行堆排序,那么算法主要分为两个步骤:

一、根据初始输入数据利用对的调整算法形成初始堆;二、通过一系列的交换和重新调整对堆进行排序

具体过程是在首次获得最大堆之后,将关键码最大的元素v[0](即堆顶)和无序区中最后一个元素交换。由此得到新的无序区v[0]、v[1]、v[2]........v[n-2]和有序区v[n-1],且满足无序区中元素的关键码不大于有序区中元素的关键码。由于交换后新的对顶v[0]可能违反堆的性质,因此再次利用堆的调整算法对无序区v[0]、v[1]、v[2]......v[n-2]进行调整。调整完成后将关键码最大的元素v[0]和无序区的最后一个元素v[n-2]进行交换,并再次利用堆的调整算法进行调整........反复进行以上步骤直到无序区中只剩下一个元素为止。

#include<iostream>
using namespace std;
void MoveToAdjust(int*A, int first, int last)
{
	int largest = 2 * first + 1;
	int temp = A[first];
	while (largest <= last)
	{
		if (largest<last && A[largest] < A[largest + 1])
			largest++;
		if (temp < A[largest])
		{
			A[first] = A[largest];
			first = largest;
			largest = 2 * first + 1;
		}
		else
			break;
	}
	A[first] = temp;
}
int* HeapSort(int*A, int n)
{
	for (int i = n / 2; i >= 0; i--)
		MoveToAdjust(A, i, n - 1);
	for (int j = n - 1; j > 0; j--)
	{
		swap(A[0], A[j]);
		MoveToAdjust(A, 0, j - 1);
	}
	return A;
}
int main()
{
	int n;
	while (cin >> n)
	{
		int * arr = new int[n];
		for (int i = 0; i < n; i++)
			arr[i] = rand()%100;
		HeapSort(arr, n);
		for (int i = 0; i < n; i++)
			cout << arr[i] << " ";
		cout << endl;
	}
	system("pause");
	return 0;
}

⑥冒泡排序及其改进:

冒泡排序的基本思想是模拟气泡上浮的过程,可以把数组看做是一个竖立的容器,有很多的泡泡(及数据元素),大泡泡对应一个较小的关键码的数据元素,小泡泡对应一个较大的关键码的数据元素,生活常识告诉我们大泡泡会先浮上去。

过程:设待排序元素对象序列中有n个对象,收先比较待排序对象v[0]和v[1]的关键码,如果v[0]>v[1],则交换元素v[0]和v[1],然后对v[i]和v[i+1]做同样的操作,直到对v[n-2]和v[n-1]做完操作,每趟过程,结果是关键码大的对象交换到待排序列的最右端位置,其他对象都向着排序的最终位置移动。在个别情况下,有元素可能回想相反方向移动,但总的趋势是向排序后的最终位置移动的。

#include<iostream>
using namespace std;
int* BubbleSort(int* A, int n)
{
	for (int i = 1; i < n-1; i++)
	{
		for (int j = 0; j <n-i ; j++)
		{
			if (A[j] > A[j + 1])
				swap(A[j], A[j + 1]);
		}		
	}
	return A;
}
int main()
{
	int n;
	while (cin >> n)
	{
		int * arr = new int[n];
		for (int i = 0; i < n; i++)
			arr[i] = rand()%100;
		BubbleSort(arr, n);
		for (int i = 0; i < n; i++)
			cout << arr[i] << " ";
		cout << endl;
	}
	system("pause");
	return 0;
}

改进思想:

若某趟排序以此交换也没有发生,则序列已经有序。一趟排序可以先从前往后比较,在从后往前比较,在从前往后遍历后记录最后发生交换的两个元素的位置,从后往前遍历是就从这个位置开始。这种双向交替比较不仅可以使大的浮出水面,也可以使小的沉入水底。

基本步骤:假设对数据表v[0]、v[1]、v[2]......v[n-1]进行排序。那么在第1阶段的自左向右遍历结束后,数据表中最大的元素就位于表中最右段的位置,因此自右向左遍历只需在新表中的第0项至第n-2项中进行。在接下来的自右向左遍历结束后,表中的最小的元素就位于序列中最左端的位置了。因此,下一阶段的操作只需要在表中的第1项到第n-2项中进行即可。也就是说,第p个阶段的自左向右遍历的操作只需在新表中第p-1到第n-p个位置上进行,而第p个阶段的自右向左遍历则相应的只在新表中第n-p-1到第p个位置上进行。特别的,当数据表中的元素为偶数时,最后一个阶段的自右向左遍历不进行任何操作。

#include<iostream>
using namespace std;
int* BubbleSort(int* A, int n)
{
	int i = 0, left = 0, right = n - 1, shift = 0;
	while (left < right)
	{
		for (i = left; i < right; i++)
		{
			if (A[i] > A[i + 1])
			{
				swap(A[i], A[i + 1]);
				shift = i;
			}
		}
		right = shift;
		for (i = right; i > left; i--)
		{
			if (A[i] < A[i - 1])
			{
				swap(A[i], A[i - 1]);
				shift = i;
			}
		}
		left = shift;
	}
	return A;
}
int main()
{
	int n;
	while (cin >> n)
	{
		int * arr = new int[n];
		for (int i = 0; i < n; i++)
			arr[i] = rand()%100;
		BubbleSort(arr, n);
		for (int i = 0; i < n; i++)
			cout << arr[i] << " ";
		cout << endl;
	}
	system("pause");
	return 0;
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值