初窥算法--从排序说起
好紧张,第一次写博客,会不会写了没人看,应该没人看,就当做学习日记吧,写写学习心得,保存代码,也为以后方面参考自己学的东西。
算法可以看做是一个工具,或者一项技术,评价一个算法的性能可以从很多方面的看,比如运行时间等,或者运行时间的增长率,即当输入的规模增大时,运行时间以多快的速度变化,本文从排序算法说起,提出了几种比较典型的排序算法,并用代码实现,供以后参考。
1 冒泡排序
冒泡排序是一种低效但是流行的算法,它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。
代码如下:
#include <iostream> //包含头文件iostream #include <vector> using namespace std; //使用命名空间std int main( ) { //////////冒泡排序////////////////// int key = 0; vector<int> ai; int num = 0; cout << "please enter the numbers that need sort:" << endl; while (cin >> num ) ai.push_back(num); //以上准备好了要排序的数组 for (unsigned i = 0; i != ai.size ()-1; ++i) { for (unsigned j = ai.size ()-1;j >= i+1; --j) { if (ai[j] < ai[j - 1]) { key = ai[j]; ai[j] = ai[j - 1]; ai[j - 1] = key; } } } for (unsigned a = 0; a != ai.size(); ++a) //输出ai { cout<< ai[a] << " "; } cout << endl; return 0; }
代码虽然简单,但是冒泡排序算法本身就是效率很低的一个算法,不值得提倡。
2 选择排序
选择排序的基本思想是:对于数组ai[n],找出其中最小的数与ai[0]进行交换,接着找出第二小的元素与ai[1]进行交换,如此循环n-1次即可,因为经过n-1次循环后,最后一个元素ai[n-1]一定是最大的。
代码如下:
#include <iostream> //包含头文件iostream #include <vector> using namespace std; //使用命名空间std int main( ) { //////////选择排序////////////////// int key = 0; unsigned i = 0,j = 0,v = 0; vector<int> ai; int num = 0; cout << "please enter the numbers that need sort:" << endl; while (cin >> num ) ai.push_back(num); while (i != ai.size()-1) { key = ai[i]; for ( j = i+1; j != ai.size()+1; ++j) { if (key >= ai[j-1]) { v = j-1; key = ai[v]; } } ai[v] = ai[i]; ai[i] = key; ++i; } for (unsigned a = 0; a != ai.size(); ++a) //输出ai { cout<< ai[a] << " "; } cout << endl; return 0; }
相比于冒泡排序,选择排序还算有点改进,但依然是低效率的。
3 插入排序
插入排序的基本思想是:对于数组ai[n],在前 i (i < n-1)项已经排好序的情况下,再把第 i+1 项插入到前面已经排好序的序列中,就像我们斗地主的时候,我们在桌子上拿走一张牌,就把他插入到我们左手已经排好顺序的牌中。
代码如下:
#include <iostream> //包含头文件iostream #include <vector> using namespace std; //使用命名空间std int main( ) { //////////插入排序////////////////// int key = 0; int i = 0; vector<int> ai; int num = 0; cout << "please enter the numbers that need sort:" << endl; while (cin >> num ) ai.push_back(num); for (unsigned j = 1; j <= ai.size()-1; ++j) { key = ai[j]; i = j-1; while (i >= 0 && ai[i] > key) { ai[i+1] = ai[i]; i = i-1; } ai[i+1] = key; } for (unsigned a = 0; a <= ai.size()-1; ++a) //输出ai { cout<< ai[a] << " "; } cout << endl; return 0; }
插入排序相比于前两种算法已经提高很多了。
4 归并排序
在了解归并排序前,先谈一下分治思想,分治思想就是将原问题分解为几个规模较小但类似于原问题的子问题,然后采用递归的方式求解这些子问题,接着再合并这些子问题的解来建立原问题的解,即:分解,解决,合并。归并排序就是利用这种思想,把要排序的序列分解成若干个子序列,分别用插入排序等方法排好这些序列,再把这些解合并起来,合并的思想也很简单,就好比桌面上有两堆牌面朝上且已经排好序的牌,最小的牌在顶上,我们希望把它们合起来,按顺序排好,我们只需比较最上面两张牌的大小,并把小的那一张取走,牌面朝下的放在桌子上,一直做下去即可。
以把一个数组分成两个数组,用插入排序排好这两个序列,再把结果合起来为例,代码如下:
#include <iostream> //包含头文件iostream #include <vector> using namespace std; //使用命名空间std //插入排序,输入形参第一个为vector对象的引用 //排序的对象是vector对象下标从p开始到q结束 void merge_sort (vector<int> &ci,unsigned p,unsigned q) { int key = 0; int i = 0; for (unsigned j = p+1; j <= q; ++j) { key = ci[j]; i = j-1; while (i >= 0 && i >= p && ci[i] > key) { ci[i+1] = ci[i]; i = i-1; } ci[i+1] = key; } } // 合并结果,输入形参第一个为vector对象的引用,第二个,第三个为数组下标 // 第一个数组下标为p到q,第二个为q+1到数组结束 void merge (vector<int> &ci,unsigned p,unsigned q) { int n1 = q - p + 1; int n2 = ci.size() - q - 1; vector<int> L; vector<int> R; for (int i = 0; i != n1; ++i) { L.push_back (ci[p+i]); } L.push_back (10000); for (int j = 0; j != n2; ++j) { R.push_back (ci[q+j+1]); } R.push_back (10000); int n = 0, m = 0; for (int k = p; k != ci.size (); ++k) { if(L[n] <= R[m]) { ci[k] = L[n]; ++n; } else { ci[k] = R[m]; ++m; } } } int main( ) { //////////归并排序////////////////// int num = 0; vector<int> ai; cout << "please enter the numbers that need sort:" << endl; while (cin >> num ) ai.push_back(num); //以上准备好了要排序的数组 int length = ai.size (); int half = length / 2; merge_sort (ai,0,half); merge_sort (ai,half+1,length - 1); merge (ai,0,half); for (unsigned a = 0; a != ai.size(); ++a) //输出ai { cout<< ai[a] << " "; } cout << endl; return 0; }
归并排序看着比较复杂,但是在数据量很大的情况下,效率明显要高于以上的几种算法。
当然,排序的算法不止这几种,还有很多,以后边学习,边思考。
由此可见算法的主要在于思想,而不在于代码,只有想不出的算法,没有用代码实现不了的算法。
终于写完,夜深了,该去写代码了。