Only_排序 解题报告汇总

Problem A:(HDU 1040)

题意:给定数据组数T,然后对于每一组数据,首先输入一个N,表示该组共有N个数,后面跟N个数字,要求输出.

插入排序
#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#define MAXN 1005

// MAXN要定义的稍微大一点,防止数组越界 



/*

该题数据较小,所以一般的排序的算法应该都可以AC此题 

*/



int N, seq[MAXN];



void insertsort(int m, int n) { // 带了个区间 

    for (int i = m+1; i <= n; ++i) {

        seq[m-1] = seq[i]; // 使用区间的左边界的左边一位来存储这个值 

        int j;

        for (j = i-1; seq[j] > seq[m-1]; --j) { // 最后一定会在我们设置的m-1位置停下来 

            seq[j+1] = seq[j];

        }

        seq[j+1] = seq[m-1];

    }

}



int main() {

    int T;

    scanf("%d", &T); // 表示有T组数据

    while (T--) {

        scanf("%d", &N); // 读入N,表示后面有N个数据 

        for (int i = 1; i <= N; ++i) {

            scanf("%d", &seq[i]); // scanf("%d", seq + i); 也可    

        }

        insertsort(1, N);

        for (int i = 1; i <= N; ++i) {

            printf(i == 1 ? "%d" : " %d", seq[i]);    

        }

        printf("\n"); // 记得最后输出一个回车 

    }  

    return 0;    

}
快速排序
#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#define MAXN 1005

// MAXN要定义的稍微大一点,防止数组越界 



/*

该题数据较小,所以一般的排序的算法应该都可以AC此题 

*/



int N, seq[MAXN];



void swap(int x, int y) { 

    // 把数组下标传进来,同样能够交换两个两个元素,同时避免了指针 

    int t = seq[x];

    seq[x] = seq[y];

    seq[y] = t;    

}



void qsort(int m, int n) {

    if (m >= n) return; // 递归结束条件 

    int i = m-1;

    for (int j = m; j < n; ++j) {

        if (seq[j] < seq[n]) {

            swap(++i, j); // 将交换封装成一个函数 

        }

    }

    swap(i+1, n);

    qsort(m, i); // 直接在该函数中递归 

    qsort(i+2, n);

}



int main() {

    int T;

    scanf("%d", &T); // 表示有T组数据

    while (T--) {

        scanf("%d", &N); // 读入N,表示后面有N个数据 

        for (int i = 0; i < N; ++i) {

            scanf("%d", &seq[i]); // scanf("%d", seq + i); 也可    

        }

        qsort(0, N-1);

        for (int i = 0; i < N; ++i) {

            printf(i == 0 ? "%d" : " %d", seq[i]);    

        }

        printf("\n"); // 记得最后输出一个回车 

    }  

    return 0;    

}

 

 


Problem B:(HDU 1106)

题意:同样是要对给定的数字排序,不过这次的数字要从一串字符串中提取出来.这个上次和大家讲了想法.就不在详细叙述了,方法绝对不会是唯一的,只要能够分离出数字就可以了.

快速排序
#include <stdio.h>

#include <string.h>

#include <stdlib.h>



char str[1005];



int num[1005];



void swap(int *p, int *q) { // 交换元素函数,使用指针实现 

    int t = *p;

    *p = *q;

    *q = t;    

}



int partition(int a[], int m, int n) {

    int i = m-1;

    for (int j = m; j < n; ++j) {

        if (a[j] < a[n]) {

            ++i;

            swap(&a[i], &a[j]);

        }

    }

    swap(&a[i+1], &a[n]); // 注意要传递地址,否则出错 

    return i + 1;

}



void quicksort(int a[], int m, int n) {

    if (m < n) {

        int pos = partition(a, m, n);

        quicksort(a, m, pos-1);

        quicksort(a, pos+1, n);    

    }

}



int main() {

    int len;

    while (scanf("%s", str) != EOF) {

        len = strlen(str);

        str[len] = '5';

        len += 1;

        for (int i = 0; i < len; ++i) {

            str[i] -= '0';

        }

        int t = 0, cnt = 0, useful = (str[0] != 5); // 要弄清楚如何提取出各个数字 

        for (int i = 0; i < len; ++i) {

            if (str[i] == 5) {

                if (useful) {

                    num[++cnt] = t;

                    t = 0;

                }

                useful = (str[i+1] != 5); 

                // 5后面是否跟着不是5的数字决定了下一个5可以作为提取数字的标记 

            } else {

                t *= 10;

                t += str[i];

            }

        }

    /*    for (int i = 1; i <= cnt; ++i) { // 调试代码 

            printf("%d ", num[i]);    

        }

        puts("");*/

        quicksort(num, 1, cnt);

        for (int i = 1; i <= cnt; ++i) {

            printf(i == 1 ? "%d" : " %d", num[i]);    

        }

        puts("");

    }

    return 0;        

}

 

 

Problem C:(HDU 2673)

题意:给定一个序列,要求输出一个最大的数后,输出剩下数中的最小的一个,然后再输出剩下的数中最大中的一个,如此反复.

解法:这题在排序后还需要做一件事,就是定义两个变量,一个从第一位开始,一个从最后一位开始,交替输出数字.

View Code
#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#define MAXN 10005



int N, seq[MAXN];



inline void swap(int x, int y) { 

    // 把数组下标传进来,同样能够交换两个两个元素,同时避免了指针 

    int t = seq[x];

    seq[x] = seq[y];

    seq[y] = t;

}



void qsort(int m, int n) {

    if (m >= n) return; // 递归结束条件 

    int i = m-1;

    for (int j = m; j < n; ++j) {

        if (seq[j] < seq[n]) {

            swap(++i, j); // 将交换封装成一个函数 

        }

    }

    swap(i+1, n);

    qsort(m, i); // 直接在该函数中递归 

    qsort(i+2, n);

}



int main() {

    int i, j;

    while (scanf("%d", &N) == 1) {

        for (i = 1; i <= N; ++i) {

            scanf("%d", &seq[i]);    

        }

        qsort(1, N);

        printf("%d", seq[N]); // N至少为1,因此我们先输出一个数,这样后面的格式就好控制 

        for (i = 1, j = N-1; i <= j; ++i, --j) {

            if (i == j) { // 这样就只要输出一个数字就可以了

                printf(" %d", seq[j]);

            } else {

                printf(" %d %d", seq[i], seq[j]);

                // 由于先输出了一个大的数,因此后面就是小,大,小,大的序列了

            }

        }

        puts("");

    }

    return 0;

}

虚拟OJ C++提交要去掉中文注释,杭电上C++,G++均可AC.

 

 

Problem D:(HDU 1425)

题意:给定一个序列,含有N个数字,要求输出前M大的数字.

解法:不改前面从小到大排序的代码的话,从后面输出就可以了.

View Code
#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#define MAXN 1000005



int M, N, seq[MAXN];



inline void swap(int x, int y) { 

    // 把数组下标传进来,同样能够交换两个两个元素,同时避免了指针 

    int t = seq[x];

    seq[x] = seq[y];

    seq[y] = t;

}



void qsort(int m, int n) {

    if (m >= n) return; // 递归结束条件 

    int i = m-1;

    for (int j = m; j < n; ++j) {

        if (seq[j] < seq[n]) {

            swap(++i, j); // 将交换封装成一个函数 

        }

    }

    swap(i+1, n);

    qsort(m, i); // 直接在该函数中递归 

    qsort(i+2, n);

}



int main() {

    while (scanf("%d %d", &N, &M) == 2) {

        for (int i = 1; i <= N; ++i) {

            scanf("%d", seq + i);    

        }

        qsort(1, N);

        for (int i = N, j = 0; j < M; --i, ++j) { // j用来统计输出了多少个数字 

            printf(i == N ? "%d" : " %d", seq[i]);

        }

        puts("");

    }

    return 0;    

}

 

 

Problem E:(HDU 2689)

题意:给定N个数(大小为1-N),问如果只能交换相邻的数,问至少多少次能够使得这个序列递增的序列.由于给定的数一定各不相同因此也就不会出现相同的元素是否交换的问题了.如果有相同元素的话,那么我们肯定不对其进行交换.

解法:由于只能够交换相邻的位数,因此每次只能够消除一个逆序对.所以求出序列中有多少个逆序对就可以了.我们知道冒泡排序,插入排序就是不停的交换相邻的算法,因此可以使用这两种排序方式来统计.或者直接统计.

直接统计
#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#define MAXN 1005



int N, seq[MAXN];



int main() {

    int cnt; // count 计数用 

    while (scanf("%d", &N) != EOF) {

        cnt = 0;

        for (int i = 1; i <= N; ++i) {

            scanf("%d", seq + i);

            for (int j = 1; j < i; ++j) {

                if (seq[j] > seq[i]) {// 存在逆序对    

                    ++cnt;

                }

            }

        }

        printf("%d\n", cnt);

    }

    return 0;

}
冒泡排序
#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#define MAXN 1005 



int N, seq[MAXN], cnt;



void swap(int a, int b) {

    int t = seq[a];

    seq[a] = seq[b];

    seq[b] = t;    

}



void bubble_sort(int m, int n) {

    int ti = n-m; // n-m+1个数,只要做n-m次冒泡就可以了 

    for (int i = 1; i <= ti; ++i) {

        for (int j = m; j <= n-i; ++j) {// 最后一对需要比较的数前面那个数的编号是n-i

            if (seq[j] > seq[j+1]) {

                swap(j, j+1);

                ++cnt;

            }

        }

    }

}



int main() {

    while (scanf("%d", &N) != EOF) {

        cnt = 0;

        for (int i = 1; i <= N; ++i) {

            scanf("%d", &seq[i]);    

        }

        bubble_sort(1, N);

        printf("%d\n", cnt);

    }

    return 0;

}
插入排序
#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#define MAXN 1005 



int N, seq[MAXN], cnt;



void insert_sort(int m, int n) {

    int i, j;

    for (i = m+1; i <= n; ++i) {

        seq[m-1] = seq[i];

        for (j = i-1; seq[j] > seq[m-1]; --j) {

            seq[j+1] = seq[j];

            ++cnt;

        }

        seq[j+1] = seq[m-1];

    }

}



int main() {

    while (scanf("%d", &N) != EOF) {

        cnt = 0;

        for (int i = 1; i <= N; ++i) {

            scanf("%d", &seq[i]);    

        }

        insert_sort(1, N);

        printf("%d\n", cnt);

    }

    return 0;

}

 

 

Problem F:(HDU 1236)

题意:给定学生信息,还有题目的分数,需要统计出超过分数线的人数,然后将这些人按照成绩从高到低排列,成绩相同按照学号从小到大排列.

解法:需要使用一个函数来取代原来红果果的大于(<) 或 小于(>) 的比较.

View Code
#include<stdio.h>

#include<stdlib.h>

#include<math.h>

#include<string.h>

#define MAXN 1005



int N, M, G, score[15];



struct STU {

    char name[25];

    int score;

}stu[MAXN];



void swap(int a, int b) {

    struct STU t;

    t = stu[a];

    stu[a] = stu[b];

    stu[b] = t;

}



int bigger(int a, int b) {

    if (stu[a].score != stu[b].score) { 

        // 如果分数不相等的话,那么就返回前者是否大于后者,满足一个从大到小的性质 

        return stu[a].score > stu[b].score;

    } else { // 进入这个else说明分数一定是相等的,接着按照学号从小到大牌 

        return strcmp(stu[a].name, stu[b].name) < 0;

        // 自己去查下strcmp函数的功能. 把两个字符串挨位进行一个比较

        // 返回值-1,表示前面比后面小, 返回值1表示比后面大, 0 表示相等 

    } 

}



void qsort(int m, int n) {

    if (m >= n) return;

    int i = m - 1;

    for (int j = m; j < n; ++j) {

        if (bigger(j, n)) { 

        // 就相当于别的题目中的a[j] > a[n]表示一个关系

        // 从小到大是a[j] < a[n] 从大到小就反过来 

            swap(++i, j);

        }

    }    

    swap(i+1, n);

    qsort(m, i);

    qsort(i+2, n);

}



int main() {

    int cnt;

    while (scanf("%d", &N), N) {

        cnt = 0;

        scanf("%d %d", &M, &G);

        for (int i = 1; i <= M; ++i) {

            scanf("%d", score + i);

        }

        for (int i = 1; i <= N; ++i) {

            int lim, c, sum = 0;

            scanf("%s %d", stu[i].name, &lim);

            for (int j = 1; j <= lim; ++j) {

                scanf("%d", &c);

                sum += score[c];

            }

            stu[i].score = sum;

            cnt += sum >= G ? 1 : 0;

        }

        qsort(1, N);

        printf("%d\n", cnt);

        for (int i = 1; i <= cnt; ++i) {

            printf("%s %d\n", stu[i].name, stu[i].score);    

        }

    }

    return 0;

}

 

以上是所有题目的解题思路及代码......  大家加油!!!

你可能感兴趣的:(排序)