各种排序相关题目的实现
Posted 枯萎的海风
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了各种排序相关题目的实现相关的知识,希望对你有一定的参考价值。
1. 冒泡排序
循环n次, 每次将最大值交换到最后的一个位置
class BubbleSort {
public:
int* bubbleSort(int* A, int n) {
// write code here
for (int i = 0; i != n - 1; i++){
for (int j = 0; j != n - i - 1; j++){
if (A[j] > A[j + 1])
swap(A[j], A[j + 1]);
}
}
return A;
}
};
2. 选择排序
每次从剩余部分中, 挑选出最小的值, 并与相应位置上的数值进行交换
class SelectionSort {
public:
int* selectionSort(int* A, int n) {
// write code here
for (int i = 0; i != n; i++){
int minid = i;
for (int j = i; j != n; j++){
if (A[j] < A[minid]){
minid = j;
}
}
if (minid != i)
swap(A[minid], A[i]);
}
return A;
}
};
3. 插入排序
每次向已经排序的序列中插入一个值, 保证插入后的数组还是排序的
class InsertionSort {
public:
int* insertionSort(int* A, int n) {
// write code here
for (int i = 0; i != n; i++){
int tmp = A[i];
for (int j = i - 1; j != -2; j--){
if (j == -1){
A[j + 1] = tmp;
continue;
}
if (A[j] > tmp)
A[j + 1] = A[j];
else{
A[j + 1] = tmp;
break;
}
}
}
return A;
}
};
4. 归并排序
对两个子数组分别归并排序, 然后对这两个数组合并
class MergeSort {
public:
int* mergeSort(int* A, int n) {
// write code here
if (n <= 1)
return A;
int lenA1 = n >> 1, lenA2 = n - (n >> 1);
int * A1 = mergeSort(A, lenA1);
int * A2 = mergeSort(A + lenA1, lenA2);
// merge
int * B = new int[n];
int id1 = 0, id2 = 0, id = 0;
while (id1 < lenA1 && id2 < lenA2){
if (A1[id1] < A2[id2]){
B[id++] = A1[id1++];
}
else{
B[id++] = A2[id2++];
}
}
while (id1 < lenA1){
B[id++] = A1[id1++];
}
while (id2 < lenA2){
B[id++] = A2[id2++];
}
for (int i = 0; i != n; i++){
A[i] = B[i];
}
return A;
}
};
5. 快速排序
先对原数据进行分割, 划分成 比 privot 大的和比 privot 小的部分, 然后对这两个部分分别进行快速排序
class QuickSort {
public:
int* quickSort(int* A, int n) {
// write code here
if (n <= 1)
return A;
int tmp = A[0];
int start = 0;
int stop = n - 1;
while (start < stop){
while (start < stop && A[stop] >= tmp)
stop--;
if (start < stop)
A[start] = A[stop];
while (start < stop && A[start] < tmp)
start++;
if (start < stop)
A[stop] = A[start];
}
A[stop] = tmp;
quickSort(A, stop);
quickSort(A + stop + 1, n - stop - 1);
return A;
}
};
6. 堆排序
建立一个堆, 然后对堆依次做调整
class HeapSort {
public:
int* heapSort(int* A, int n) {
// write code here
for (int i = n - 1; i != -1; i--){
modify(A, i);
swap(A[i], A[0]);
}
return A;
}
private:
void modify(int * A, int n){
for (int i = n; i != -1; i--){
if (A[i] > A[i / 2])
swap(A[i], A[i / 2]);
}
}
};
7. 希尔排序
实际上就是步长因子不断减小的插入排序
class ShellSort {
public:
int* shellSort(int* A, int n) {
// write code here
for (int gap = n / 2; gap > 0; gap /= 2){
// insert sort
for (int i = gap; i != n; i++){
int tmp = A[i];
for (int j = i - gap; j >= -gap; j -= gap){
if (j < 0){
A[j + gap] = tmp;
continue;
}
if (A[j] > tmp){
A[j + gap] = A[j];
}
else{
A[j + gap] = tmp;
break;
}
}
}
}
return A;
}
};
8. 计数排序
计算元素出现的次数, 然后排序
class CountingSort {
public:
int* countingSort(int* A, int n) {
// write code here
int mymax = INT_MIN, mymin = INT_MAX;
for (int i = 0; i != n; i++){
if (mymax < A[i])
mymax = A[i];
if (mymin > A[i])
mymin = A[i];
}
int size = mymax - mymin + 1;
int * B = new int[size];
memset(B, 0, size * sizeof(int));
for (int i = 0; i != n; i++)
B[A[i] - mymin]++;
int id = 0;
for (int i = 0; i != size; i++){
for (int j = 0; j != B[i]; j++){
A[id++] = i + mymin;
}
}
return A;
}
};
9. 基数排序
基数排序内部需要用到一个稳定的排序算法, 这里偷懒, 直接使用了STL 的 stable_sort
class RadixSort{
public:
int* radixSort(int* A, int n) {
// write code here
using namespace std::placeholders;
vector<int> arr(A, A + n);
int mymax = *max_element(arr.begin(), arr.end());
int N = 0;
while (mymax){
mymax /= 10;
N++;
}
cout << N << endl;
for (int i = 0; i != N; i++){
stable_sort(arr.begin(), arr.end(), bind(cmp, _1, _2, i));
for_each(arr.begin(), arr.end(), [](int a){cout << a << " "; });
cout << endl;
}
for (int i = 0; i != n; i++)
A[i] = arr[i];
return A;
}
private:
static bool cmp(int a, int b, int id){
int aa = int(a / pow(10, id)) % 10;
int bb = int(b / pow(10, id)) % 10;
return aa < bb;
}
};
10. 小范围排序
实际上是堆排序的一种应用
/*
已知一个几乎有序的数组,几乎有序是指,如果把数组排好顺序的话,每个元素移动的距离可以不超过k,并且k相对于数组来说比较小。请选择一个合适的排序算法针对这个数据进行排序。
给定一个int数组A,同时给定A的大小n和题意中的k,请返回排序后的数组。
*/
class ScaleSort {
public:
vector<int> sortElement(vector<int> A, int n, int k) {
// write code here
vector<int> myheap(A.begin(), A.begin() + k);
buildHeap(myheap, k);
for (int i = 0; i != n - k; i++){
A[i] = myheap[0];
myheap[0] = A[i + k];
modifyHeap(myheap, k, 0);
}
for (int i = 0; i != k; i++){
A[i + n - k] = myheap[0];
myheap[0] = myheap[k - 1 - i];
modifyHeap(myheap, k - i, 0);
}
return A;
}
private:
void buildHeap(vector<int> & myheap, int k){
for (int i = k / 2; i >= 0; i--){
modifyHeap(myheap, k, i);
}
}
void modifyHeap(vector<int> & myheap, int k, int pos){
while (true){
int targetid = 2 * pos + 1;
if (targetid >= k)
break;
if (2 * pos + 2 < k && myheap[targetid] > myheap[2 * pos + 2]){
targetid = 2 * pos + 2;
}
if (myheap[pos] < myheap[targetid])
break;
swap(myheap[targetid], myheap[pos]);
pos = targetid;
}
}
// // 递归版本的modifyHeap
// void modifyHeap(vector<int> & myheap, int k, int pos){
// int targetid = 2 * pos + 1;
// if (targetid >= k)
// return;
//
// if (2 * pos + 2 < k && myheap[targetid] > myheap[2 * pos + 2]){
// targetid = 2 * pos + 2;
// }
//
// if (myheap[pos] < myheap[targetid])
// return;
//
// swap(myheap[targetid], myheap[pos]);
// modifyHeap(myheap, k, targetid);
// }
};
11. 重复值判断
/*
请设计一个高效算法,判断数组中是否有重复值。必须保证额外空间复杂度为O(1)。
给定一个int数组A及它的大小n,请返回它是否有重复值。
*/
class Checker {
public:
bool checkDuplicate(vector<int> & a, int n) {
// write code here
buildHeap(a, n);
for (int i = 0; i != n; i++){
swap(a[n - i - 1], a[0]);
modifyHeap(a, n - i - 1, 0);
}
for (int i = 0; i != n; i++){
if (i > 0 && a[i - 1] == a[i])
return true;
}
return false;
}
private:
void buildHeap(vector<int> & myheap, int k){
for (int i = k / 2; i >= 0; i--){
modifyHeap(myheap, k, i);
}
}
void modifyHeap(vector<int> & myheap, int k, int pos){
while (true){
int targetid = 2 * pos + 1;
if (targetid >= k)
break;
if (2 * pos + 2 < k && myheap[targetid] > myheap[2 * pos + 2]){
targetid = 2 * pos + 2;
}
if (myheap[pos] < myheap[targetid])
break;
swap(myheap[targetid], myheap[pos]);
pos = targetid;
}
}
};
12. 有序数合并
从数组的尾部开始操作
/*
有两个从小到大排序以后的数组A和B,其中A的末端有足够的缓冲空容纳B。请编写一个方法,将B合并入A并排序。
给定两个有序int数组A和B,A中的缓冲空用0填充,同时给定A和B的真实大小int n和int m,请返回合并后的数组。
*/
class Merge {
public:
int* mergeAB(int* A, int* B, int n, int m) {
// write code here
int ia = n - 1, ib = m - 1, id = n + m - 1;
while (ib >= 0){
if (ia >= 0){
if (A[ia] >= B[ib])
A[id--] = A[ia--];
else
A[id--] = B[ib--];
}
else
A[id--] = B[ib--];
}
return A;
}
};
13. 三色排序
荷兰国旗问题, 三个指针区分三个数据范围{0}{1}{2}
class ThreeColor {
public:
vector<int> sortThreeColor(vector<int> A, int n) {
// write code here
int low = 0, high = n - 1, cur = 0;
while (cur <= high){
if (A[cur] == 1)
cur++;
else if (A[cur] == 0){
if (cur != low)
swap(A[cur], A[low]);
cur++;
low++;
}
else if (A[cur] == 2){
swap(A[cur], A[high]);
high--;
}
}
return A;
}
};
14. 有序矩阵查找
典型的杨氏矩阵查找问题, 从左上角入手
/*
现在有一个行和列都排好序的矩阵,请设计一个高效算法,快速查找矩阵中是否含有值x。
给定一个int矩阵mat,同时给定矩阵大小nxm及待查找的数x,请返回一个bool值,代表矩阵中是否存在x。所有矩阵中数字及x均为int范围内整数。保证n和m均小于等于1000。
*/
class Finder {
public:
bool findX(vector<vector<int> > mat, int n, int m, int x) {
// write code here
int i = 0, j = m - 1;
while (true){
if (i >= n || j < 0)
return false;
if (mat[i][j] == x)
return true;
else if (mat[i][j] > x)
j--;
else
i++;
}
return false;
}
};
15. 最短子数组
从左边开始找第一个下降的项位置, 从右边开始找第一个上升的项的位置
/*
对于一个数组,请设计一个高效算法计算需要排序的最短子数组的长度。
给定一个int数组A和数组的大小n,请返回一个二元组,代表所求序列的长度。(原序列位置从0开始标号,若原序列有序,返回0)。保证A中元素均为正整数。
*/
class Subsequence {
public:
int shortestSubsequence(vector<int> A, int n) {
// write code here
int left = 0, right = 1;
int mymax;
for (int i = 0; i != n; i++){
if (i == 0){
mymax = A[0];
}
else{
if (mymax <= A[i]){
mymax = A[i];
}
else{
left = i;
}
}
}
int mymin;
for (int i = n - 1; i != -1; i--){
if (i == n - 1){
mymin = A[n - 1];
}
else{
if (mymin >= A[i]){
mymin = A[i];
}
else{
right = i;
}
}
}
return left - right + 1;
}
};
16. 相邻两数最大差值
利用桶排序的思想 (鸽巢原理)
/*
有一个整形数组A,请设计一个复杂度为O(n)的算法,算出排序后相邻两数的最大差值。
给定一个int数组A和A的大小n,请返回最大的差值。保证数组元素多于1个。
*/
class Gap {
public:
int maxGap(vector<int> A, int n) {
// write code here
int mymax = INT_MIN, mymin = INT_MAX;
for (int i = 0; i != n; i++){
if (A[i] > mymax)
mymax = A[i];
if (A[i] < mymin)
mymin = A[i];
}
double gap = (mymax - mymin + 0.001) * 1.0 / (n + 1);
vector<vector<int>> bucks(n + 1, vector<int>{INT_MIN, INT_MAX, 0});
for (int i = 0; i != n; i++){
int id = (A[i] - mymin) / gap;
bucks[id][0] = max(bucks[id][0], A[i]);
bucks[id][1] = min(bucks[id][1], A[i]);
bucks[id][2]++;
}
int maxgap = 0;
int id = 0;
while (id < n){
while (!bucks[id][2])
id++;
int low = bucks[id][0];
id++;
while (!bucks[id][2])
id++;
int high = bucks[id][1];
int tmp = high - low;
maxgap = max(maxgap, tmp);
}
return maxgap;
}
};
以上是关于各种排序相关题目的实现的主要内容,如果未能解决你的问题,请参考以下文章