实验内容及原理
用随机函数生成16个2位正整数(10~99),从复杂度为O(n2) 的插入排序、选择排序、冒泡(双向冒泡)和复杂度为O(nlog2n) 的堆排序、快速排序、归并排序等多种排序算法各选1种实现,输出排序中间过程、统计关键字的比较次数和记录的移动次数。
sort.h
#include"stdafx.h"
#include"iostream"
using namespace std;
void swap(int*a, int*b);
void printArray(int array[], int n);
void printquick();
void merge1(int array[], int temp[], int front, int rear);
void merge2(int array[], int temp[], int front, int rear);
void Heap(int array[], int n, int pre);
void setArray(int array[], int temp[]);
void bubblesort(int array[], int n); //冒泡排序
void doublebubblesort(int array[], int n);//双向冒泡
void selectionsort(int array[], int n); //选择排序
void insertionsort(int array[], int n);//插入排序
void mergesort(int array[], int n);//归并排序
void heapSort(int array[], int n);//堆排序
void quicksort(int array[], int left, int right);//快速排序
sort.cpp
#include "stdafx.h"
#include"sort.h"
static int qa = 0;
static int qg = 0;
static int qb = 0;
void swap(int*a, int*b)
{
int temp = *a;
*a = *b;
*b = temp;
}
void printArray(int array[], int n)
{
for (int i = 0; i < n; i++)
{
cout << array[i] << "--";
}
cout << endl;
}
void setArray(int Array[], int temp[])
{
for (int i = 0; i < 16; i++)
{
temp[i] = Array[i];
}
}
void bubblesort(int Array[], int n)
{
bool flag = 1;
for (int i = 0; i < n&&flag; i++)
{
flag = 0;
for (int j = n-1; j > i; j--)
{
if (Array[j] <= Array[j - 1])
{
swap(Array[j], Array[j - 1]);
flag = 1;
}
}
}
}
void doublebubblesort(int Array[], int n)
{
cout << "双向冒泡:" << endl;
int a=0,b=0,c=0;
bool flag = 0;
int front = 0; int rear = n - 1;
while (front<rear)
{
flag = 0;
for (int j = rear; j > front; j--)
{
if (Array[j - 1] > Array[j])
{
swap(Array[j - 1], Array[j]);
flag = 1;
a++;
}
c++;
}
rear -= 1;
for (int i = front; i <= rear; i++)
{
if (Array[i] > Array[i + 1])
{
swap(Array[i], Array[i + 1]);
flag = 1;
a++;
}
c++;
}
front += 1;
if (flag == 0)
{
break;
}
b++;
cout << "第" << b << "趟排序结果:"; printArray(Array, 16);
}
cout << "关键字交换次数:" << a<<endl;
cout << "关键字比较次数:" << c<<endl;
}
void selectionsort(int array[], int n)
{
for (int i = 0; i < n; i++)
{
int min = array[i];
int c = i;
for (int j = i + 1; j < n; j++)
{
if (min > array[j])
{
min = array[j];
c = j;
}
}
swap(array[i], array[c]);
}
}
/*
void doubleselection(int array[], int n)
{
int left = 0, right = n - 1;
int min = array[left];
int max = array[right];
int MI = left, MA = right;
while (left <= right)
{
min = array[left];
max = array[right];
MI = left, MA = right;
for (int i = left; i < right; i++)
{
if (array[i] <= min)
{
min = array[i];
MI = i;
}
if (array[i] >= max)
{
max = array[i];
MA = i;
}
}
if (MA == left && MI != right)
{
swap(array[right], array[MA]);
swap(array[left], array[MI]);
}
else if (MI == right && MA == left)
{
swap(array[left], array[MI]);
}
else
{
swap(array[left], array[MI]);
swap(array[right], array[MA]);
}
left++; right--;
}
}
*/
void insertionsort(int array[], int n)
{
int c = 0;
for (int i = 1; i < n; i++)
{
for (int j = i; j > 0; j--)
{
if (array[j] < array[j - 1])
{
swap(array[j], array[j - 1]);
}
else
{
break;
}
}
}
}
void merge1(int array[], int temp[], int front, int rear)
{
int mid = (front + rear) / 2;
int pre = 0, i = front, j = rear, t = mid + 1;
while (i <= mid && t <= j)
{
if (array[i] < array[t])
{
temp[pre] = array[i];
i++;
}
else
{
temp[pre] = array[t];
t++;
}
pre++;
}
for (; i <= mid; pre++, i++)
{
temp[pre] = array[i];
}
for (; t <= j; pre++, t++)
{
temp[pre] = array[t];
}
for (int c = 0; c < pre; c++)
{
array[front + c] = temp[c];
}
}
void merge2(int array[], int temp[], int front, int rear)
{
if (front<rear)
{
int mid = (front + rear) / 2;
merge2(array, temp, front, mid);
merge2(array, temp, mid + 1, rear);
merge1(array, temp, front, rear);
}
}
void mergesort(int array[], int n)
{
int temp[16];
merge2(array, temp, 0, n - 1);
}
void Heap(int array[], int n, int pre)
{
if (pre >= n)
return;
if (2 * pre + 2 < n&&array[2 * pre + 2] > array[pre])
{
if (array[2 * pre + 2] >= array[2 * pre + 1])
{
swap(array[2 * pre + 2], array[pre]);
Heap(array, n, 2 * pre + 2);
}
else
{
swap(array[2 * pre + 1], array[pre]);
Heap(array, n, 2 * pre + 1);
}
}
else if (2 * pre + 1 < n&&array[2 * pre + 1] > array[pre])
{
swap(array[2 * pre + 1], array[pre]);
Heap(array, n, 2 * pre + 1);
}
}
void heapSort(int array[], int n)
{
for (int t = n / 2; t >= 0; t--)
{
Heap(array, n, t);
}
for (int i = n; i > 0; i--)
{
swap(array[0], array[i - 1]);
Heap(array, i - 1, 0);
}
}
void quicksort(int array[], int left, int right)
{
if (right>left)
{
int base = array[left];
int i = left, j = right;
while (i < j)
{
qg++;
while (array[j] >= base && i<j)
{
j--;
qg++;
}
swap(array[i], array[j]);
qb++;
qg++;
while (array[i] <= base && i<j)
{
i++;
qg++;
}
swap(array[i], array[j]);
qb++;
}
qa++;
cout << "第" << qa << "趟排序";
printArray(array, 16);
quicksort(array, left, i - 1);
quicksort(array, i + 1, right);
}
}
void printquick()
{
cout << "关键字交换次数:" << qb << endl;
cout << "关键字比较次数:" << qg << endl;
}
main.cpp
#include "stdafx.h"
#include"time.h"
#include"sort.h"
int main()
{
srand(int(time(0)));
int test[16],temp[16];
for (int i = 0; i < 16; i++)//用随机函数生成16个2位正整数
{
test[i] = rand() %89 + 10;
}
setArray(test, temp);
bubblesort(temp, 16);
setArray(test, temp);
doublebubblesort(temp,16);
setArray(test, temp);
selectionsort(temp, 16);
setArray(test, temp);
insertionsort(temp, 16);
setArray(test, temp);
mergesort(temp, 16);
setArray(test, temp);
heapSort(temp, 16);
setArray(test, temp);
cout << "快速排序:" << endl;
quicksort(temp, 0, 15);
printquick();
}
实验结果及分析
双向冒泡:冒泡排序的改进,基本原理与冒泡排序相同,从数组的一端向另一端遍历,与下一个元素作比较,例如在升序排序中,从后往前遍历,若下一个元素比对应的元素大,则两者交换,如此一趟遍历后,最左端的元素即为数组中最小的元素,进行下一趟遍历,仍是从后往前遍历,此次遍历只到最左端右边的一个元素,即每次遍历完成一个元素的排序,当遍历至最右端时,完成排序。普通冒泡算法每次遍历都是朝一个方向进行的,双向冒泡为两个方向交替进行,这样子会略微提高算法的复杂性和空间复杂度,但是可以解决对一个高度逆序的数组进行排序的过程中效率底下的问题。
第一趟遍历需要比较n个元素,第二趟需要n-1个元素…因此冒泡排序算法时间复杂度为o((1/2)×n(n-1))=o(n^2)
快速排序:快速排序的原理依旧是交换排序,但是每次交换的对象为两个待调整的序列,即遍历前,都选择一个基准元素,而后将比基准元素小的元素放在左边,将比基准元素大的元素放在右边,当完成一趟排序后,基准元素的位置就确定了,然后再分别对基准元素左右两个待排序的数列进行同样处理,当数列的元素只有一个时,则该数列已经排序完毕,当所有序列处理完毕时,整个数组完成排序。
每次遍历都要对整个数列进行遍历,所有数列加起来的元素为n,但平均只需要logn轮遍历,因此该算法时间复杂度为o(n*logn)
由算法时间复杂度可知,当n越大时,快速排序法比冒泡排序等时间复杂度为o(n^2)的简单排序方法要高效得多,而在较少元素的情况下,例如本实验的示例中,快速排序法也要优于双向冒泡法,其效率跟待排数组的元素个数和基准元素的选取有关。