/* * 鸡尾酒排序,设置标记位 */ voidCocktailSort(int a[], int n){ int left = 0; int right = n-1; int i; bool isSwaped = false; //设置标记位,标记上一次遍历数组时是否有交换 //如果没有交换的话就直接break,因为没有交换就说明已经排好序了 while (left < right) { isSwaped = false; for (i = left; i < right; i++) { //先从左到右选出最大的 if (a[i] > a[i+1]) { swap(a, i, i+1); isSwaped = true; } } if (!isSwaped) { break; } right--;
isSwaped = false; for (i = right; i > 0; i--) { //再从右到左选出最小的 if (a[i] < a[i-1]) { swap(a, i, i-1); isSwaped = true; } } if (!isSwaped) { break; } left++; } }
选择排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/* * 选择排序 */ voidSelectionSort(int a[], int n){ int i, j, min; for (i = 0; i < n-1; i++) { min = i; for (j = i+1; j < n; j++) { //一轮下来选出最小的元素的下标 if (a[min] > a[j]) { min = j; } } if (i != min) { //如果最小的元素不是这轮的第一个,则交换 swap(a, i, min); } } }
/* * 插入排序 */ voidInsertionSort(int a[], int n){ //默认第一个数a[0]是有序的
//分析:从第二个数开始,每个数依次跟前面已排序序列从后往前比较, //若小于前面的数,则前面的数依次往后移位,直到大于前面的数,则放在前面的数的后一位 int i; for (i = 1; i < n; i++) { int get = a[i]; //先将拿到的数保存起来 int j = i - 1; //若小于前面的数,则前面的数依次往后移位,直到大于前面的数 while (j >= 0 && a[j] > get) { a[j+1] = a[j]; j--; } //放在前面的数的后一位 a[j+1] = get; } }
/* * 插入排序的改进:二分插入排序 * * 二分插入排序:对于插入排序,如果比较操作的代价比交换操作大的话,可以采用二分查找来减少比较操作的次数。 * * 比较:当n较大时,二分插入排序的比较次数比直接插入排序的最差情况好得多,但比直接插入排序的最好情况要差, * 所当以元素初始序列已经接近升序时,直接插入排序比二分插入排序比较次数少。 * 二分插入排序元素移动次数与直接插入排序相同,依赖于元素初始序列。 */ voidInsertionSortDichotomy(int a[], int n){ int i; for (i = 1; i < n; i++) { int get = a[i]; //已排序数组的左右边界 int left = 0; int right = i - 1;
while (left <= right) { int middle = (left + right) / 2; if (a[middle] < get) { //如果拿到的数大于中间数,则应放到后半部分 left = middle + 1; } else { //否则应放在左半部分(包括了等于中间数的情况) right = middle - 1; } } //执行完循环后,拿到的数应放在left的位置(结果就是这样)
/* * 合并两个已经排好序的数组a[left...mid]和a[mid+1...right] */ voidMerge(int a[], int left, int mid, int right, int temp[]){ int i = left; //第一个数组开头位标 int j = mid + 1; //第二个数组开头位标 int k = 0;
//比较两数组元素大小 while (i <= mid && j <= right) { temp[k++] = a[i] <= a[j] ? a[i++] : a[j++]; } //将剩余未比较的元素放入temp数组中 while (i <= mid) { temp[k++] = a[i++]; } while (j <= right) { temp[k++] = a[j++]; } //将temp数组(已排好序)赋给数组a int len = right - left + 1; //合并后的数字长度,注意:这里必须先存起来,因为循环体中的赋值操作改变了left for (k = 0; k < len; k++) { a[left++] = temp[k]; //注意:是从a[left]开始赋值,而不是a[0] } }
/* * 归并排序 */ voidMergeSort(int a[], int left, int right, int temp[]){ if (left == right) { return; } int mid = (left + right) / 2; MergeSort(a, left, mid, temp); MergeSort(a, mid+1, right, temp); //合并两个已排好序的子数组 Merge(a, left, mid, right, temp); }