④选择排序:
以升序排序为例:刷吗在一组数据对象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;
}