从要排序序列的第一个元素开始,不断比较相邻元素的值,发现逆序则交换,将值较大的元素逐渐从前向后移动。
每找到待排序序列的最大值时,就将该最大值固定在待排序序列的尾部,且每找到一个待排序序列最大值需要循环一次,n 个值则需要循环 n 次,但最后一个值无需比较,则实际需循环 n-1 次,即 i < arr.length - 1
。
void bubbleSort (int arr[]) { for (int i = 0; i < arr.length - 1; i++) { for (int j = 0; j < arr.length - i - 1; j++) { if (arr[j] > arr[j + 1]) { int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } }
当然,该方法还可以进行优化。
定义一个布尔变量 flag
,用来标记每轮是否进行了交换。在每轮遍历开始时,将 flag
设置为 false。若当轮没有发生交换,即此时 flag
依然为 false,说明此时数组已经按照升序排列。此时外层循环直接退出,排序结束。
void bubbleSort (int arr[]) { boolean flag = false; for (int i = 0; i < arr.length - 1; i++) { flag = false; for (int j = 0; j < arr.length - i - 1; j++) { if (arr[j] > arr[j + 1]) { int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; flag = true; //该轮发生交换 } } if (!flag) { break; //数组已有序 } } }
复杂度分析:
时间复杂度 O(n^2)
空间复杂度 O(1)
选择排序每次会从未排序区间中找到最小的元素,将其放到已排序区间的末尾。同样,选择排序也需要比较 n - 1
轮,最后一轮无需比较。
void selectSort (int arr[]) { for (int i = 0; i < arr.length - 1; i++) { int minIndex = i; //初始化最小值索引 for (int j = i + 1; j < arr.length; j++) { if (arr[j] < arr[minIndex]) { minIndex = j; } } if (minIndex != i) { int temp = arr[i]; arr[i] = arr[minIndex]; arr[minIndex] = temp; } } }
复杂度分析:
时间复杂度 O(n^2)
空间复杂度 O(1)
typedef int ElemType; typedef struct { ElemType *elem; //顺序表基址,elem[0]闲置或作为监视哨 int length; //顺序表长度 } SqList;
/** * 直接插入排序 */ void insertSort(SqList &L) { int i, j; for (i = 2; i <= L.length; i++) { if (L.elem[i] < L.elem[i - 1]) { //将L.elem[i]保存在空闲的0号单元,并作为哨兵 L.elem[0] = L.elem[i]; L.elem[i] = L.elem[i - 1]; //因为有哨兵L.elem[0],所以条件 j>0 可写可不写 for (j = i - 2; L.elem[0] < L.elem[j]; j--) { L.elem[j + 1] = L.elem[j]; //记录后移 } L.elem[j + 1] = L.elem[0]; //插入到正确位置 } } }
typedef int ElemType; typedef struct { ElemType *elem; //顺序表基址,elem[0]闲置或作为监视哨 int length; //顺序表长度 } SqList;
/** * 一趟希尔插入排序 */ void shellInsert(SqList &L, int dk) { int i, j; for (i = dk + 1; i <= L.length; i++) { if (L.elem[i] < L.elem[i - dk]) { L.elem[0] = L.elem[i]; //条件j>0不能省,因为插入的步长为dk,L.elem[0]无法再充当哨兵 for (j = i - dk; j > 0 && L.elem[0] < L.elem[j]; j -= dk) { L.elem[j + dk] = L.elem[j]; //记录后移 } L.elem[j + dk] = L.elem[0]; //插入到正确位置 } } } /** * 希尔排序 */ void shellSort(SqList &L, int dlta[], int t) { int k; //按增量dlta[0..t-1]对顺序表L进行希尔插入排序 for (k = 0; k < t; k++) { shellInsert(L, dlta[k]); } }
/** * 划分算法 */ int Partition(int rcd[], int low, int high) { int pivot = rcd[low]; //记录枢纽关键字 while (low < high) //从 low 和 high 两端交替向中间移动 { while (low < high && rcd[high] >= pivot) high--; rcd[low] = rcd[high]; //比枢纽关键字小的关键字移到低端 while (low < high && rcd[low] <= pivot) low++; rcd[high] = rcd[low]; //比枢纽关键字大的关键字移到高端 } rcd[low] = pivot; //枢纽移到正确位置 return low; //返回枢纽位置 } /** * 快速排序(版本一) */ void QuickSort(int rcd[], int low, int high) { int pivotloc; //枢纽位序 if (low < high) { pivotloc = Partition(rcd, low, high); QuickSort(rcd, low, pivotloc - 1); //对枢纽之前的子序列递归快排 QuickSort(rcd, pivotloc + 1, high); //对枢纽之后的子序列递归快排 } }
/** * 快速排序(版本二) */ void quick_sort(int rcd[], int low, int high){ if(low >= high){ //递归结束条件 return; } int pivot = rcd[low]; int left = low; int right = high; while (low < high){ while (low < high && rcd[high] >= pivot) high--; rcd[low] = rcd[high]; while (low < high && rcd[low] <= pivot) low++; rcd[high] = rcd[low]; } rcd[low] = pivot; quick_sort(rcd, left, low-1); //对枢纽之前的子序列递归快排 quick_sort(rcd, high+1, right); //对枢纽之后的子序列递归快排 }
/** * 2-路归并 */ void Merge(int SR[], int TR[], int i, int m, int n){ //将相邻的有序序列SR[i..m]和SR[m+1..n]归并为有序的TR[i,n] int k, j; for (k = i, j = m + 1; i <= m && j <= n; k++){ //将SR中关键字从小到大复制到TR中 if (SR[i] <= SR[j]){ TR[k] = SR[i++]; }else{ TR[k] = SR[j++]; } } while (i <= m) //将剩余的SR[i..m]复制到TR TR[k++] = SR[i++]; while(j <= n) //将剩余的SR[j..n]复制到TR TR[k++] = SR[j++]; } /** * 归并排序(版本一) */ void MergeSort(int R1[], int R2[], int i, int low, int high){ //对R1[s..t]归并排序,若i%2==1,则排序后的记录存入R2[s..t],否则存入R1[s..t] int mid; if(low == high){ //结束拆分,准备归并 if(i%2 == 1){ R2[low] = R1[low]; //为保证最后一趟归并到 R1 数组 } }else{ mid = (low + high) / 2; //将区间[s..t]平分为[s..mid]和[mid..t] MergeSort(R1, R2, i+1, low, mid); //对区间[s..mid]递归 MergeSort(R1, R2, i+1, mid+1, high); //对区间[mid..t]递归 if(i%2 == 1){ Merge(R1, R2, low, mid, high); //将R1[s..mid]和R1[mid+1..t]归并到R2[s..t] }else{ Merge(R2, R1, low, mid, high); //将R2[s..mid]和R2[mid+1..t]归并到R1[s..t] } } }
/** * 归并排序(版本二) */ void merge_sort(int SR[], int TR[], int low, int high){ int i, j, k; if(low >= high){ //直到有序(即只剩一个数) return; } int mid = (low + high) / 2; merge_sort(SR, TR, low, mid); merge_sort(SR, TR, mid+1, high); //将相邻的有序序列SR[i..m]和SR[m+1..n]归并为有序的TR[i,n] for(k=low, i=low, j=mid+1; i<=mid && j<=high; k++){ if(SR[i] <= SR[j]){ TR[k] = SR[i++]; }else{ TR[k] = SR[j++]; } } while(i <= mid) TR[k++] = SR[i++]; while(j <= high) TR[k++] = SR[j++]; for(k=low; k<=high; k++){ SR[k] = TR[k]; //复制回待排数组 } }
int BinSearch(int rcd[], int key, int low, int high){ //在有序序列rcd[low..high]中折半查找目标关键字key int mid = (low + high) / 2; if(low > high) return -1; //找不到key,返回-1 if(rcd[mid] == key) return mid; //中间关键字与目标关键字匹配,返回中间关键字下标 else if(rcd[mid] > key) return BinSearch(rcd, key, low, mid-1); //在前半区折半查找 else return BinSearch(rcd, key, mid+1, high); //在后半区折半查找 }
int bin_search(int rcd[], int key, int low, int high){ //在有序序列rcd[low..high]中折半查找目标关键字key int mid; while(low <= high){ mid = (low + high) / 2; if(rcd[mid] == key) return mid; else if(rcd[mid] > key) high = mid - 1; //在前半区折半查找 else low = mid + 1; //在后半区折半查找 } return -1; //找不到key,返回-1 }