在C++和数据结构的学习中,我学到了很多种排序方法。
下面我简单列出这些排序算法的C++实现方法。还有很多不成熟的地方,以后会及时改正!!!
#include<stack> #include<assert.h> //直接插入排序 void InsertSort(int* a,size_t size) { assert(a); for (int i = 0; i < size - 1; ++i) { //进入for循环,tmp保存end后一个位置的值 int end = i; int tmp = a[end + 1]; //end之前的值所有比tmp大的都向后挪 while (end>=0 && a[end]>tmp) { //将end位置的值向后挪一个位置 a[end + 1] = a[end]; --end; } a[end + 1] = tmp; } } //打印数组 void PrintArray(int* a,size_t size) { for (int i = 0; i < size; ++i) { cout << a[i] << " "; } cout << endl; } //希尔排序 //原理类似于插入排序,把数组分为不同组,每两个元素之间有一定的间隔,提高了效率 void ShellSort(int* a,size_t size) { assert(a); int gap = size; while (gap > 1) { gap = gap/3+1; //元素间隔 for (int i = 0; i < size-gap; ++i) { int end = i; int tmp = a[end + gap]; while (end >= 0 && a[end] > tmp) { a[end + gap] = a[end]; end -= gap; } a[end + gap] = tmp; } } } //堆排序 void AdjustDown(int* a, size_t size, size_t parent) { int child = parent * 2 + 1; while (child < size) { //child指向左子树,若存在右子树且大于左子树,则child指向右子树 if ((child+1<size) && (a[child]<a[child+1])) { ++child; } //孩子节点大于父节点,就交换,同时更新父节点和子节点 if (a[child] > a[parent]) { swap(a[parent],a[child] ); parent = child; child = parent * 2 + 1; } //已经为有序状态 else { break; } } } void HeapSort(int* a, size_t size) { assert(a); //建堆(大堆) for (int i=(size-2)/2; i >= 0; --i) { AdjustDown(a, size, i); } //调整 for (int i = 0; i < size-i-1; ++i) { swap(a[0], a[size-i-1]); AdjustDown(a, size-i-1, 0); } } //单趟排序 int PartSort1(int* a, int left, int right) { //以最后一个值为key int key = a[right]; int begin = left; int end = right; while (begin < end) { //begin从前往后找到大与key的值,则停止 while (begin<end && a[begin]<key) { ++begin; } //end从后往前找到小于key的值,则停止 while (begin<end && a[end]>key) { --end; } //将大于key的值换到后面,将小于key的值换到前面 if (begin < end) { swap(a[begin], a[end]); } } //解决只有两个元素时出现的bug if (a[begin]>a[right]) { swap(a[begin], a[right]); return begin; } else { return right; } } //挖坑法 int PartSort2(int* a, int left, int right) { int key = a[right]; while (left < right) { //找到left的值大于key,停止,否则向后走 while (left < right && a[left] <= key) { ++left; } //此时将left的值填到刚才挖走的right上 if (left < right) { a[right] = a[left]; } //找到right的值小于key,停止,否则向前走 while (left < right && a[right] >= key) { --right; } //此时将right的值填到刚才挖走的left上 if (left < right) { a[left] = a[right]; } } a[left] = key; return left; } //三数取中间 int GetMidIndex(int* a, int left, int right) { int mid = left + (right - left) / 2; if (a[mid] < a[right]) { //a[left] a[mid] a[right] if (a[left] < a[mid]) { return mid; } //a[mid] a[right] a[left] if (a[right] < a[left]) { return right; } //a[mid] a[left] a[right] else { return left; } } else { //a[right] a[mid] a[left] if (a[mid] < a[left]) { return mid; } //a[left] a[right] a[mid] if (a[left] < a[right]) { return right; } //a[right] a[left] a[mid] else { return left; } } } //优化---解决快排基本有序时效率太低问题 int PartSort3(int* a, int left, int right) { int midIndex = GetMidIndex(a, left, right);//得到中间值 int key = a[right]; int prev = left - 1; int cur = left; while (cur < right) { //cur探路,找小 2, 5, 7, 1, 4, 8, 0, 9, 6, 3 //prev找大 2, 1, 0, 3, 4, 8, 7, 9, 6, 5 if (a[cur] < key && ++prev != cur) { swap(a[cur], a[prev]); } ++cur; } //将key放在刚才prev的下一个位置 swap(a[++prev], a[right]); return prev; } //快速排序 void QuickSort(int* a, int left, int right) { assert(a); if (left >= right) { return; } //数组中元素个数小于13,用插入排序效率更高 if (left - right < 13) { InsertSort(a, right-left+1); } //快排递归 else { int div = PartSort3(a, left, right); //递归排序,解决每一个子问题 QuickSort(a, left, div - 1); QuickSort(a, div + 1, right); } } //选择排序 void SelectSort(int* a, int size) { int left = 0; int right = size - 1; while (left < right) { //[left,right] 闭区间 for (int i = left; i <= right; ++i) { if (a[i] < a[left]) { swap(a[i], a[left]); } if (a[i]>a[right]) { swap(a[i], a[right]); } } //区间逐渐向中间收拢,直到left和right相遇 ++left; --right; } } //非递归快速排序 void QuickSort_NonR(int* a, int left, int right) { assert(a); stack<int> s; if (left < right) { //得到中间点 int mid = PartSort3(a, left, right); //左半部分 if (left < mid - 1) { s.push(left); s.push(mid - 1); } //右半部分 if (mid + 1 < right) { s.push(mid + 1); s.push(right); } while (!s.empty()) { //每部分先push的是左,后push的右 //取时先得到每部分的右,再是左 int r = s.top(); s.pop(); //栈中取出数,需要pop一下 int l = s.top(); s.pop(); //给当前的小数组单趟排序,并且得到中间点 mid = PartSort3(a, l, r); if (l < mid - 1) { s.push(l); s.push(mid - 1); } if (mid + 1 < r) { s.push(mid + 1); s.push(r); } } } } //合并每两个排好序的小组元素 void _Merge(int* a, int* tmp, int begin, int mid, int end) { int index = begin; int i = begin; int j = mid + 1; while (i <= mid && j <= end) { //先排小的 if (a[i] < a[j]) { tmp[index++] = a[i++]; } else { tmp[index++] = a[j++]; } } //剩余数据 while (i <= mid) { tmp[index++] = a[i++]; } while (j <= end) { tmp[index++] = a[j++]; } //将tmp中数据复制到a中 for (int i = 0; i < index; i++) { a[i] = tmp[i]; } } //递归合并 void _MergeSort(int* a, int* tmp, int left, int right) { if (a == NULL || left >= right) { return; } int mid = left + (right - left) / 2; //每次递归进行找数组的左半部分 _MergeSort(a, tmp, left, mid); //每次递归进行找数组的右半部分 _MergeSort(a, tmp, mid + 1, right); //将得到的左右两部分进行合并 _Merge(a, tmp, left, mid, right); } //归并排序 void MergeSort(int* a, size_t size) { assert(a); //新建一块size大小的空间 int* tmp = new int[size]; _MergeSort(a, tmp, 0, size - 1); delete[] tmp; } //计数排序 void CountSort(int* a, size_t size) { assert(a); int min = a[0]; int max = a[0]; for (size_t i = 0; i < size; ++i) { //找到最小值 if (a[i] < min) { min = a[i]; } //找到最大值 if (a[i] > max) { max = a[i]; } } int range = max - min + 1; //计数范围 int* count = new int[range];//计数区间 memset(count, 0, sizeof(int)*range); for (size_t i = 0; i < size; ++i) { //统计每个元素出现的次数,放在对应位置上 //已有顺序 count[a[i] - min]++; } size_t index = 0; for (int i = 0; i < range; ++i) { //可能有重复数据 while (count[i]--) { //此时在range范围中,下标即为需存储的值 a[index++] = i + min; } } } //获取最大基数 int GetMaxRadix(int* a, size_t size) { int radix = 1; int max = 10; for (size_t i = 0; i < size; ++i) { while (a[i] > max) { max *= 10; ++radix; } } return radix; } //基数排序 void LSDSort(int* a, size_t size) { assert(a); int maxRadix = GetMaxRadix(a, size); int count[10] = { 0 };//计数器 int start[10] = { 0 };//收集器 int* bucket = new int[size];//创建size个桶 int radix = 1;//基数至少为一 for (int i = 1; i <= maxRadix; ++i)//进行maxRadix次排序 { memset(count, 0, sizeof(int)* 10);//初始化计数器 for (size_t i = 0; i < size; ++i) { int num = (a[i] / radix) % 10;//计算数据在计数器中的位置 count[num]++;//统计每个桶中的数据个数 } size_t index = 1; start[0] = 0; while (index < 10) { start[index] = start[index - 1] + count[index - 1];//收集 ++index; } for (size_t i = 0; i < size; ++i) { int num = (a[i] / radix) % 10; bucket[start[num]++] = a[i];//按照start中位置信息将数组数据依次存入桶中 } radix *= 10; memcpy(a, bucket, sizeof(int)*size);//将桶中内容拷贝到a中 } delete[] bucket; }