这门课讲的排序相当清楚,老师用很容易懂的方式讲原理,代码部分在linux下写,用gdb调试,这才是编程的学习方法。记得以前国内本科也学过,但根本没讲清楚。现在研究生又听这门公开课,发现把原理说清楚之后,代码自己很容易就实现了。
另外gdb调试工具也很好用很重要,但国内学的时候老师甚至没有提过。
几个命令:run,break, continue, next, step
https://blog.csdn.net/shaozhenghan/article/details/81370240
1 到 8 8个整数,从小到大排序。
最坏的情况,初始排列是:8,7,6,5,4,3,2,1
冒泡排序是相邻元素两两比较,然后交换。在最坏情况下需要交换8*8=64次。
因此时间复杂度是O(n^2)
以上是听课的理论,下面是课后自己写代码练习,从小到大排序。
代码实现1--C语言
#include
void swap(int *a, int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
void printArray(const int array[], size_t size)
{
for(size_t i = 0; i != size; ++i)
{
printf("%d\n", *(array+i));
}
}
// From small to large
void bubbleSort(int array[], size_t size)
{
for(size_t i = 0; i != size-1; ++i)
for(size_t i = 0; i != size-1; ++i)
{
if(array[i] > array[i+1])
swap(array+i, array+i+1);
}
}
int main(int argc, char const *argv[])
{
int a[8] = {8,7,6,5,4,3,2,1};
size_t size = 8;
printArray(a, size);
bubbleSort(a, size);
printArray(a, size);
return 0;
}
需注意C语言没有传引用形参!所以C语言版本的必须用指针来写swap函数。
代码实现2--C++
#include
void swap(int &a, int &b)
{
int tmp = a;
a = b;
b = tmp;
}
void printArray(const int array[], size_t size)
{
for(size_t i = 0; i != size; ++i)
{
std::cout << array[i] << std::endl;
}
}
// From small to large
void bubbleSort(int array[], size_t size)
{
for(size_t i = 0; i != size-1; ++i)
for(size_t i = 0; i != size-1; ++i)
{
if(array[i] > array[i+1])
swap(array[i], array[i+1]);
}
}
int main(int argc, char const *argv[])
{
int a[8] = {8,7,6,5,4,3,2,1};
size_t size = 8;
printArray(a, size);
bubbleSort(a, size);
printArray(a, size);
return 0;
}
数组是以指针形式传递给函数的,所以函数一开始并不知道数组的确切尺寸,所以应该提供一些额外的信息。C++中常用方法有两种:1. 显示地传递一个表示数组大小的形参,这也是C语言和C++11标准之前常用的; 2. 在C++11标准中,可以传递指向数组首元素和尾后元素的指针, 用std::begin() 和 std::end() 函数,更简单,更安全,避免下标越界或者访问非法指针造成segmentation error。
我这里只用了第一种,第二种见我这篇博客:https://blog.csdn.net/shaozhenghan/article/details/81437799
代码实现3--C++ 容器vector版本
#include
#include
void swap(int &a, int &b)
{
int tmp = a;
a = b;
b = tmp;
}
void printArray(const std::vector &intvec)
{
for(auto &i : intvec)
{
std::cout << i << " ";
}
std::cout << "\n";
}
// From small to large
void bubbleSort(std::vector &intvec)
{
for(size_t i = 0; i != intvec.size()-1; ++i)
for(auto it = intvec.begin(); it != intvec.end()-1; ++it)
{
if((*it) > *(it+1))
swap(*it, *(it+1));
}
// printArray(intvec);
}
int main(int argc, char const *argv[])
{
std::vector a = {8,7,6,5,4,3,2,1};
std::cout << "before sorting" << std::endl;
printArray(a);
bubbleSort(a);
std::cout << "after sorting" << std::endl;
printArray(a);
return 0;
}
使用c++的vector容器类型,可以使用迭代器,范围for循环,auto类型等C++11新标准特性,使得代码更安全,不容易出现下标越界缓冲区溢出等严重错误。
另外printArray函数形参要写成常量引用,因为函数内部不会改变vector对象,这一点要养成习惯。
1 到 8 8个整数,从小到大排序。
假设初始排列是:4,2,6,8,1,3,7,5
那么经过第一次排序后,变为:1,2,6,8,4,3,7,5, 即4和1互换了。
第二次从第二项开始比较,因为2是从第二项开始最小的数,所以不变。
最坏情况下(初始排列为:8,7,6,5,4,3,2,1),需要交换8+7+6+……+1 次,即n+……+1=n(n+1)/2
时间复杂度是O(n^2). (只考虑高次项)
代码实现一下:
#include
void swap(int &a, int &b)
{
int tmp = a;
a = b;
b = tmp;
}
void printArray(const int array[], size_t size)
{
for(size_t i = 0; i != size; ++i)
{
std::cout << array[i] << " ";
}
std::cout << "\n";
}
// From small to large
void selectSort(int array[], size_t size)
{
for(size_t j = 0; j != size-1; ++j)
for(size_t i = j+1; i != size; ++i)
{
if(array[j] > array[i])
swap(array[j], array[i]);
}
}
int main(int argc, char const *argv[])
{
int a[8] = {4, 2, 6, 8, 1, 3, 7, 5};
size_t size = 8;
printArray(a, size);
selectSort(a, size);
printArray(a, size);
return 0;
}
好处:代码简洁,避免了循环。
坏处:有内存溢出的风险。segmentation error 段错误(核心已转储)
例子:求1到整数m的累加和
int sum_one_to_m (int m)
{
if (m <= 0)
return (0);
else
return (m + sum_one_to_m (m-1));
}