[问题描述]
各种内部排序算法的时间复杂度分析结果只给出了算法执行时间的阶,或大概执行的时间。试通过随机的数据比较各算法的关键字比较次数和关键字移动次数,以取得直观感受
[基本要求]
①对以下10种常用的内部排序算法进行比较:直接插入排序;折半折入排序,二路插入排序;希尔排序;起泡排序;快速排序;简单选择排序;堆排序;归并排序;基数排序
②待排序表的表长不少于100;其中的数据要用伪随机数产生程序产生:至少要用5组不同的输入数据作比较;比较的指标为有关键字参加的比较次数和关键字移动次数(关键字交换计为3次移动)。
[测试数据]
由随机产生器决定。
[实现提示]
主要工作是设法在程序中适当的地方插入计数操作。程序还可以包括计算结果波动大小的解释。注意分块调试的方法。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAXSIZE 100
int counst = 0, temp = 0;
int coust = 0, te = 0;
typedef struct
{
int r[MAXSIZE + 1]; // r[0]为工作单元或闲置
int length; // length为顺序表的长度
} SqeList;
SqeList *S_null(SqeList *L)
{
L->length = 0;
return L;
}
SqeList *S_c(SqeList *L)
{
L = S_null(L);
int n = rand() % 100 + 1;
while (L->length != MAXSIZE)
{
L->length++;
L->r[L->length] = n;
n = rand() % 100 + 1;
}
return L;
}
void read(SqeList *L)
{
int i = 0;
for (i = 1; i <= L->length; i++)
printf("%d ", L->r[i]);
printf("\n");
}
void InsertSort(SqeList *L)
{ //对顺序表L中的元素做直接插入
int j, i, count = 0, temp = 0; // count:比较次数,temp:移动次数
for (i = 1; i <= L->length; i++)
{
count++;
L->r[0] = L->r[i];
j = i - 1; //将待插入元素存到监视哨r[0]中}
while (L->r[0] < L->r[j])
{ //寻找插入位置
count++;
L->r[j + 1] = L->r[j];
j = j - 1;
temp++;
}
count++;
temp++;
L->r[j + 1] = L->r[0]; //将待插入元素插入到已排序的序列中
}
count++;
printf("直接插入排序:比较次数:%d,移动次数:%d\n", count, temp);
}
void Shelllnsert(SqeList *L, int di, int *count, int *temp)
{ //对顺序表L做一趟希尔插入排序,di为该趟排序的增量
int i, j;
for (i = 1 + di; i <= L->length; i++)
{ // 1+di为第一个子序列的第二个元
*count += 1;
if (L->r[i] < L->r[i - di])
{
*count += 1;
L->r[0] = L->r[i]; //备份L->r[i](不做监视哨)
for (j = i - di; (j > 0) && (L->r[0] < L->r[j]); j -= di)
{
L->r[j + di] = L->r[j];
*count += 1;
*temp += 1;
}
*count += 1;
L->r[j + di] = L->r[0];
}
}
*count += 1;
}
void ShellSort(SqeList *L, int delta[], int n)
{ //对顺序表L按增量序列delta[0] ~ delta[n-1]做希尔排序
int i;
int count = 0, temp = 0; // count:比较次数,temp:移动次数
for (i = 0; i <= n - 1; i++)
Shelllnsert(L, delta[i], &count, &temp);
printf("希尔排序:比较次数:%d,移动次数:%d\n", count, temp);
}
void BubbleSort(SqeList *L)
{ //对顺序表L做冒泡排序
int i, j, n, change;
int x, count = 0, temp = 0; // count:比较次数,temp:移动次数
n = L->length;
change = 1; // change为记录元素交换
for (i = 0; i < n && change; ++i)
{ //做n-1趟排序
count++;
change = 0;
for (j = 0; j < n - i; ++j)
{
count++;
if (L->r[j] > L->r[j + 1])
{
count++;
temp++;
x = L->r[j];
L->r[j] = L->r[j + 1];
L->r[j + 1] = x;
change = 1;
}
count++;
}
count++;
}
count++;
printf("冒泡排序:比较次数:%d,移动次数:%d\n", count, temp);
}
int Partition(SqeList *H, int left, int right)
{ //对顺序表H中的H->r[left]至H->r[right]部分进行快速排序的一次划分,放中间数的位置(基准位置)
int x;
int low, high;
x = H->r[left]; // 选择中间数
low = left;
high = right;
while (low < high)
{
counst++;
while (H->r[high] >= x && low < high)
{
high--;
counst++;
} //首先从右向左扫描,查找第一个关键字小于x.key的元素
if (low < high)
{
counst++;
H->r[low] = H->r[high];
temp++;
low++;
}
while (H->r[low] < x && low < high)
{
low++;
counst++;
} //然后从左向右扫描,查找第一个关键字不小于x.key 的元素
if (low < high)
{
counst++;
temp++;
H->r[high] = H->r[low];
high--;
}
}
H->r[low] = x; //将中间数保存到 low=high 的位置
temp++;
return low; //返回存放中间数的位置
}
void QuickSort(SqeList *L, int low, int high)
{ //对顺序表L用快速排序算法进行排序
int mid;
if (low < high)
{
mid = Partition(L, low, high);
QuickSort(L, low, mid - 1);
QuickSort(L, mid + 1, high);
}
}
void SelectSort(SqeList *L)
{ //对顺序表L做直接选择排序
int count = 0, temp = 0; // count:比较次数,temp:移动次数
int n, i, k, j, x;
n = L->length;
for (i = 0; i < n; ++i)
{
count++;
k = i;
for (j = i + 1; j <= n; ++j)
{
count++;
if (L->r[j] < L->r[k])
{
k = j;
count++;
}
}
count++;
if (k != i)
{
count++;
temp++;
x = L->r[i];
L->r[i] = L->r[k];
L->r[k] = x;
}
}
count++;
printf("直接选择插入:比较次数:%d,移动次数:%d\n", count, temp);
}
void InSort(SqeList *L, int *count, int *temp)
{ //对顺序表L中的元素做直接插入
int j, i;
for (i = 1; i <= L->length / 2; i++)
{
*count += 1;
L->r[0] = L->r[i];
j = i - 1; //将待插入元素存到监视哨r[0]中}
while (L->r[0] < L->r[j])
{ //寻找插入位置
*count += 1;
*temp += 1;
L->r[j + 1] = L->r[j];
j = j - 1;
}
*count += 1;
*temp += 1;
L->r[j + 1] = L->r[0]; //将待插入元素插入到已排序的序列中
}
*count += 1;
}
void Insert_Sort(SqeList *L)
{
int count = 0, temp = 0;
int i = 2, j;
int low = 1, high = i - 1, mid = (low + high) / 2;
for (; i <= L->length; i++)
{
count++;
int low = 1, high = i - 1;
L->r[0] = L->r[i];
while (low <= high)
{
count += 1;
mid = (low + high) / 2;
if (L->r[0] < L->r[mid])
high = mid - 1;
else
low = mid + 1;
}
count += 1;
for (j = i; j > high + 1; j--)
{
count += 1;
L->r[j] = L->r[j - 1];
temp++;
}
count += 1;
L->r[high + 1] = L->r[0];
temp++;
}
printf("折半查找排序:比较次数:%d,移动次数:%d\n", count, temp);
}
void Inse_Sort(SqeList *L)
{ //二路插入排序
int arr[L->length];
int fir, fin, i, j, count = 0, temp = 0;
int low, high, mid, n = L->length;
fir = 0;
fin = 0;
arr[0] = L->r[1];
for (i = 2; i <= n; i++)
{
count++;
// printf("%d,%d ",arr[fir],fir);
if (L->r[i] >= arr[fin])
{
count++;
temp++;
fin = (fin + 1 + n) % n;
arr[fin] = L->r[i];
}
else if (L->r[i] <= arr[fir])
{
count++;
temp++;
fir = (fir - 1 + n) % n;
arr[fir] = L->r[i];
}
else
{
count++;
if (L->r[i] <= arr[0])
{
count++;
// printf("arr[n-1]=%d ",arr[n-1]);
if (L->r[i] >= arr[n - 1])
{
count++;
for (j = fir; j <= n - 1; j++)
{
count++;
temp++;
arr[j - 1] = arr[j];
}
count++;
temp++;
arr[n - 1] = L->r[i];
fir -= 1;
}
else
{
count++;
low = fir;
high = n - 1;
while (low <= high)
{
count++;
mid = (low + high) / 2;
if (L->r[i] < arr[mid])
{
high = mid - 1;
count++;
}
else
{
count++;
low = mid + 1;
}
}
count++;
for (j = fir; j <= high; j++)
{
count++;
temp++;
arr[j - 1] = arr[j];
}
count++;
temp++;
arr[high] = L->r[i];
fir -= 1;
}
}
else
{
count++;
low = 0;
high = fin;
while (low <= high)
{
count++;
mid = (low + high) / 2;
if (L->r[i] < arr[mid])
{
high = mid - 1;
count++;
}
else
{
low = mid + 1;
temp++;
}
}
count++;
for (j = fin; j >= high + 1; j--)
{
count++;
arr[j + 1] = arr[j];
temp++;
}
count++;
temp++;
arr[high + 1] = L->r[i];
fin += 1;
}
}
}
for (i = 1, j = fir - 1; i <= L->length; i++)
{
temp++;
if (j == L->length - 1)
j = 0;
else
j++;
L->r[i] = arr[j];
}
count++;
// for(j=0;j<n;j++){
// printf("%d ",arr[j]);
// }
printf("二路插入排序:比较次数:%d,移动次数:%d\n", count, temp);
}
void Down(SqeList *L, int i, int n, int *count, int *tem)
{ // 最后结果就是大顶堆
int parent = i;
int temp; // 父节点下标
int child = 2 * i; // 子节点下标
while (child < n)
{
*count += 1;
if (child + 1 < n && L->r[child] < L->r[child + 1])
{ // 判断子节点那个大,大的与父节点比较
child++;
*count += 1;
}
if (L->r[parent] < L->r[child])
{ // 判断父节点是否小于子节点
*count += 1;
*tem += 1;
temp = L->r[parent]; // 交换父节点和子节点
L->r[parent] = L->r[child];
L->r[child] = temp;
parent = child; // 子节点下标 赋给 父节点下标
}
child = child * 2; // 换行,比较下面的父节点和子节点
}
*count += 1;
}
void Heapsort(SqeList *L)
{ //堆排序
int size = L->length + 1;
int i, count = 0, tem = 0;
for (i = size / 2 - 1; i >= 1; i--)
{
Down(L, i, size, &count, &tem);
}
for (i = size - 1; i > 1; i--)
{
// printf("%ds ",L->r[i]);
temp = L->r[i];
L->r[i] = L->r[1];
L->r[1] = temp;
tem++;
Down(L, 1, i, &count, &tem);
}
printf("堆排序:比较次数:%d,移动次数:%d\n", count, tem);
}
void merge(SqeList *L, int start, int mid, int end)
{
int result[MAXSIZE + 1];
int k = 0;
int i = start;
int j = mid + 1;
while (i <= mid && j <= end)
{
coust += 1;
if (L->r[i] < L->r[j])
{
coust += 1;
te += 1;
result[k++] = L->r[i++];
}
else
{
coust == 1;
te += 1;
result[k++] = L->r[j++];
}
}
coust == 1;
if (i == mid + 1)
{
coust += 1;
while (j <= end)
{
coust += 1;
te += 1;
result[k++] = L->r[j++];
}
coust += 1;
}
if (j == end + 1)
{
coust += 1;
while (i <= mid)
{
coust += 1;
te += 1;
result[k++] = L->r[i++];
}
coust += 1;
}
for (j = 0, i = start; j < k; i++, j++)
{
coust += 1;
te += 1;
L->r[i] = result[j];
}
coust += 1;
}
void Merge_sort(SqeList *L, int start, int end)
{ //折半排序
if (start >= end)
{
coust += 1;
return;
}
int mid = (start + end) / 2;
Merge_sort(L, start, mid);
Merge_sort(L, mid + 1, end);
merge(L, start, mid, end);
}
void Radix_sort(SqeList *L)//基数排序
{
int arr[10][MAXSIZE] = {0};
int i, j, k, m, num = 10, count = 0, temp = 0;
for (i = 1; i < 4; i++)
{
count++;
num = 10;
for (k = 1; k < i; k++)
{
count++;
num *= 10;
} //(L->r[i]%num)/(num/10):比较的位数数字
count++;
for (j = 1; j <= L->length; j++)
{
count++;
for (k = 0; k < L->length; k++)
{
count++;
if (arr[(L->r[j] % num) / (num / 10)][k] == 0)
{
count++;
temp++;
arr[(L->r[j] % num) / (num / 10)][k] = L->r[j];
break;
}
}
count++;
}
count++;
for (j = 0, m = 1; j < 10; j++)
{
count++;
for (k = 0; k < MAXSIZE; k++)
{
count++;
if (m > L->length)
{
count++;
break;
}
if (arr[j][k] != 0)
{
count++;
temp++;
L->r[m] = arr[j][k];
m++;
arr[j][k] = 0;
}
}
count++;
}
count++;
}
count++;
printf("基数排序:比较次数:%d,移动次数:%d\n", count, temp);
}
int main(void)
{
srand((unsigned)time(NULL));
SqeList *L;
L = (SqeList *)malloc(sizeof(SqeList));
int d[] = {5, 2, 1};
int i=1;
while(i<=5){
L = S_c(L);
printf("\n排序前:\n");
read(L);
SqeList L1 = *L;
InsertSort(&L1);//直接插入
L1=*L;
Insert_Sort(&L1);//折半查找
L1=*L;
ShellSort(&L1,d,3);//希尔排序
L1=*L;
BubbleSort(&L1);//冒泡排序
L1=*L;
QuickSort(&L1,1,L->length);//快速排序
printf("快速排序:比较次数:%d,移动次数:%d\n",counst,temp);
L1=*L;
SelectSort(&L1);//直接选择排序
L1=*L;
Inse_Sort(&L1);//二路插入排序
L1=*L;
Heapsort(&L1);//推排序
L1=*L;
Merge_sort(&L1,1,MAXSIZE);//归并排序
printf("归并排序:比较次数:%d,移动次数:%d\n",coust,te);
L1=*L;
Radix_sort(&L1); //基数排序
printf("排序后:\n");
read(&L1);
i++;
}
return 0;
}
如果单看代码的话,算法是能实现的,但单论比较次数和移动次数,总感觉不对。
供自己保存使用,如有问题,欢迎指出。