排序算法题目及解析

选举学生会

洛谷 P1271

题目描述

学校正在选举学生会成员,有 n ( n ≤ 999 ) n(n\le 999) n(n999) 名候选人,每名候选人编号分别从 1 到 n n n,现在收集到了 m ( m < = 2000000 ) m(m<=2000000) m(m<=2000000) 张选票,每张选票都写了一个候选人编号。现在想把这些堆积如山的选票按照投票数字从小到大排序。

输入格式

输入 n n n m m m 以及 m m m 个选票上的数字。

输出格式

求出排序后的选票编号。

样例 #1

样例输入 #1

5 10
2 5 2 2 5 2 2 2 1 2

样例输出 #1

1 2 2 2 2 2 2 2 5 5

解体思路:就是简单的排序输出就行了,我们这儿不使用标准库的排序算法,自己手写随便两个排序

/*
 * @Author: xiguan
 * @Email: xiguan.teng@qq.com
 * @Version: 1.0
 * @Date: 2022-08-22 16:28:59
 * @LastEditTime: 2022-09-26 18:57:54
 */
#include <bits/stdc++.h>
#include <stdlib.h>

using namespace std;
typedef long long ll;

ll n, m;
vector<ll> arr;


// O(n^2) 的算法有两个样例超时了,我们换个O(n*lg^n)的
void insertSort( vector<ll> &v ){
    ll len = v.size();
    if( len <= 1 ){
        return ;
    }

    for( int idx = 1; idx < len; ++ idx ){
        for( int jdx = idx - 1; jdx >= 0 && v[jdx] > v[jdx + 1]; -- jdx ){
            swap( v[jdx], v[jdx + 1] );
        }
    }
}

pair<ll, ll> partition( vector<ll> &v, ll L, ll R ){
    ll less_than = L - 1;
    ll more_than = R;

    while( L < more_than ){
        if( v[L] < v[R] ){
            swap( v[++ less_than], v[L ++] );
        }else if( v[L] > v[R] ){
            swap( v[-- more_than], v[L] );
        }else{
            L ++;
        }
    }

    swap( v[more_than], v[R] );

    return { less_than + 1, more_than };
}

void quickSort( vector<ll> & v, ll L, ll R ){
    if( L < R ){
        pair<ll, ll> t = partition( v, L, R );
        quickSort( v, L, t.first - 1 );
        quickSort( v, t.second + 1, R );
    }
}


int main( int argc, char *argv[] ){

    cin >> n >> m;
    for( int idx = 0; idx < m; ++ idx ){
        ll t; cin >> t;
        arr.push_back( t );
    }

    quickSort( arr, 0, m - 1 );

    for( int idx = 0; idx < m; ++ idx ){
        cout << arr[idx] << ' ';
    }
    cout << endl;
    return 0;
}

快速排序

洛谷 P1177

题目描述

利用快速排序算法将读入的 N N N 个数从小到大排序后输出。

快速排序是信息学竞赛的必备算法之一。对于快速排序不是很了解的同学可以自行上网查询相关资料,掌握后独立完成。(C++ 选手请不要试图使用 STL,虽然你可以使用 sort 一遍过,但是你并没有掌握快速排序算法的精髓。)

输入格式

1 1 1 行为一个正整数 N N N,第 2 2 2 行包含 N N N 个空格隔开的正整数 a i a_i ai,为你需要进行排序的数,数据保证了 A i A_i Ai 不超过 1 0 9 10^9 109

输出格式

将给定的 N N N 个数从小到大输出,数之间空格隔开,行末换行且无空格。

样例 #1

样例输入 #1

5
4 2 4 5 1

样例输出 #1

1 2 4 4 5

解题思路:同样也是排序输出就行,我们上一次用了快排,这次用归并好了,O(n^2) 的算法很明显会超时,就不写了

/*
 * @Author: xiguan
 * @Email: xiguan.teng@qq.com
 * @Version: 1.0
 * @Date: 2022-08-22 16:28:59
 * @LastEditTime: 2022-09-26 19:10:17
 */
#include <bits/stdc++.h>
#include <stdlib.h>

using namespace std;
typedef long long ll;

ll n;
vector<ll> arr;


void merge( vector<ll> &v, ll L, ll mid, ll R ){
    ll *temp = new ll[R - L + 1];

    ll i = 0;
    ll p1 = L;
    ll p2 = mid + 1;

    while( p1 <= mid && p2 <= R ){
        temp[i ++] = v[p1] < v[p2] ? v[p1 ++] : v[p2 ++];
    }

    while( p1 <= mid ){
        temp[i ++] = v[p1 ++];
    }
    while( p2 <= R ){
        temp[i ++] = v[p2 ++];
    }

    for( int idx = 0; idx < i; ++ idx ){
        v[L + idx] = temp[idx];
    }

    delete[] temp;
}


void mergeSort( vector<ll> &v, ll L, ll R ){
    
    if( L >= R || n <= 1){
        return ;
    }

    ll mid = L + ((R - L) >> 1);
    mergeSort( v, L, mid );
    mergeSort( v, mid + 1, R );
    merge( v, L, mid, R );
}


int main( int argc, char *argv[] ){

    cin >> n;
    for( int idx = 0; idx < n; ++ idx ){
        ll t; cin >> t;
        arr.push_back( t );
    }
    mergeSort( arr, 0, n - 1 );

    for( int idx = 0; idx < n; ++ idx ){
        cout << arr[idx] << " ";
    }
    puts( "" );
    return 0;
}

求第 k 小的数

洛谷 P1923

题目描述

输入 n n n 1 ≤ n < 5000000 1 \le n < 5000000 1n<5000000 n n n 为奇数)个数字 a i a_i ai 1 ≤ a i < 10 9 1 \le a_i < {10}^9 1ai<109),输出这些数字的第 k k k 小的数。最小的数是第 0 0 0 小。

请尽量不要使用 nth_element 来写本题,因为本题的重点在于练习分治算法。

输入格式

输出格式

样例 #1

样例输入 #1

5 1
4 3 2 1 5

样例输出 #1

2

解题思路:简单排序,返回数组相应下标即可。

解题的时候发现自己写的排序都会超时,这儿我们对快排优化一下,只找符合条件的那部分;

再次优化之后发现还是有tle问题,这时我们发现数据特别大,使用题目的提示吧

ps:突然想起之前刚学算法的时候,洛谷的题目很恶心,会卡 scanf 等等的时间,这道题 T 麻了。

/*
 * @Author: xiguan
 * @Email: xiguan.teng@qq.com
 * @Version: 1.0
 * @Date: 2022-08-22 16:28:59
 * @LastEditTime: 2022-09-26 19:37:15
 */
#include <bits/stdc++.h>
#include <stdlib.h>

using namespace std;
typedef long long ll;

ll n, k;
ll arr[5000010];

void heapInsert( vector<ll> &v, ll index ){
    while( v[index] > v[(index - 1) / 2] ){
        swap( v[index], v[(index - 1) / 2] );
        index = (index - 1) / 2;
    }
}

void heapIfy( vector<ll> &v, ll index, ll heapsize ){

    ll left_child = index * 2 + 1;

    while( left_child < heapsize ){

        ll largest = left_child + 1 < heapsize && v[left_child + 1] > v[left_child] ? left_child + 1 : left_child;

        largest = v[largest] > v[index] ? largest : index;

        if( largest == index ){
            break;
        }

        swap( v[index], v[largest] );
        index = largest;
        left_child = index * 2 + 1;
    }
}

void heapSort( vector<ll> &v, ll n ){
    if( n <= 1 ){
        return ;
    }

    for( int idx = 0; idx < n; ++ idx ){
        heapInsert( v, idx );
    }

    ll heapsize = n;
    swap( v[0], v[-- heapsize] );
    while( heapsize > 0 ){
        heapIfy( v, 0, heapsize );
        swap( v[0], v[-- heapsize] );
    }
}

void merge( vector<ll> &v, ll L, ll mid, ll R ){
    ll *temp = new ll[R - L + 1];

    ll i = 0;
    ll p1 = L;
    ll p2 = mid + 1;

    while( p1 <= mid && p2 <= R ){
        temp[i ++] = v[p1] < v[p2] ? v[p1 ++] : v[p2 ++];
    }

    while( p1 <= mid ){
        temp[i ++] = v[p1 ++];
    }
    while( p2 <= R ){
        temp[i ++] = v[p2 ++];
    }

    for( int idx = 0; idx < i; ++ idx ){
        v[L + idx] = temp[idx];
    }

    delete[] temp;
}


void mergeSort( vector<ll> &v, ll L, ll R ){
    
    if( L >= R || n <= 1){
        return ;
    }

    ll mid = L + ((R - L) >> 1);
    mergeSort( v, L, mid );
    mergeSort( v, mid + 1, R );
    merge( v, L, mid, R );
}

pair<ll, ll> partition( vector<ll> &v, ll L, ll R ){
    ll less_than = L - 1;
    ll more_than = R;

    while( L < more_than ){
        if( v[L] < v[R] ){
            swap( v[++ less_than], v[L ++] );
        }else if( v[L] > v[R] ){
            swap( v[-- more_than], v[L] );
        }else{
            L ++;
        }
    }

    swap( v[more_than], v[R] );

    return { less_than + 1, more_than };
}

void quickSort( vector<ll> & v, ll L, ll R ){
    if( L < R ){
        pair<ll, ll> t = partition( v, L, R );
        if( k < t.first ){
            quickSort( v, L, t.first - 1 );
        }else if( k > t.second ){
            quickSort( v, t.second + 1, R );
        }else{
            cout << v[t.first] << endl;
            exit( 0 );
        }
    }
}

int main( int argc, char *argv[] ){

    cin >> n >> k;
    for( int idx = 0; idx < n; ++ idx ){
        scanf( "%d", &arr[idx] );
    }
    
    // quickSort( arr, 0, n - 1 );
    nth_element( arr, arr + k, arr + n );

    // for( int idx = 0; idx < n; ++ idx ){
    //     cout << arr[idx] << " ";
    // }
    // puts( "" );
    cout << arr[k] << endl;
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值