数据结构算法 - 冒泡、选择和插入排序

排序算法我们一般可以从以下几个方面入手:

1.手写排序算法;

2.时间复杂度,空间复杂度,排序的稳定性;

3.能够了解各大排序算法的优劣,能根据具体的场景选择合适的算法;

4.能够优化排序算法。

冒泡排序

冒泡排序的思想:重复地遍历要排序的列表,比较每一对相邻项,如果它们的顺序不对,就交换它们。重复遍历列表,直到不需要交换。

 

 

template<typename T>

void bubbleSort(T arr[], int len) {

for (int i = 0; i < len - 1; ++i) {

for (int j = 0; j < len - i - 1; ++j) {

if (arr[j] > arr[j + 1]) {

std::swap(arr[j], arr[j + 1]);

}

}

}

}

时间复杂度:两个 for 循环嵌套,执行的次数是 n-1+n-2+n-3+...+1 。转换一下是 1+2+3+4+...+n-1, 这便是初中数学的等差数列求和即 n²/2-n/2 。因此冒泡排序的时间复杂度是O(n²)级别的。

选择排序

选择排序的思想:重复地遍历要排序的列表,比较每一对相邻项,记录最小位置的角标,每循环一次后与最小位置进行交换。重复遍历列表,直到不需要交换。

void selectSort(int arr[], int len) {

for (int i = 0; i < len - 1; ++i) {

int min = i;

for (int j = i + 1; j < len; ++j) {

if (arr[min] > arr[j]) {

min = j;

}

}

std::swap(arr[i], arr[min]);

}

}

时间复杂度与冒泡排序的求法一致都是 O(n²) 级别的,但我们不妨来测试一下执行时间,假设对 20000 数据进行排序,我们分别来看下冒泡和选择所花费时间。

// 随机创建一个数组

int *create_array(int len, int low, int high) {

int *arr = new int[len];

for (int i = 0; i < len; ++i) {

arr[i] = rand() % (high-low) + low;

}

return arr;

}

// copy 一份数组

int *copy_array(int *arr, int len) {

int *copy_arr = (int *) malloc(sizeof(int) * len);

memcpy(copy_arr, arr, sizeof(int) * len);

return copy_arr;

}

// 创建接一组近有序的数组

int *create_nearly_ordered_array(int len, int swapNums) {

int *arr = new int[len];

for (int i = 0; i < len; ++i) {

arr[i] = i;

}

for (int i = 0; i < swapNums; ++i) {

int randomX = rand() % (len - 1);

int randomY = rand() % (len - 1);

std::swap(arr[randomX], arr[randomY]);

}

return arr;

}

// 利用函数指针来对数组排序,并打印排序时间

void sort_array(char *sortName, void(*sort)(int *, int), int *arr, int len) {

clock_t start = clock();

sort(arr, len);

clock_t end = clock();

LOGE("%s执行时间:%lf", sortName, static_cast<double>(end - start) / CLOCKS_PER_SEC * 1000);

for (int i = 1; i < len; ++i) {

assert(arr[i] >= arr[i - 1]);

}

对 20000 条随机数据进行排序,检测结果冒泡排序消耗 4.434036s 选择排序消耗 2.381274s ,对 20000 条接近有序的数据进行排序,检测结果冒泡排序消耗 2.282863s 选择排序消耗 2.379822s 。

为什么会这样我相信我们心里都有了答案,因此基于这个测试,我们便可以去优化我们的排序算法了,从两个方面入手,减少我们循环次数或者减少交换次数。这篇文章主要是分析排序算法,所以这里先不介绍优化。

插入排序

插入排序的思想:插入排序是在一个已经有序的小序列的基础上,一次插入一个元素。比较是从有序序列的末尾开始,也就是想要插入的元素和已经有序的最大者开始比起,如果比它大则直接插入在其后面,否则一直往前找直到找到它该插入的位置。

 

void insertSort(int arr[], int len) {

int j;

for (int i = 1; i < len; ++i) {

int temp = arr[i];

for (j = i; j > 0 && temp < arr[j - 1]; --j) {

arr[j] = arr[j - 1];

}

arr[j] = temp;

}

}

对 20000 条随机数据进行排序,检测结果冒泡排序消耗 4.434036s ,选择排序消耗 2.381274s ,插入排序消耗 2.054081s 。对 20000 条接近有序的数据进行排序,检测结果冒泡排序消耗 2.282863s ,选择排序消耗 2.379822s ,插入排序消耗 0.006815s 。我们可以看到对于一个接近有序的序列,插入排序所消耗的时间远远要低于其他排序算法,那是因为对于一个接近有序的数据,插入排序的时间复杂度最优可达 O(n) 级别。

END

碧茂课堂精彩课程推荐:

1.Cloudera数据分析课;

2.Spark和Hadoop开发员培训;

3.大数据机器学习之推荐系统;

4.Python数据分析与机器学习实战;

详情请关注我们公众号:碧茂大数据-课程产品-碧茂课堂

现在注册互动得海量学币,大量精品课程免费送!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShuYunBIGDATA

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值