最近、AtCoderを始めた初心者です。チュートリアルの問題を解いたのですが、もう少しスマートな書き方や、効率のよいアルゴリズムがあればと思い質問しました。質問内容は、
- もっと簡潔な書き方はないか?
- マージのアルゴリズムを改良できないか、in-placeにできないか? (log(Combination(2n, n))=O(n)?)
- n=5の場合のチューニングをコンパイル時に自動でさせる方法はないか? (保守性が高い、メタな表記がありそう)
の3点です。自力だと力業でゴリ押す汚いコードしか書けないものですから、コンテストに参加するにはまだまだ力不足と痛感しておりますが、ご教授教示いただけますと助かります。
C++
1#include <iostream> 2#include <algorithm> 3#include <type_traits> 4#include <utility> 5#include <vector> 6 7namespace practiceB{ 8 9template <class RandomAccessIterator, class Compare> 10void sort(const RandomAccessIterator first, const RandomAccessIterator last, Compare comp) 11{ 12 std::size_t n = std::distance(first, last); 13 if(n < 2) return; 14 if(n != 5){ 15 auto mid = first + n / 2; 16 practiceB::sort(first, mid, comp); 17 practiceB::sort(mid, last, comp); 18 19 std::vector<typename std::remove_const<typename std::remove_reference<decltype(*first)>::type>::type> tmp(n); 20 std::merge(first, mid, mid, last, tmp.begin(), comp); 21 std::move(tmp.begin(), tmp.end(), first); 22 } 23 else{ 24 if(!comp(first[0], first[1])){ 25 std::swap(first[0], first[1]); 26 } 27 if(!comp(first[2], first[3])){ 28 std::swap(first[2], first[3]); 29 } 30 if(!comp(first[0], first[2])){ 31 std::swap(first[0], first[2]); 32 std::swap(first[1], first[3]); 33 } 34 if(comp(first[2], first[4])){ 35 if(comp(first[3], first[4])){ 36 if(comp(first[1], first[3])){ 37 if(!comp(first[1], first[2])){ 38 std::swap(first[1], first[2]); 39 } 40 } 41 else{ 42 std::swap(first[1], first[2]); 43 std::swap(first[2], first[3]); 44 if(!comp(first[3], first[4])){ 45 std::swap(first[3], first[4]); 46 } 47 } 48 } 49 else{ 50 if(comp(first[1], first[4])){ 51 std::swap(first[3], first[4]); 52 if(!comp(first[1], first[2])){ 53 std::swap(first[1], first[2]); 54 } 55 } 56 else{ 57 std::swap(first[1], first[2]); 58 std::swap(first[2], first[4]); 59 if(!comp(first[3], first[4])){ 60 std::swap(first[3], first[4]); 61 } 62 } 63 } 64 } 65 else{ 66 if(comp(first[0], first[4])){ 67 if(comp(first[1], first[2])){ 68 std::swap(first[2], first[3]); 69 std::swap(first[2], first[4]); 70 if(!comp(first[1], first[2])){ 71 std::swap(first[1], first[2]); 72 } 73 } 74 else{ 75 std::swap(first[1], first[4]); 76 if(!comp(first[3], first[4])){ 77 std::swap(first[3], first[4]); 78 } 79 } 80 } 81 else{ 82 std::swap(first[0], first[4]); 83 std::swap(first[1], first[4]); 84 if(comp(first[2], first[4])){ 85 if(!comp(first[3], first[4])){ 86 std::swap(first[3], first[4]); 87 } 88 } 89 else{ 90 std::swap(first[2], first[4]); 91 std::swap(first[3], first[4]); 92 } 93 } 94 } 95 } 96} 97 98} 99
5/16編集:標準テンプレートにmergeが実装されているらしいので、それを使うようにしました。関数が減り、見やすくはなりましたが依然としてn=5の場合がカオスです…。
URLは https://teratail.com/help/question-tips#questionTips3-7 の [リンク] で [リンク先のタイトル](http...) に修正してください。
他のMarkdownの機能も確認しておいてください。
教授 → 教示
マージソートは、安定ソートですが。それの拘らなくても良いのですか?
compを呼ぶ回数を最小に > 簡潔性、保守性 >>> 必要メモリの少なさ、安定ソート
これぐらいの認識です。中身の要素はすべて異なる、という前提なので、安定ソートである必要は、ないです。
どうしてもマージソートと特定のケースへの条件分岐が必要なんですか?
それをスマートと呼ぶのは非常に抵抗がありますが。
もしそうであるなら「スマート」を定義してください。
教授教示 → 教示
回答2件
あなたの回答
tips
プレビュー