排序算法
1.排序算法
.
计算机科学发展至今,已经出现了许多种不同的排序算法。在本章的课程中,介绍了插入排序(insertion sort)、冒泡排序(bubble sort)、归并排序(merge sort)、选择排序(selection sort) 和 快速排序(quick sort)这 5 种排序算法。
- 根据算法的时间复杂度,可以将排序算法分为复杂度为 O(nlogn)、O(n) 或 O(n2) 等时间复杂度的排序算法。比如 O(n) 的 基数排序(radix sort)、O(nlogn) 的归并排序、O(n2)的冒泡排序。
- 根据排序过程中元素是否完全保存在内存中,可以将算法分为 内部排序(internal sort) 和 外部排序(external sort)。本章介绍的这 55 种排序算法都是内部排序算法。
- 对于一个排序算法,如果排序前的线性表中满足 i < j 且 ai = aj 的任意两个元素 ai和 aj,在排序后 ai 仍在 aj之前,则称这个排序算法为 稳定排序(stable sort),否则称这个排序算法为 不稳定排序(unstable sort)。
排序算法在数据结构和算法中有非常重要的地位。有很多算法都要基于排序算法的结果来进行,比如折半查找算法等。对于现有的排序算法,我们已经可以证明其中几种(堆排序、归并排序)的运行时间上界 O(nlogn) 和比较排序算法(不考虑不用通过比较获得排序结果的希尔排序等)的最坏情况下界是相等的,也就是说,这几种算法已经是渐进最优的比较排序算法。
2.三种稳定排序算法
1)插入排序
插入排序是一种非常直观的排序算法,它的基本思想是将线性表分为已排序的前半部分和待排序的后半部分,从待排序部分选出第一个元素,插入到已排序部分的对应位置中,直到全部记录都插入到已排序部分中。
插入排序每次插入的时间复杂度为 O(n),一共执行 n−1 次,因此总体时间复杂度为 O(n2)。查找插入位置的过程可以使用折半查找算法将查找的时间复杂度优化到 O(logn),但因为还需要 O(n) 的时间复杂度来在顺序表上执行移动操作,所以总体时间复杂度依然是 O(n2)。
1 /*插入排序的实现*/ 2 #include <iostream> 3 #include <cstring> 4 using namespace std; 5 class Vector { 6 private: 7 int size, length; 8 int * data; 9 public: 10 Vector(int input_size) { 11 size = input_size; 12 length = 0; 13 data = new int[size]; 14 } 15 ~Vector() { 16 delete[] data; 17 } 18 bool insert(int loc, int value) { 19 if (loc < 0 || loc > length) { 20 return false; 21 } 22 if (length >= size) { 23 return false; 24 } 25 for (int i = length; i > loc; --i) { 26 data[i] = data[i - 1]; 27 } 28 data[loc] = value; 29 length++; 30 return true; 31 } 32 void print() { 33 for (int i = 0; i < length; ++i) { 34 if (i > 0) { 35 cout << " "; 36 } 37 cout << data[i]; 38 } 39 cout << endl; 40 } 41 void sort() { 42 for(int i=0;i<length;i++){ 43 for(int j=i-1;j>=0;j--){ 44 if(data[j]>data[j+1]){ 45 swap(data[j],data[j+1]); 46 } 47 else{ 48 break; 49 } 50 } 51 } 52 } 53 }; 54 int main() { 55 int n; 56 cin >> n; 57 Vector arr(n); 58 for (int i = 0; i < n; ++i) { 59 int x; 60 cin >> x; 61 arr.insert(i, x); 62 } 63 arr.sort(); 64 arr.print(); 65 return 0; 66 }
2)冒泡排序
和插入排序算法不同,冒泡排序算法是一种基于交换的排序算法。基于交换的排序,是指根据线性表中两个元素关键字的比较结果来对换这两个元素在序列中的位置。
冒泡排序算法的基本思想为:假如待排序线性表的长度为n,从前往后两两比较相邻元素的关键字,若 ai-1>ai,则交换它们,直到线性表比较完成。每趟交换以后最后一个元素一定是最大的,不再参与下一趟交换。也就是对于第 i 趟交换,只需要比较到 an-i 即可。直到一趟比较内没有进行交换,算法结束。时间复杂度和插入排序一样,也为O(n2)。
1 /*冒泡排序的实现*/ 2 #include <iostream> 3 #include <cstring> 4 using namespace std; 5 class Vector { 6 private: 7 int size, length; 8 int * data; 9 public: 10 Vector(int input_size) { 11 size = input_size; 12 length = 0; 13 data = new int[size]; 14 } 15 ~Vector() { 16 delete[] data; 17 } 18 bool insert(int loc, int value) { 19 if (loc < 0 || loc > length) { 20 return false; 21 } 22 if (length >= size) { 23 return false; 24 } 25 for (int i = length; i > loc; --i) { 26 data[i] = data[i - 1]; 27 } 28 data[loc] = value; 29 length++; 30 return true; 31 } 32 void print() { 33 for (int i = 0; i < length; ++i) { 34 if (i > 0) { 35 cout << " "; 36 } 37 cout << data[i]; 38 } 39 cout << endl; 40 } 41 void sort() { 42 for(int i=0;i<length-1;i++){ 43 bool swapped=false; 44 for(int j=0;j<length-i-1;j++){ 45 if(data[j]>data[j+1]){ 46 swap(data[j],data[j+1]); 47 swapped=true; 48 } 49 } 50 if(swapped==false){ 51 break; 52 } 53 } 54 } 55 }; 56 int main() { 57 int n; 58 cin >> n; 59 Vector arr(n); 60 for (int i = 0; i < n; ++i) { 61 int x; 62 cin >> x; 63 arr.insert(i, x); 64 } 65 arr.sort(); 66 arr.print(); 67 return 0; 68 }
3)归并排序
1 /*归并排序*/ 2 #include <iostream> 3 #include <cstring> 4 using namespace std; 5 class Vector { 6 private: 7 int size, length; 8 int * data, * temp; 9 void merge_sort(int l,int r){ 10 if(l==r){ 11 return; 12 } 13 int mid=(l+r)/2; 14 merge_sort(l,mid); 15 merge_sort(mid+1,r); 16 int x=l,y=mid+1,loc=l; 17 while(x<=mid||y<=r){ 18 if(x<=mid&&(y>r||data[x]<=data[y])){ 19 temp[loc]=data[x]; 20 x++; 21 } 22 else{ 23 temp[loc]=data[y]; 24 y++; 25 } 26 loc++; 27 } 28 for(int i=l;i<=r;i++){ 29 data[i]=temp[i]; 30 } 31 } 32 public: 33 Vector(int input_size) { 34 size = input_size; 35 length = 0; 36 data = new int[size]; 37 temp = new int[size]; 38 } 39 ~Vector() { 40 delete[] data; 41 delete[] temp; 42 } 43 bool insert(int loc, int value) { 44 if (loc < 0 || loc > length) { 45 return false; 46 } 47 if (length >= size) { 48 return false; 49 } 50 for (int i = length; i > loc; --i) { 51 data[i] = data[i - 1]; 52 } 53 data[loc] = value; 54 length++; 55 return true; 56 } 57 void print() { 58 for (int i = 0; i < length; ++i) { 59 if (i > 0) { 60 cout << " "; 61 } 62 cout << data[i]; 63 } 64 cout << endl; 65 } 66 void sort() { 67 merge_sort(0,length-1); 68 } 69 }; 70 int main() { 71 int n; 72 cin >> n; 73 Vector arr(n); 74 for (int i = 0; i < n; ++i) { 75 int x; 76 cin >> x; 77 arr.insert(i, x); 78 } 79 arr.sort(); 80 arr.print(); 81 return 0; 82 }
3.不稳定排序算法
常见的不稳定排序算法有 选择排序(selection sort)、快速排序(quick sort)、堆排序(heap sort)、希尔排序(shell sort) 等。在本章的课程中,我们只介绍其中的选择排序和快速排序。
1)选择排序
1 /*选择排序的实现*/ 2 #include <iostream> 3 #include <cstring> 4 using namespace std; 5 class Vector { 6 private: 7 int size, length; 8 int * data; 9 public: 10 Vector(int input_size) { 11 size = input_size; 12 length = 0; 13 data = new int[size]; 14 } 15 ~Vector() { 16 delete[] data; 17 } 18 bool insert(int loc, int value) { 19 if (loc < 0 || loc > length) { 20 return false; 21 } 22 if (length >= size) { 23 return false; 24 } 25 for (int i = length; i > loc; --i) { 26 data[i] = data[i - 1]; 27 } 28 data[loc] = value; 29 length++; 30 return true; 31 } 32 void print() { 33 for (int i = 0; i < length; ++i) { 34 if (i > 0) { 35 cout << " "; 36 } 37 cout << data[i]; 38 } 39 cout << endl; 40 } 41 void sort() { 42 for(int i=0;i<length-1;i++){ 43 for(int j=i+1;j<length;j++){ 44 if(data[i]>data[j]){ 45 swap(data[i],data[j]); 46 } 47 } 48 } 49 } 50 }; 51 int main() { 52 int n; 53 cin >> n; 54 Vector arr(n); 55 for (int i = 0; i < n; ++i) { 56 int x; 57 cin >> x; 58 arr.insert(i, x); 59 } 60 arr.sort(); 61 arr.print(); 62 return 0; 63 }
3)快速排序
1 /*快速排序的实现*/ 2 #include <iostream> 3 #include <cstring> 4 using namespace std; 5 class Vector { 6 private: 7 int size, length; 8 int * data; 9 void quick_sort(int l,int r){ 10 int pivot=data[l],i=l,j=r; 11 do{ 12 while(i<=j&&data[i]<pivot){ 13 i++; 14 } 15 while(i<=j&&data[j]>pivot){ 16 j--; 17 } 18 if(i<=j){ 19 swap(data[i],data[j]); 20 i++; 21 j--; 22 } 23 }while(i<=j); 24 if(l<j){ 25 quick_sort(l,j); 26 } 27 if(r>i){ 28 quick_sort(i,r); 29 } 30 } 31 public: 32 Vector(int input_size) { 33 size = input_size; 34 length = 0; 35 data = new int[size]; 36 } 37 ~Vector() { 38 delete[] data; 39 } 40 bool insert(int loc, int value) { 41 if (loc < 0 || loc > length) { 42 return false; 43 } 44 if (length >= size) { 45 return false; 46 } 47 for (int i = length; i > loc; --i) { 48 data[i] = data[i - 1]; 49 } 50 data[loc] = value; 51 length++; 52 return true; 53 } 54 void print() { 55 for (int i = 0; i < length; ++i) { 56 if (i > 0) { 57 cout << " "; 58 } 59 cout << data[i]; 60 } 61 cout << endl; 62 } 63 void sort() { 64 quick_sort(0,length-1); 65 } 66 }; 67 int main() { 68 int n; 69 cin >> n; 70 Vector arr(n); 71 for (int i = 0; i < n; ++i) { 72 int x; 73 cin >> x; 74 arr.insert(i, x); 75 } 76 arr.sort(); 77 arr.print(); 78 return 0; 79 }