排序算法,基本是面试必考的点,个人总结了一些排序算法的实现
1. 冒泡排序
- 从起始点开始,比较相邻两个成员的大小,满足条件的,就交换位置,直到全部遍历完
void TestSort::BubbleSort(int* arr, int size) { if (arr == nullptr) { return; } for (int i = 0; i < size; ++i) { for (int j = 0; j < size - 1 - i; ++j) { if (arr[j] > arr[j + 1]) { int tmp = arr[j + 1]; arr[j + 1] = arr[j]; arr[j] = tmp; } } } }
2. 选择排序
- 第一次,从
a[1]~a[n-1]找出最小值,然后跟a[0]比较,如果小于a[0],则交换 - 第二次,从
a[2]~a[n-1]找出最小值,然后跟a[1]比较,如果小于a[1],则交换 - ...
- 第n-1次,比较
a[n-2]和a[n-1],如果后者小于前者,则交换void TestSort::SelectSort(int* arr, int size) { if (arr == nullptr) { return; } for (int i = 0; i < size - 1; ++i) { int min = i; for (int j = i + 1; j < size; ++j) { if (arr[j] < arr[i]) { min = j; } } if (i != min) { int tmp = arr[i]; arr[i] = arr[min]; arr[min] = tmp; } } }
3. 插入排序
- 主要的思路就是不断构造一个有序的序列
- 从
a[0]开始,然后将a[1]跟a[0]比较,如果小于,则交换 - 此时
a[0], a[1]为有序序列 - 接着就是
a[2]在a[0], a[1]中找合适位置 - 直到
a[n-1]在a[0] ... a[n-2]中找合适位置void TestSort::InsertSort(int* arr, int size) { if (arr == nullptr || size <= 1) { return; } for (int i = 1; i < size; ++i) { int j = i; int tmp = arr[i]; while (j >= 1 && arr[j - 1] >= tmp) { arr[j] = arr[j - 1]; --j; } if (i != j) { arr[j] = tmp; } } }
4. 归并排序
- 将数组平均分为左右两部分,再递归分下去,直到成员为1个为止
- 然后开始合并左右两个数组,使其成为一个有序的序列
- 然后回到上一层,将左右两个有序的序列再次合并,使其成为有序的序列,直到回到最上层
void TestSort::Merge(int* arr, int low, int mid, int high) { int old = low; const int size = high - low + 1; int* tmp = new int[size]; memset(tmp, 0, sizeof(int) * size); // 合并左右两个数组 int mrg = mid + 1; int index = 0; while (low <= mid && mrg <= high) { if (arr[low] < arr[mrg]) { tmp[index++] = arr[low++]; } else { tmp[index++] = arr[mrg++]; } } // 左边剩下的 while (low <= mid) { tmp[index++] = arr[low++]; } // 右边剩下的 while (mrg <= high) { tmp[index++] = arr[mrg++]; } // 赋值 memcpy(&arr[old], tmp, sizeof(int) * size); delete tmp; } void TestSort::MergeSort(int* arr, int low, int high) { if (arr == nullptr || low >= high) { return; } int mid = (low + high) / 2; MergeSort(arr, low, mid); MergeSort(arr, mid + 1, high); Merge(arr, low, mid, high); }
5. 堆排序
- 主要就是利用二叉堆堆顶最大或最小的特性来排序
- 先将数组构建为二叉堆,此时堆顶为最大值,将其与
a[n-1]交换,此时a[n-1]是有序的 - 因为交换后,堆顶就不是最大值了,所以需要调整二叉堆,将剩下的成员里最大的移到堆顶,然后和
a[n-2]交换,此时a[n-2] a[n-1]是有序的 - 重复操作,直到最后一个
- 其实,所谓的创建二叉堆和调整二叉堆,都是移动成员,使堆顶成为最大值或最小值,操作的方法是一样的,就是比较父节点和子节点,然后将最大值放到父节点,然后递归到最底层
void TestSort::HeapMax(int* arr, int size, int index) { int left = (2 * index) + 1; int right = left + 1; int max = index; // 比较左子节点 if (left < size && arr[left] > arr[index]) { max = left; } // 比较右子节点 if (right < size && arr[right] > arr[max]) { max = right; } // 交换 if (index != max) { Swap(arr[index], arr[max]); HeapMax(arr, size, max); } } void TestSort::HeapSort(int *arr, int size) { if (arr == nullptr || size <= 0) { return; } // 创建一个大根堆 int indexLast = size - 1; int indexStart = (indexLast - 1) / 2; for (int i = indexStart; i >= 0; --i) { HeapMax(arr, size, i); } // 排序大根堆 for (int i = size - 1; i >= 0; --i) { Swap(arr[0], arr[i]); HeapMax(arr, i, 0); } }
6. 快速排序
- 用
a[0]来做分割,将数组分成左a[0] ~ a[mid]和右a[mid+1] ~ a[n-1] - 然后递归对左右两边进行上面的操作,直到数组被分割到为1个成员
- 然后写代码的思路是
- 假如数组的第一位的索引为 low,数组的最后以为的索引为 high
- 用
a[0]来做比较值,设tmp = a[0] - 然后
high开始,在low < high的条件下, 如果a[high]大于等于tmp,则--high,否则,a[low] = a[high] - 然后
low开始,在low < high的条件下, 如果a[low]小于等于tmp,则++low,否则,a[high] = a[low] - 直到
low == high,a[low] = tmp,此时数组就被分成了左右两个,左边的a[low] ~ a[mid]都是小于等于tmp的 - 右边的
a[mid+1] ~ a[high]都是大于tmp的 - 再对这两个数组执行上述的操作,直到数组被分割到只剩下1个成员为止
int TestSort::GetIndex(int* arr, int low, int high) { if (arr == nullptr) { return -1; } int tmp = arr[low]; while (low < high) { while (low < high && arr[high] >= tmp) { --high; } if (low >= high) { break; } else { arr[low] = arr[high]; } while (low < high && arr[low] <= tmp) { ++low; } if (low >= high) { break; } else { arr[high] = arr[low]; } } arr[low] = tmp; return low; } void TestSort::QuickSort(int* arr, int low, int high) { if (low >= high) { return; } int index = GetIndex(arr, low, high); if (index == -1) { return; } QuickSort(arr, low, index - 1); QuickSort(arr, index + 1, high); }