《数据结构与算法》实验:排序算法实验比较——选择排序 & 堆排序

心已入冬 提交于 2020-02-03 00:11:04

《数据结构与算法》实验和课程Github资源 

《数据结构与算法》实验报告

学生姓名

郭茁宁

院(系)

计算机科学与技术

  

1183710109

 

软件工程

实验时间

2019年12月27日(周五)

实验地点

格物213室

实验项目

实验/5-5排序算法实验比较(4学时)

实验目的:将课程的基本原理、技术和方法与实际应用相结合,训练和提高学生组织、存储和处理信息的能力,以及复杂问题的数据结构设计能力和程序设计能力,培养软件设计与开发所需要的实践能力。

实验要求:灵活运用基本的数据结构和算法知识,对实际问题进行分析和抽象;结合程序设计的一般过程和方法为实际问题设计数据结构和有效算法;用高级语言对数据结构和算法进行编程实现、调试,测试其正确性和有效性。

实验内容:排序算法的实现与实验比较

     实现一组经典的排序算法,通过实验数据的设计,考察不同规模和分布的数据对排序算法运行时间影响的规律,验证理论分析结果的正确性。

1 实现以下三组排序方法中的一组排序算法:

1)冒泡排序和快速排序;

2)插入排序和希尔排序;

3)选择排序和堆排序。

2 产生不同规模和分布的数据,以“图或表”的方式给出输入规模和分布对排序方法运行时间变化趋势的影响(画出T(n)的曲线)。并与理论分析结果比较。

3 将上述“图或表”采用图片等形式贴在实验报告中,与作适当分析或说明。

数据结构定义:

数组:存放读入元素,用于选择排序

堆:最小堆,用于堆排序

#define N 1000000

int a[N + 5];

算法设计与分析(要求画出核心内容的程序流程图):

  1. 选择排序:

从小到大排序时,排到第i个位置时,应该选择第i+1到第n个位置上最小的元素放在这个位置。在实际编程中,为了不另外开数组空间,在放置位置时,采用“与该位置原本的元素交换”的方法。

void SelectSort(int n)

{

    int mini;

    for (int i = 1; i < n; i++)

    {

        mini = i;

        for (int j = i + 1; j <= n; j++)

            if (a[j] < a[mini]) mini = j;

        if (i != mini) Swap(i, mini);

    }

    printf("SelectSort:\n");

}

  1. 堆排序:

建堆:

从堆的底层开始建立,保证建立第i层时,第i+1到logN层的元素都满足根节点元素小于其子结点元素,最后整个堆的根节点是整个堆的最小值。

取最小值:

每次取处堆的根结点,然后和任意一个叶子结点交换,并从上到小调整堆。

void HeapAdjust(int x, int n) //调整堆

{

    if (x * 2 > n) return;

    int maxi = x * 2 + 1 > n ? x * 2 : (a[x * 2< a[x * 2 + 1? x * 2 : x * 2 + 1);

    if (a[maxi] < a[x]) Swap(x, maxi), HeapAdjust(maxi, n);

}

void HeapSort(int n)

{

    for (int i = n; i >= 1; i--HeapAdjust(i, n); //建立最小堆

    for (int i = n; i > 1; i--)

    {

        Swap(1, i); //取出堆根节点

        HeapAdjust(1, i - 1); //调整堆,此时大小减1

    }

}

 

实验测试结果及结果分析:

Heap1 0.017200s

Heap2 0.020300s

Heap3 0.018800s

Heap4 0.020300s

Heap5 0.020300s

Select1 1.626500s

Select2 1.096900s

Select3 1.067200s

Select4 1.157800s

Select5 1.067200s

示例为100000规模数据,在测试中,每一个规模测试5组数据,舍弃偶然误差,取平均值,进行统计分析。

sta = GetTickCount();

for (int i = 1; i <= M; i++HeapSort(n);

end = GetTickCount();

 

printf("Heap%d %.6lfs\n", j, (double)(end - sta) / 1000 / M);

 

左纵轴、水绿色是堆排序时间,右纵轴、紫色是选择排序时间;

可以从图中看出选择排序的时间曲线是2次函数的曲线,增长速度远超希尔排序的NlogN曲线。

问题及解决方法:

  1. 时间数据存在偏差——多组数据进行平均;
  2. 一组数据排序好后再排序不具有典型性——同一规模多组不同分布;
  3. 两种排序时间数据差别太大——用不同尺度坐标轴

源程序名称:lab5.cpp

注意:正文文字为宋体小4号,图中文字为宋体5号。行距为多倍行距1.25。

      源程序与此报告打包提交,压缩包采用学号命名。

// lab5.cpp

#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <windows.h>
using namespace std;
#define Swap(x, y) (a[x] = a[x] ^ a[y], a[y] = a[x] ^ a[y], a[x] = a[x] ^ a[y])
#define N 1000000
int a[N + 5];

void HeapAdjust(int x, int n) //调整堆
{
    if (x * 2 > n) return;
    int maxi = x * 2 + 1 > n ? x * 2 : (a[x * 2] < a[x * 2 + 1] ? x * 2 : x * 2 + 1);
    if (a[maxi] < a[x]) Swap(x, maxi), HeapAdjust(maxi, n);
}

void HeapSort(int n)
{
    for (int i = n; i >= 1; i--) HeapAdjust(i, n); //建立最小堆
    for (int i = n; i > 1; i--)
    {
        Swap(1, i); //取出堆根节点
        HeapAdjust(1, i - 1); //调整堆,此时大小减1
    }
}

void Print(int n)
{
    for (int i = 1; i < n; i++) printf("%d ", a[i]);
    printf("%d\n\n", a[n]);
}

void SelectSort(int n)
{
    int mini;
    for (int i = 1; i < n; i++)
    {
        mini = i;
        for (int j = i + 1; j <= n; j++)
            if (a[j] < a[mini]) mini = j;
        if (i != mini) Swap(i, mini);
    }
}

#define M 10
int main()
{
    freopen("init.txt", "r", stdin);
    //freopen("output.txt", "w", stdout);
    int n;
    DWORD sta, end;
    scanf("%d", &n);
    for (int j = 1; j <= 5; j++)
    {
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
        sta = GetTickCount();
        for (int i = 1; i <= M; i++) HeapSort(n);
        end = GetTickCount();
        printf("Heap%d %.6lfs\n", j, (double)(end - sta) / 1000 / M);
    }
    for (int j = 1; j <= 5; j++)
    {
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
        sta = GetTickCount();
        SelectSort(n);
        end = GetTickCount();
        printf("Select%d %.6lfs\n", j, (double)(end - sta) / 1000 / M);
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}
// create_data.cpp

#include <cstdio>
#include <cstdlib>
#define N 100000
#define M (1 << 30)
int main()
{
    freopen("init.txt", "w", stdout);
    printf("%d\n", N);
    for (int j = 1; j <= 5; j++, printf("\n"))
        for (int i = 1; i <= N; i++)
        {
            int x = rand() % M + 1, y = rand() % 15;
            x = x << y;
            printf("%d ", x);
        }
    fclose(stdout);
    return 0;
}
# d.py 画图

import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns

heap_n = [10000, 50000, 100000, 200000, 300000]
heap_t = [0.001575, 0.008575, 0.016, 0.03555, 0.051975]
slct_n = [10000, 50000, 100000, 200000, 300000]
slct_t = [0.01095, 0.257425, 1.054325, 4.168375, 9.321475]

plt.rcParams["figure.figsize"] = (10.0, 6.0)
fig = plt.figure()
style = ["darkgrid", "dark", "white", "whitegrid", "ticks"]
sns.set_style(style[2])

ax1 = fig.add_subplot(111)
ax1.set_ylim([0, 1])
ax1.plot(heap_n, heap_t, "c", ms=10, lw=1, marker="o")  # 设置线粗细,节点样式
ax1.set_ylabel("Heap_time", fontsize="20")
ax1.tick_params(labelsize=10)
for x, y in zip(heap_n, heap_t):  # # 添加数据标签
    plt.text(
        x, y + 0.01, str(y) + "s", ha="center", va="bottom", fontsize=8, rotation=0
    )
# plt.plot(heap_t, label="heap")
# plt.legend(bbox_to_anchor=(0.15, 1.0))

ax2 = ax1.twinx()
ax2.set_ylim([0, 10])
ax2.plot(slct_n, slct_t, "darkviolet", ms=7, lw=1, marker="o")  # 设置线粗细,节点样式
ax2.set_ylabel("Select_time", fontsize="20")
ax2.tick_params(labelsize=10)
for x, y in zip(slct_n, slct_t):  # # 添加数据标签
    plt.text(x, y + 0.1, str(y) + "s", ha="center", va="bottom", fontsize=8, rotation=0)
# plt.plot(slct_t, label="slct")
"""
plt.legend(
    bbox_to_anchor=(0.0, 1.02, 1.0, 0.102),
    loc=0,
    ncol=3,
    mode="expand",
    borderaxespad=0.0,
)
"""
plt.savefig(r"D:\GZN\HIT\个人文件\2019秋数据结构与算法\Lab5\1.png", dpi=1000, bbox_inches="tight")
plt.grid()
plt.show()

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!