算法2:数据排序

零.【摘要】在这个专刊里,我会把所有算法都讲一遍,这章讲了个种排序大全和题目。

一.【简介】排序在生活很常见,如:考试成绩排序,身高排序……排序无处不在。这章我会讲如和在C++中进行排序。

二.【排序算法大全】:

1.

冒泡排序(Bubble Sort):比较相邻的元素,如果顺序错误则交换它们,重复进行直到没有需要交换的元素。时间复杂度为O(n^2)。

  • 示例:
    #include <iostream>
    using namespace std;
    
    void bubbleSort(int arr[], int n) {
        for (int i = 0; i < n-1; i++) {
            for (int j = 0; j < n-i-1; j++) {
                if (arr[j] > arr[j+1]) {
                    swap(arr[j], arr[j+1]);
                }
            }
        }
    }
    
    int main() {
        int arr[] = {64, 34, 25, 12, 22, 11, 90};
        int n = sizeof(arr) / sizeof(arr[0]);
    
        bubbleSort(arr, n);
    
        for (int i = 0; i < n; i++) {
            cout << arr[i] << " ";
        }
        cout << endl;
    
        return 0;
    }

    选择排序(Selection Sort):依次选择未排序元素中的最小值,将其放在已排序序列的末尾。时间复杂度为O(n^2)。

  • 示例:
    #include <iostream>
    using namespace std;
    
    void selectionSort(int arr[], int n) {
        for (int i = 0; i < n-1; i++) {
            int minIdx = i;
            for (int j = i+1; j < n; j++) {
                if (arr[j] < arr[minIdx]) {
                    minIdx = j;
                }
            }
            swap(arr[i], arr[minIdx]);
        }
    }
    
    int main() {
        int arr[] = {64, 34, 25, 12, 22, 11, 90};
        int n = sizeof(arr) / sizeof(arr[0]);
    
        selectionSort(arr, n);
    
        for (int i = 0; i < n; i++) {
            cout << arr[i] << " ";
        }
        cout << endl;
    
        return 0;
    }
    插入排序(Insertion Sort):将未排序元素逐个插入到已排序序列的适当位置。时间复杂度为O(n^2)。
    
    示例:
    #include <iostream>
    using namespace std;
    
    void insertionSort(int arr[], int n) {
        for (int i = 1; i < n; i++) {
            int key = arr[i];
            int j = i - 1;
            while (j >= 0 && arr[j] > key) {
                arr[j+1] = arr[j];
                j--;
            }
            arr[j+1] = key;
        }
    }
    
    int main() {
        int arr[] = {64, 34, 25, 12, 22, 11, 90};
        int n = sizeof(arr) / sizeof(arr[0]);
    
        insertionSort(arr, n);
    
        for (int i = 0; i < n; i++) {
            cout << arr[i] << " ";
        }
        cout << endl;
    
        return 0;
    }

    快速排序(Quick Sort):选择一个基准元素,将比基准小的元素放在其左边,将比基准大的元素放在其右边,然后分别递归对左右两个子序列进行快速排序。时间复杂度为O(nlogn)。

  • 示例:
    #include <iostream>
    using namespace std;
    
    int partition(int arr[], int low, int high) {
        int pivot = arr[high];
        int i = low - 1;
        for (int j = low; j < high; j++) {
            if (arr[j] < pivot) {
                i++;
                swap(arr[i], arr[j]);
            }
        }
        swap(arr[i+1], arr[high]);
        return i+1;
    }
    
    void quickSort(int arr[], int low, int high) {
        if (low < high) {
            int pi = partition(arr, low, high);
    
            quickSort(arr, low, pi-1);
            quickSort(arr, pi+1, high);
        }
    }
    
    int main() {
        int arr[] = {64, 34, 25, 12, 22, 11, 90};
        int n = sizeof(arr) / sizeof(arr[0]);
    
        quickSort(arr, 0, n-1);
    
        for (int i = 0; i < n; i++) {
            cout << arr[i] << " ";
        }
        cout<<endl;
    
        return 0;
    }

    归并排序(Merge Sort):将数组拆分为两个子数组进行排序,然后将两个排序好的子数组合并成一个有序数组。时间复杂度为O(nlogn)。

  • 示例:
    #include <iostream>
    using namespace std;
    
    void merge(int arr[], int left, int mid, int right) {
        int n1 = mid - left + 1;
        int n2 = right - mid;
    
        int L[n1], R[n2];
    
        for (int i = 0; i < n1; i++) {
            L[i] = arr[left + i];
        }
        for (int j = 0; j < n2; j++) {
            R[j] = arr[mid + 1 + j];
        }
    
        int i = 0, j = 0, k = left;
        while (i < n1 && j < n2) {
            if (L[i] <= R[j]) {
                arr[k] = L[i];
                i++;
            }
            else {
                arr[k] = R[j];
                j++;
            }
            k++;
        }
    
        while (i < n1) {
            arr[k] = L[i];
            i++;
            k++;
        }
    
        while (j < n2) {
            arr[k] = R[j];
            j++;
            k++;
        }
    }
    
    void mergeSort(int arr[], int left, int right) {
        if (left < right) {
            int mid = left + (right - left) / 2;
    
            mergeSort(arr, left, mid);
            mergeSort(arr, mid + 1, right);
    
            merge(arr, left, mid, right);
        }
    }
    
    int main() {
        int arr[] = {64, 34, 25, 12, 22, 11, 90};
        int n = sizeof(arr) / sizeof(arr[0]);
    
        mergeSort(arr, 0, n-1);
    
        for (int i = 0; i < n; i++) {
            cout << arr[i] << " ";
        }
        cout << endl;
    
        return 0;
    }

    堆排序(Heap Sort):将数组构建为最大堆,然后将堆顶元素与最后一个元素交换,再将剩余元素重新构建为最大堆,重复进行直到所有元素有序。时间复杂度为O(nlogn)。

  • 示例:
    #include <iostream>
    using namespace std;
    
    void heapify(int arr[], int n, int i) {
        int largest = i;
        int left = 2 * i + 1;
        int right = 2 * i + 2;
    
        if (left < n && arr[left] > arr[largest]) {
            largest = left;
        }
    
        if (right < n && arr[right] > arr[largest]) {
            largest = right;
        }
    
        if (largest != i) {
            swap(arr[i], arr[largest]);
            heapify(arr, n, largest);
        }
    }
    
    void heapSort(int arr[], int n) {
        for (int i = n / 2 - 1; i >= 0; i--) {
            heapify(arr, n, i);
        }
    
        for (int i = n - 1; i > 0; i--) {
            swap(arr[0], arr[i]);
            heapify(arr, i, 0);
        }
    }
    
    int main() {
        int arr[] = {64, 34, 25, 12, 22, 11, 90};
        int n = sizeof(arr) / sizeof(arr[0]);
    
        heapSort(arr, n);
    
        for (int i = 0; i < n; i++) {
            cout << arr[i] << " ";
        }
        cout << endl;
    
        return 0;
    }

    计数排序(Counting Sort):统计数组中每个元素的出现次数,然后根据统计结果重新排列元素。时间复杂度为O(n+k),其中k是待排序元素的取值范围。

  • 示例:
    #include <iostream>
    using namespace std;
    
    void countingSort(int arr[], int n, int k) {
        int output[n];
        int count[k+1] = {0};
    
        for (int i = 0; i < n; i++) {
            count[arr[i]]++;
        }
    
        for (int i = 1; i <= k; i++) {
            count[i] += count[i-1];
        }
    
        for (int i = n-1; i >= 0; i--) {
            output[count[arr[i]]-1] = arr[i];
            count[arr[i]]--;
        }
    
        for (int i = 0; i < n; i++) {
            arr[i] = output[i];
        }
    }
    
    int main() {
        int arr[] = {4, 2, 2, 8, 3, 3, 1};
        int n = sizeof(arr) / sizeof(arr[0]);
        int k = 8;
    
        countingSort(arr, n, k);
    
        for (int i = 0; i < n; i++) {
            cout << arr[i] << " ";
        }
        cout << endl;
    
        return 0;
    }

    桶排序(Bucket Sort):将元素根据值的范围划分到不同的桶中,对每个桶中的元素进行排序,然后合并所有桶中的元素。时间复杂度为平均情况下O(n+k),其中k是桶的数量。

  • 示例:
    #include <iostream>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    void bucketSort(float arr[], int n) {
        vector<float> buckets[n];
    
        for (int i = 0; i < n; i++) {
            int index = n * arr[i];
            buckets[index].push_back(arr[i]);
        }
    
        for (int i = 0; i < n; i++) {
            sort(buckets[i].begin(), buckets[i].end());
        }
    
        int index = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < buckets[i].size(); j++) {
                arr[index++] = buckets[i][j];
            }
        }
    }
    
    int main() {
        float arr[] = {0.8, 0.2, 0.5, 0.1, 0.9, 0.3};
        int n = sizeof(arr) / sizeof(arr[0]);
    
        bucketSort(arr, n);
    
        for (int i = 0; i < n; i++) {
            cout << arr[i] << " ";
        }
        cout << endl;
    
        return 0;
    }

    基数排序(Radix Sort):按照数字的每一位进行排序,将所有元素分配到不同的桶中,重复该过程直到所有位都被处理。时间复杂度为O(kn),其中k是数字的最大位数。

  • 示例:
    #include <iostream>
    using namespace std;
    
    int getMax(int arr[], int n) {
        int mx = arr[0];
        for (int i = 1; i < n; i++) {
            if (arr[i] > mx) {
                mx = arr[i];
            }
        }
        return mx;
    }
    
    void countingSort(int arr[], int n, int exp) {
        int output[n];
        int count[10] = {0};
    
        for (int i = 0; i < n; i++) {
            count[(arr[i] / exp) % 10]++;
        }
    
        for (int i = 1; i < 10; i++) {
            count[i] += count[i-1];
        }
    
        for (int i = n-1; i >= 0; i--) {
            output[count[(arr[i] / exp) % 10] - 1] = arr[i];
            count[(arr[i] / exp) % 10]--;
        }
    
        for (int i = 0; i < n; i++) {
            arr[i] = output[i];
        }
    }
    
    void radixSort(int arr[], int n) {
        int max = getMax(arr, n);
    
        for (int exp = 1; max / exp > 0; exp *= 10) {
            countingSort(arr, n, exp);
        }
    }
    
    int main() {
        int arr[] = {170, 45, 75, 90, 802, 24, 2, 66};
        int n = sizeof(arr) / sizeof(arr[0]);
    
        radixSort(arr, n);
    
        for (int i = 0; i < n; i++) {
            cout << arr[i] << " ";
        }
        cout << endl;
    
        return 0;
    }

    希尔排序(Shell Sort):将数组分割为多个子序列,对每个子序列进行插入排序,逐步减小子序列的间隔直到为1。时间复杂度取决于间隔序列的选择。

  • 示例:
    #include <iostream>
    using namespace std;
    
    void shellSort(int arr[], int n) {
        for (int gap = n/2; gap > 0; gap /= 2) {
            for (int i = gap; i < n; i++) {
                int temp = arr[i];
                int j;
                for (j = i; j >= gap && arr[j-gap] > temp; j -= gap) {
                    arr[j] = arr[j-gap];
                }
                arr[j] = temp;
            }
        }
    }
    
    int main() {
        int arr[] = {64, 34, 25, 12, 22, 11, 90};
        int n = sizeof(arr) / sizeof(arr[0]);
    
        shellSort(arr, n);
    
        for (int i = 0; i < n; i++) {
            cout << arr[i] << " ";
        }
        cout << endl;
    
        return 0;
    }

    以上是几种常见的排序算法,每个算法都有其自己的特点和适用场景。根据需要选择合适的排序算法以获得更高效的排序结果。

三.【题目讲解】:

1:成绩排序


时间限制: 1000 ms         内存限制: 65536 KB
提交数: 65296     通过数: 27178

【题目描述】

给出班里某门课程的成绩单,请你按成绩从高到低对成绩单排序输出,如果有相同分数则名字字典序小的在前。

【输入】

第一行为n (0 < n < 20),表示班里的学生数目;

接下来的n行,每行为每个学生的名字和他的成绩, 中间用单个空格隔开。名字只包含字母且长度不超过20,成绩为一个不大于100的非负整数。

【输出】

把成绩单按分数从高到低的顺序进行排序并输出,每行包含名字和分数两项,之间有一个空格。

【输入样例】

4
Kitty 80
Hanmeimei 90
Joey 92
Tim 28

【输出样例】

Joey 92
Hanmeimei 90 
Kitty 80
Tim 28

提交 统计信息 提交记录

【题目讲解】题目可以通过创建一个包含学生信息的结构体数组,可以使用冒泡排序算法进行排序。冒泡排序的基本思想是从数组的第一个元素开始,比较相邻的两个元素,如果前面的元素大于后面的元素,则交换它们的位置。重复这个过程,直到整个数组按照指定的顺序排序。

首先,在 struct Student 中定义了一个结构体,用来存储学生的姓名和成绩。

struct Student {
    string name;
    int grade;
};

 然后,使用冒泡排序算法对学生成绩进行排序的 bubbleSort 函数。

void bubbleSort(vector<Student>& students) {
    int n = students.size();
    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - i - 1; j++) {
            if (students[j].grade < students[j + 1].grade ||
                (students[j].grade == students[j + 1].grade && students[j].name > students[j + 1].name)) {
                // 交换位置
                swap(students[j], students[j + 1]);
            }
        }
    }
}

main 函数中,首先读取学生的数目 n,然后创建一个存储学生信息的向量 students。接下来,使用循环逐个读取每个学生的姓名和成绩,并将其存储在 students 向量中。

int main() {
    int n;
    cin >> n; // 输入学生数目

    vector<Student> students(n);
    for (int i = 0; i < n; i++) {
        cin >> students[i].name >> students[i].grade; // 输入学生姓名和成绩
    }

最后,调用 bubbleSort 函数对学生成绩进行排序,并依次输出排序后的成绩单。

    bubbleSort(students); // 使用冒泡排序对成绩单进行排序

    for (int i = 0; i < n; i++) {
        cout << students[i].name << " " << students[i].grade << endl; // 输出排序后的成绩单
    }

    return 0;
}

【完整代码】:

#include <iostream>
#include <string>
#include <vector>
using namespace std;

// 定义学生结构体
struct Student {
    string name;
    int grade;
};

// 冒泡排序函数
void bubbleSort(vector<Student>& students) {
    int n = students.size();
    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - i - 1; j++) {
            if (students[j].grade < students[j + 1].grade ||
                (students[j].grade == students[j + 1].grade && students[j].name > students[j + 1].name)) {
                // 交换位置
                swap(students[j], students[j + 1]);
            }
        }
    }
}

int main() {
    int n;
    cin >> n; // 输入学生数目

    vector<Student> students(n);
    for (int i = 0; i < n; i++) {
        cin >> students[i].name >> students[i].grade; // 输入学生姓名和成绩
    }

    bubbleSort(students); // 使用冒泡排序对成绩单进行排序

    for (int i = 0; i < n; i++) {
        cout << students[i].name << " " << students[i].grade << endl; // 输出排序后的成绩单
    }

    return 0;
}

整个程序的主要思路是通过冒泡排序算法对学生成绩进行排序,当成绩相同时,按照姓名的字典序进行排序。最后输出排序后的成绩单。

【优化代码】:我们可以优化代码,这就要用到sort函数。

【格式】:sort(开始位置,结束位置,排序方式);默认排序方式是从小到大排;

以下是使用 sort 函数对 N 个数进行从大到小排序的示例代码:

#include<iostream>
#include<algorithm> 
using namespace std;
int a[10010],n;
bool cmp(int a,int b){
	 return a>b;
}//排序方式:从大到小 
int main(){
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    sort(a+1,a+1+n,cmp);//直接调用sort函数 
    for(int i=1;i<=n;i++) cout<<a[i]<<" ";
	return 0;
}

【优化答案】:

#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
using namespace std;

struct Student {
    string name;
    int score;
};

bool compare(Student a, Student b) {
    if (a.score != b.score) {
        return a.score > b.score;
    } else {
        return a.name < b.name;
    }
}

int main() {
    int n;
    cin >> n;

    vector<Student> students(n);
    for (int i = 0; i < n; i++) {
        cin >> students[i].name >> students[i].score;
    }

    sort(students.begin(), students.end(), compare);

    for (int i = 0; i < n; i++) {
        cout << students[i].name << " " << students[i].score << endl;
    }

    return 0;
}

2:合影效果


时间限制: 1000 ms         内存限制: 65536 KB
提交数: 29292     通过数: 16873

【题目描述】

小云和朋友们去爬香山,为美丽的景色所陶醉,想合影留念。如果他们站成一排,男生全部在左(从拍照者的角度),并按照从矮到高的顺序从左到右排,女生全部在右,并按照从高到矮的顺序从左到右排,请问他们合影的效果是什么样的(所有人的身高都不同)?

【输入】

第一行是人数n�(2≤n≤402≤�≤40,且至少有11个男生和11个女生)。

后面紧跟n�行,每行输入一个人的性别(男male或女female)和身高(浮点数,单位米),两个数据之间以空格分隔。

【输出】

n�个浮点数,模拟站好队后,拍照者眼中从左到右每个人的身高。每个浮点数需保留到小数点后22位,相邻两个数之间用单个空格隔开。

【输入样例】

6
male 1.72
male 1.78
female 1.61
male 1.65
female 1.70
female 1.56

【输出样例】

1.65 1.72 1.78 1.70 1.61 1.56

提交 统计信息 提交记录

题目讲解:题目要求将男生按照矮到高的顺序从左到右排列,女生按照高到矮的顺序从左到右排列,然后输出站好队后每个人的身高。我们使用结构体 Person 存储每个人的性别和身高。然后定义了自定义的比较函数 compare,按照题目要求对人员排序。在排序后,我们使用 cout 输出每个人的身高,并使用 fixed 和 setprecision 设定输出格式以保留两位小数。最后输出换行符 endl。注意,题目要求禁止使用动态数组,因此我们使用了静态数组 people

#include <iostream>
#include <algorithm>
#include <iomanip>
using namespace std;

struct Person {
    string gender;
    double height;
};

// 自定义比较函数,按照题目要求排序
bool compare(Person a, Person b) {
    if (a.gender == "male" && b.gender == "female") {
        return true; // 男生在女生前面
    } else if (a.gender == "female" && b.gender == "male") {
        return false; // 女生在男生后面
    } else {
        if (a.gender == "male") {
            return a.height < b.height; // 男生按照矮到高排序
        } else {
            return a.height > b.height; // 女生按照高到矮排序
        }
    }
}

int main() {
    int n;
    cin >> n;

    Person people[n];

    for (int i = 0; i < n; i++) {
        cin >> people[i].gender >> people[i].height;
    }

    // 使用自定义的比较函数进行排序
    sort(people, people + n, compare);

    // 输出排序后的结果
    for (int i = 0; i < n; i++) {
        // 保留两位小数
        cout << fixed << setprecision(2) << people[i].height << " ";
    }
    cout << endl;

    return 0;
}

3:分数线划定


时间限制: 1000 ms         内存限制: 65536 KB
提交数: 35162     通过数: 16713

【题目描述】

世博会志愿者的选拔工作正在 A 市如火如荼的进行。为了选拔最合适的人才,A市对所有报名的选手进行了笔试,笔试分数达到面试分数线的选手方可进入面试。面试分数线根据计划录取人数的150%150%划定,即如果计划录取m�名志愿者,则面试分数线为排名第m×150%�×150%(向下取整)名的选手的分数,而最终进入面试的选手为笔试成绩不低于面试分数线的所有选手。

现在就请你编写程序划定面试分数线,并输出所有进入面试的选手的报名号和笔试成绩。

【输入】

第一行,两个整数n,m(5≤n≤5000,3≤m≤n)�,�(5≤�≤5000,3≤�≤�),中间用一个空格隔开,其中n� 表示报名参加笔试的选手总数,m� 表示计划录取的志愿者人数。输入数据保证m×150%�×150%向下取整后小于等于n�。

第二行到第 n+1�+1 行,每行包括两个整数,中间用一个空格隔开,分别是选手的报名号k(1000≤k≤9999)�(1000≤�≤9999)和该选手的笔试成绩s(1≤s≤100)�(1≤�≤100)。数据保证选手的报名号各不相同。

【输出】

第一行,有两个整数,用一个空格隔开,第一个整数表示面试分数线;第二个整数为进入面试的选手的实际人数。

从第二行开始,每行包含两个整数,中间用一个空格隔开,分别表示进入面试的选手的报名号和笔试成绩,按照笔试成绩从高到低输出,如果成绩相同,则按报名号由小到大的顺序输出。

【输入样例】

6 3
1000 90
3239 88
2390 95
7231 84
1005 95
1001 88

【输出样例】

88 5
1005 95
2390 95
1000 90
1001 88
3239 88

【提示】

样例说明:m×150%=3×150%=4.5�×150%=3×150%=4.5,向下取整后为44。保证44个人进入面试的分数线为8888,但因为8888有重分,所以所有成绩大于等于8888的选手都可以进入面试,故最终有55个人进入面试。

提交 统计信息 提交记录

【题目讲解】这道题要求根据计划录取的志愿者人数,计算出面试分数线,并输出所有进入面试的选手的报名号和笔试成绩。我们定义了一个结构体 Candidate 存储每个选手的报名号和笔试成绩。然后定义了自定义的比较函数 compare,按照题目要求对选手排序。在排序后,我们可以根据计划录取的志愿者人数,计算出面试分数线,并遍历所有选手,统计实际进入面试的人数。最后,输出面试分数线和实际进入面试的人数,并分别输出进入面试的选手的报名号和成绩。注意,题目要求面试分数线向下取整,因此计算时需要使用 m * 150 / 100 - 1

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

struct Candidate {
    int id;
    int score;
};

bool compare(Candidate a, Candidate b) {
    if (a.score != b.score) {
        return a.score > b.score; // 按照成绩从高到低排序
    } else {
        return a.id < b.id; // 成绩相同则按照报名号从小到大排序
    }
}

int main() {
    int n, m;
    cin >> n >> m;

    vector<Candidate> candidates(n);
    for (int i = 0; i < n; i++) {
        cin >> candidates[i].id >> candidates[i].score;
    }

    // 对选手按照成绩从高到低排序
    sort(candidates.begin(), candidates.end(), compare);

    // 计算面试分数线
    int interviewScore = candidates[m * 150 / 100 - 1].score;

    // 计算实际进入面试的人数
    int interviewCount = 0;
    for (int i = 0; i < n; i++) {
        if (candidates[i].score >= interviewScore) {
            interviewCount++;
        }
    }

    // 输出面试分数线和实际进入面试的人数
    cout << interviewScore << " " << interviewCount << endl;

    // 分别输出进入面试的选手的报名号和成绩
    for (int i = 0; i < n; i++) {
        if (candidates[i].score >= interviewScore) {
            cout << candidates[i].id << " " << candidates[i].score << endl;
        }
    }

    return 0;
}

 创作不易,点个👍,观个注吧。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值