Memasukkan elemen yang tipenya tidak diketahui ke dalam vektor

Saya sedang mengerjakan program yang mengambil elemen dari pengguna dan mengurutkannya. Untuk program ini, saya harus menggunakan vektor karena ukuran daftar elemen tidak diketahui sebelum masukan pengguna. Instruksi kami adalah:

Tulis program dalam C++ untuk mengimplementasikan pengurutan daftar elemen. Elemen dapat bertipe apa pun tetapi semuanya bertipe sama, seperti semua bilangan bulat atau semua float atau semua karakter atau semua string (string harus diurutkan seperti dalam kamus). Anda dapat menerapkan algoritma pengurutan apa pun pilihan Anda.

  1. Tanyakan kepada pengguna berapa banyak elemen yang akan ada di sana
  2. Minta pengguna untuk memasukkan elemen
  3. Minta pengguna untuk memilih urutan pengurutan: naik atau turun atau keduanya
  4. Cetak daftar input dan output
  5. Pengguna tidak akan memberikan informasi apa pun mengenai jenis elemen

Saya tidak begitu akrab dengan vektor (pada dasarnya guru membaca sekilas topik di kelas) dan buku saya tidak memberi saya banyak informasi tentang subjek tersebut. Masalah yang saya hadapi adalah saya tidak mengetahui jenis daftar elemen sampai pengguna mulai memasukkan. Sejauh ini, saya telah mencoba:

  • membuat vektor tipe void (jelas tidak diperbolehkan sekarang karena saya sudah menelitinya, ups)
  • membebani fungsi yang disebut insertInVector dengan mengirimkan elemen pertama ke fungsi dan membiarkan fungsi menentukan tipe vektor mana yang akan dibuat berdasarkan tipe elemen pertama (yang sepertinya merupakan pilihan terbaik saya ketika saya memikirkannya, kecuali saya memerlukan akses ke vektor setelah fungsi berakhir, sehingga tidak boleh dilakukan juga)
  • #include <typeinfo> dalam program, mencari tipe elemen pertama, lalu membuat vektor menggunakan vector<typeid(firstElement).name()> dan sejujurnya saya tidak yakin mengapa itu tidak berhasil, tetapi ternyata tidak.

Seperti saya katakan, saya memiliki pengalaman yang SANGAT terbatas dengan vektor karena ini adalah pertama kalinya saya menggunakannya. Saya juga seorang programmer yang cukup baru sehingga banyak penelitian yang saya lakukan mengenai hal ini tidak masuk akal. Bantuan apa pun yang dapat diberikan dalam hal ini akan SANGAT dihargai!


person Monique    schedule 10.06.2012    source sumber
comment
Saya rasa Anda dapat menggunakan boost::any. Argumen templat harus diteruskan pada waktu kompilasi.   -  person chris    schedule 10.06.2012
comment
apakah semua elemen memiliki tipe yang sama, atau dapatkah pengguna memasukkan elemen dengan tipe berbeda selama eksekusi program yang sama?   -  person juanchopanza    schedule 10.06.2012
comment
Semua elemen harus memiliki tipe yang sama ketika dimasukkan oleh pengguna   -  person Monique    schedule 10.06.2012
comment
Dan bagaimana cara menentukan tipenya berdasarkan input?   -  person juanchopanza    schedule 10.06.2012
comment
vector<void> tidak diperbolehkan... vector<void*> diperbolehkan. Dan sebenarnya seluruh persyaratan tampak agak aneh. Apakah Anda yakin ini adalah cara terbaik untuk melakukan pendekatan? Dan apakah ini pekerjaan rumah?   -  person Zaid Amir    schedule 10.06.2012
comment
Ya, ini pekerjaan rumah. Saya tidak yakin ini cara terbaik untuk melakukan pendekatan, tidak. Guru saya cenderung memberikan instruksi yang sangat luas untuk tugas   -  person Monique    schedule 10.06.2012
comment
Instruksi kami adalah: Tulis program dalam C++ untuk mengimplementasikan pengurutan daftar elemen. Elemen dapat bertipe apa pun tetapi semuanya bertipe sama, seperti semua bilangan bulat atau semua float atau semua karakter atau semua string (string harus diurutkan seperti dalam kamus). Anda dapat menerapkan algoritma pengurutan apa pun pilihan Anda. 1. Tanyakan kepada pengguna berapa banyak elemen yang akan ada 2. Minta pengguna untuk memasukkan elemen 3. Minta pengguna untuk memilih urutan pengurutan: menaik atau menurun atau keduanya 4. Cetak daftar masukan dan keluaran 5. Pengguna tidak akan memberikan apa pun informasi mengenai jenis elemen   -  person Monique    schedule 10.06.2012
comment
Yes, this is homework. Maka Anda harus menambahkan tag pekerjaan rumah ke pertanyaan Anda   -  person Zaid Amir    schedule 10.06.2012
comment
Maaf, saya tidak sadar itu penting... sama sekali. Masalah saya bukan hanya menyelesaikan tugas pekerjaan rumah, tetapi memahami konsep di balik apa yang digunakan pekerjaan rumah saya   -  person Monique    schedule 10.06.2012
comment
@Monique: secara umum penting dalam cara kita menjawab pertanyaan. Untuk pekerjaan rumah, Anda lebih mungkin mendapatkan petunjuk (sehingga Anda dapat memikirkannya sendiri) dan lebih banyak detail tentang konsep yang mendasarinya (karena kami berasumsi Anda belum mengetahui banyak hal).   -  person Matthieu M.    schedule 10.06.2012


Jawaban (4)


C++ adalah bahasa yang diketik secara statis. Artinya semua tipe harus ditentukan selama kompilasi: Anda tidak dapat memasukkan tipe baru saat menjalankan program.

  • membuat vektor tipe void (jelas tidak diperbolehkan sekarang karena saya sudah menelitinya, ups)

void sebenarnya adalah tipe yang cukup aneh, sebagian besar merupakan pengganti ketika Anda mengharapkan suatu tipe (seperti tipe pengembalian fungsi) dan tidak ada yang disediakan. void* digunakan sebagai penunjuk ke tipe yang tidak diketahui (kebanyakan dalam C) tapi ini cukup meretas, karena informasi tentang dokumen asli dibuang (sejauh menyangkut bahasa) sehingga hal ini menyebabkan masalah untuk benar-benar melakukan sesuatu dengan nilai tersebut jadi diperoleh.

  • membebani fungsi yang disebut insertInVector dengan mengirimkan elemen pertama ke fungsi dan membiarkan fungsi menentukan tipe vektor mana yang akan dibuat berdasarkan tipe elemen pertama

  • #include <typeinfo> dalam program, mencari tipe elemen pertama, lalu membuat vektor menggunakan vector<typeid(firstElement).name()> dan sejujurnya saya tidak yakin mengapa itu tidak berhasil, tetapi ternyata tidak.

Sayangnya tidak ada yang mungkin: karena Anda tidak dapat mendeklarasikan variabel tanpa tipe, tipe firstElement apa yang akan digunakan untuk memulai?


Masalah yang Anda uraikan secara umum sulit. Pada dasarnya ini berarti Anda harus menerima serangkaian karakter, dan kemudian mengkodekan serangkaian aturan untuk menentukan cara menafsirkan karakter tersebut. Hal ini dilakukan secara umum dengan menggunakan tata bahasa untuk menyandikan aturan-aturan tersebut; tetapi tata bahasanya mungkin rumit untuk tugas yang mungkin sederhana.

Izinkan saya memberikan contoh kecil:

class Input {
public:
    enum Type {
        Int,
        Double,
        String
    };

    static Input Parse(std::string const& s);

    Input(): _type(Int), _int(0), _double(0.0) {} // need to define a default...

    Type type() const { return _type; }

    int asInt() const {
        assert(_type == Int && "not an int");
        return _int;
    }

    double asDouble() const {
        assert(_type == Double && "not a double");
        return _double;
    }

    std::string const& asString() const {
        assert(_type == String && "not a string");
        return _string; 
    }

private:
    Type _type;
    int _int;
    double _double;
    std::string _string;
};

Jelas, tantangan sebenarnya adalah Parse input dengan benar.

Idenya adalah dengan menggunakan seperangkat aturan, misalnya:

  • sebuah int hanya terdiri dari angka, opsional diawali dengan -
  • a double hanya terdiri dari angka, dengan paling banyak satu . dan secara opsional diawali dengan -
  • a string bisa apa saja, oleh karena itu adalah tujuan umum kami

Kemudian kita dapat menulis bagian pengenalan dari metode Parse:

static bool isInt(std::string const& s) {
    if (s.empty()) { return false; }
    
    // The first character may be among digits and '-'
    char const first = s.at(0);
    if (not isdigit(first) and first != '-') { return false; }

    // Subsequent characters may only be digits
    for (char c: s.substr(1)) {
        if (not isdigit(c)) { return false; }
    }

    // Looks like it is an int :)
    return true;
} // isInt

// Note: any int could be interpreted as a double too
static bool maybeDouble(std::string const& s) {
    if (s.empty()) { return false; }

    // The first character may be among digits, '.' and '-'
    char const first = s.at(0);
    if (not isdigit(first) and first != '.' and first != '-') { return false; }

    // There may only be one dot
    bool hasSeenDot = s.at(0) == '.';

    // Subsequent characters may only be digits and a dot now
    for (char c: s.substr(1)) {
        if (not isdigit(c) and c != '.') { return false; }

        if (c == '.') {
            if (hasSeenDot) { return false; } // no second dot allowed
            hasSeenDot = true;
        }
    }

    // Looks like it could be a double
    return true;
} // maybeDouble

static Input::Type guessType(std::string const& s) {
    if (isInt(s)) { return Input::Int; }

    // Test double after we ensured it was not an int
    if (maybeDouble(s)) { return Input::Double; }

    return Input::String;
} // guessType

Dan dengan logika tebak-tebakan bersama, akhirnya muncullah parse:

Input Input::Parse(std::string const& s) {
    Input result;

    result._type = guessType(s);

    switch(result._type) {
    case Input::Int: {
        std::istringstream stream(s);
        s >> result._int;
        return result;
    }
    case Input::Double: {
        std::istringstream stream(s);
        s >> result._double;
        return result;
    }
    case Input::String:
        result._string = s;
        return result;
    }

    // Unreachable (normally)
    abort();
} // Input::Parse

Fiuh!

Jadi ? Hampir sampai. Sekarang kita perlu menentukan bagaimana membandingkan dua masukan. Mudah saja jika semuanya memiliki tipe yang sama, jika tidak Anda perlu menentukan logika arbitrer. Anda dapat mengubah input Int menjadi input Double dengan cukup mudah, tetapi untuk string ini sedikit lebih aneh.

// define < for comparing two instance of "Input",
// assuming they both have the same type
bool operator<(Input const& left, Input const& right) {
    assert(left.type() == right.type() && "Different Types!");

    switch(left.type()) {
    case Input::Int: return left.asInt() < right.asInt();
    case Input::Double: return left.asDouble() < right.asDouble();
    case Input::String: return left.asString() < right.asString();
    }
} // operator<

Dan yang terakhir, programnya:

int main(int argc, char* argv[]) {
    // parse command line
    std::vector<Input> inputs;

    // by convention argv[0] is the program name, it does not count!
    for (int i = 1; i != argc; ++i) {
        inputs.push_back(Input::Parse(argv[i]));

        // Detect that the type is the same as the first input
        if (inputs.size() >= 2) {
            if (inputs.back().type() != inputs.front().type()) {
                std::cerr << "Please only use one type among Int, Double and String\n";
                return 1; // non-0 is an error
            }
        }
    }

    // sort
    std::sort(inputs.begin(), inputs.end());

    // echo back to the user
    for (Input const& i: inputs) {
        switch(i.type()) {
        case Input::Int: std::cout << i.asInt() << "\n"; break;
        case Input::Double: std::cout << i.asDouble() << "\n"; break;
        case Input::String: std::cout << i.asString() << "\n"; break;
        }
    }

    // End of the program
    return 0;
}

Tentu saja karena saya tidak tahu tipe apa yang ingin Anda hadapi.. Saya telah memutuskan set yang sewenang-wenang;) Namun ini akan memberi Anda kerangka untuk dijadikan dasar.

person Matthieu M.    schedule 10.06.2012
comment
Itu jawaban yang bagus. Satu-satunya hal yang saya tidak suka dari desain ini adalah desainnya agak rakus dalam hal kebutuhan memori, tapi menurut saya itu tidak masalah dalam kasusnya. - person akappa; 10.06.2012
comment
Ini adalah jawaban yang bagus, tetapi tampaknya tujuan dari tugasnya adalah untuk menerapkan algoritma pengurutan, jadi saya pribadi akan menghapus rekomendasi untuk menggunakan std::sort. Meskipun demikian, memberi +1 untuk detailnya (dan memang mengatasi masalah OP). - person Fraser; 10.06.2012
comment
Belum pernah mendengar tentang boost::variant? Itu akan jauh lebih ideal daripada menulis sendiri. Juga, Anda lupa pernyataan break di saklar. - person Puppy; 13.06.2012
comment
Ini sepertinya berlebihan, karena satu-satunya tempat Anda memerlukan tipe tersebut adalah fungsi perbandingan. - person Mooing Duck; 13.06.2012
comment
@DeadMG: Terima kasih untuk break. Adapun boost::variant =› tidak cocok untuk level OP, saya khawatir; kita berbicara tentang seorang pemula yang masih berjuang dengan konsep pengetikan statis. - person Matthieu M.; 13.06.2012
comment
@Matthieu: Itulah sebabnya dia harus memulai dengan hal-hal yang bagus, bukan hal-hal yang buruk. - person Puppy; 13.06.2012
comment
@DeadMG: maka kita harus setuju untuk tidak setuju. Saya berpendapat boost::variant dan konsep kunjungan statis terlalu rumit (terlalu banyak boilerplate) untuk tugas yang ada. - person Matthieu M.; 13.06.2012

Melihat persyaratan sebenarnya dari masalah seperti yang dinyatakan dalam komentar, saya sarankan Anda menyimpan semua input dalam std::vector<std::string> dan mengurutkan vektor menggunakan std::sort. Jadi, daripada mengkhawatirkan tipe yang berbeda, Anda dapat menentukan logika pengurutan bergantung pada apa yang Anda tafsirkan untuk mewakili string dalam vektor Anda. Jadi

  1. Menerapkan fungsi pengurutan untuk string bergantung pada apa yang diwakili oleh string tersebut (lebih lanjut nanti)
  2. menyimpan input sebagai string dalam vektor.
  3. Tentukan jenis string yang diwakilinya
  4. pilih fungsi penyortiran berdasarkan jenis ini
  5. Urutkan vektor menggunakan std::sort dan fungsi pengurutan yang sesuai.

Mengenai fungsi pengurutan, std::sort menerima fungsi atau fungsi biner yang menerapkan perbandingan "kurang dari" pada dua elemen, sehingga fungsi atau fungsi Anda akan terlihat seperti

bool foo(const std::string& rhs, const std::string& lhs) {
  // implement the logic
}

Sunting: Melihat komentar yang lebih baru, tampaknya tujuan utama latihan ini adalah untuk mengimplementasikan algoritma pengurutan untuk tipe yang berbeda. Dalam hal ini, saya akan menyarankan untuk mengikuti pendekatan yang diambil oleh pustaka standar C++, yaitu mengimplementasikan pengurutan berdasarkan istilah atau perbandingan kurang dari antara dua tipe, sehingga memisahkan logika pengurutan dari tipe-tipe tersebut. untuk diurutkan. Jadi, Anda menginginkan fungsi penyortiran templat, berdasarkan tipe iterator dan fungsi/fungsi perbandingan.

person juanchopanza    schedule 10.06.2012
comment
Urutan leksikografis berbeda dengan urutan numerik. - person akappa; 10.06.2012
comment
@akappa logika penyortiran dapat ditentukan. - person juanchopanza; 10.06.2012
comment
@juanchopanza Tidakkah menurut Anda Anda dapat menerapkan algoritma pengurutan apa pun pilihan Anda menyiratkan bahwa mereka harus menulis algoritma mereka sendiri daripada menggunakan std::sort? - person Fraser; 10.06.2012
comment
@Fraser mungkin. Saya kesulitan untuk mengidentifikasi inti sebenarnya dari latihan ini. - person juanchopanza; 10.06.2012
comment
@Fraser: atau mereka dapat menentukan argumen ke-3 saat memanggil std::sort. - person Matthieu M.; 10.06.2012
comment
@juanchopanza Ya - Saya agak curiga bahwa maksud guru dalam latihan ini adalah menerapkan algoritme pengurutan, tetapi secara tidak sengaja membuat bagian tersulit dalam membuat wadah. - person Fraser; 10.06.2012
comment
@Fraser ya, mengimplementasikan fungsi penyortiran adalah salah satu tugas CS klasik. - person juanchopanza; 10.06.2012
comment
@MatthieuM. Apakah itu termasuk penerapan algoritma pengurutan? Kira itu terserah interpretasi guru. - person Fraser; 10.06.2012
comment
Ya, Anda benar sekali, inti dari latihannya adalah untuk mengimplementasikan algoritma pengurutan -_- sayangnya dia tidak berpengalaman dalam mengajar (mahasiswa pascasarjana) dan tidak mendalami vektor karena sebenarnya tidak seharusnya dibahas sampai chapter selanjutnya...mereka hanya diperkenalkan sebentar sampai sekarang, tapi menurutku dia tidak menyadarinya. - person Monique; 10.06.2012
comment
@Monique Dalam hal ini, saya akan merekomendasikan jawaban ini atau jawaban MatthieuM, tetapi mengganti std::sort dengan algoritma pengurutan Anda sendiri. - person Fraser; 10.06.2012
comment
@Monique: jadi dia mengaitkan tugas algoritmik dengan tugas desain (dan cukup canggih dalam hal itu)? Dia harus dilarang mengajar. - person akappa; 10.06.2012
comment
@akappa: atau mungkin hanya ditunjukkan dengan cara yang lebih baik, orang akan berharap bahwa seorang guru sejati akan merancang kursus yang akan dibahas :/ - person Matthieu M.; 10.06.2012

Jika Anda mengetahui tipe apa saja yang dapat dimasukkan oleh pengguna, Anda dapat menggunakan templat dan warisan:

class Generic {
public:
  virtual void process_input() = 0; // Handles the next input from user
  virtual void process_output() = 0; // Processes the data inserted
};

template <typename T>
class HandleInput : public Generic {
private:
    std::vector<T> storage;
public:
    HandleInput(T first)
    {
      storage.push_back(first);
    }

    void process_input()
    {
      // do whatever you want
    }

    void process_output()
    {
      // do whatever you want
    }
};

int main(int argc, char **argv)
{
  // Get first input
  Input i = input();
  Generic *g;

  // Instantiate the "right" generic with a switch
  switch (i.type) {
    case T:
      g = new HandleInput<T>(i.value);
  }

  // Use Generic from here onwards
}

Itu hanya sebuah ide (Input tidak dapat diimplementasikan seperti itu, Anda perlu mengubah bagian itu dengan logika yang mendapatkan sesuatu dari pengguna dan menentukan tipenya), tetapi memiliki manfaat untuk menutupi tipe tersebut ke dalam kelas generik, sehingga Anda bisa faktorkan kode Anda pada antarmuka yang disediakan oleh Generic.

Ide lain (mungkin lebih mudah) adalah menggunakan std::vector<void*> dan enum yang memberi tahu Anda jenis data yang disimpan dalam vektor. Saat Anda perlu memproses data tersebut di suatu tempat di masa mendatang, Anda dapat mengaktifkan enum untuk memasukkan elemen vektor dengan tepat ke tipe yang benar dan mengirimkannya ke kode yang sesuai.

EDIT: ide lainnya adalah mendefinisikan fungsi templat yang mengambil masukan dan mengurutkan array menggunakan pembanding standar:

#include <iostream>

#include <vector>
#include <algorithm>
#include <boost/lexical_cast.hpp>

template <typename T>
void print_v(std::vector<T> &v)
{
    typename std::vector<T>::iterator it;
    for (it = v.begin(); it != v.end(); it++)
        std::cout << *it << " ";
    std::cout << std::endl;
}

template <typename T>
void sort_and_print(T first, size_t n, bool asc)
{
    std::vector<T> v;
    v.push_back(first);
    for (size_t i = 0; i < n; i++) {
        std::string s;
        std::cin >> s;
        T e = boost::lexical_cast<T>(s);
        v.push_back(e);
    }

    print_v(v);
    if (asc)
        std::sort(v.begin(), v.end(), std::greater<T>());
    else
        std::sort(v.begin(), v.end());
    print_v(v);
}

int main(int argc, char **argv)
{
    std::string s = "test";
    sort_and_print(s, 2, true);
    unsigned int j = 3;
    sort_and_print(j, 2, true);
    return 0;
}

Logika untuk menentukan jenis input pertama terserah Anda (mungkin bisa membuka pertanyaan lain) ;)

person akappa    schedule 10.06.2012
comment
Saya khawatir Anda bertindak terlalu jauh dari pemahaman OP. Dia masih belum mengintegrasikan ide pengetikan statis dan Anda sudah menggunakan template. (Bukan berarti responnya terlalu buruk, hanya saja saya khawatir itu di luar jangkauannya) - person Matthieu M.; 10.06.2012
comment
@MatthieuM.: mungkin, tapi saya tidak tahu bagaimana dia bisa menemukan sesuatu yang lebih mudah yang tidak melibatkan boost atau sesuatu yang lebih canggih (kecuali menggunakan vektor void*, mungkin, tapi saya tidak yakin akan kehilangan tipenya dapat menghasilkan sesuatu yang bermanfaat). - person akappa; 10.06.2012
comment
@akappa, sepertinya itu mungkin berhasil tetapi Matthieu benar, ini sedikit berlebihan. Salah satu masalah utama yang saya hadapi juga adalah saya tidak tahu cara menentukan jenis masukan yang saya dapatkan dari pengguna. Saya tahu cara menggunakan fungsi seperti isdigit untuk membedakan antara karakter dan angka, tetapi lebih dari itu saya tidak mengerti =\ - person Monique; 10.06.2012
comment
@Monique: upaya Anda untuk mengabstraksi detailnya sangat bagus dan memang merupakan praktik yang baik, tetapi saya menduga detail tentang tipe apa yang bisa Anda peroleh dari masukan dan bagaimana Anda membedakannya memang bisa berguna. - person akappa; 10.06.2012
comment
Tapi bagaimana cara kerja saklarnya? Tampaknya Anda menggunakan tipe untuk kasus ini, yang memerlukan ekspresi konstan. - person juanchopanza; 10.06.2012
comment
Saya setuju, masalahnya adalah saya tidak mencoba mengabstraksikan detailnya, saya hanya tidak yakin bagaimana MENCARI detailnya. Saya tidak diperbolehkan meminta masukan dari pengguna tentang jenisnya, dan saya bingung membedakannya lebih dari itu - person Monique; 10.06.2012
comment
@Monique: apakah Anda tahu sesuatu tentang templat? - person akappa; 10.06.2012
comment
@juanchopanza: baca komentar di bawah kode, ini hanyalah semacam kodesemu yang menunjukkan sebuah ide - person akappa; 10.06.2012
comment
@akappa, tidak banyak. Saya sependapat dengan templat seperti halnya saya dengan vektor - guru saya mengajarkan konsep dasar tetapi tidak lebih dari itu. Saya juga tipe orang yang belajar dengan baik melalui contoh dan mengerjakan sesuatu secara langsung, namun saya tidak belajar dengan mudah hanya dengan membaca buku, dll. Kelas ini seperti mimpi buruk bagi saya. - person Monique; 10.06.2012
comment
@Monique: oke, pada dasarnya ada dua pendekatan di sini: (1) jangan pedulikan jenisnya saat memasukkan vektor, tetapi pertimbangkan saat Anda mengurutkannya (seperti solusi juanchopanza) atau (2) deteksi jenisnya pertama masukkan dan tulis fungsi templat dengan tipe T yang benar, yang akan Anda gunakan dalam definisi vektor (setelah itu Anda dapat menggunakan std::sort(v.begin(), v.end(), std::greater sederhana / std::lesser).(2) secara teori lebih disukai (Anda melakukan konversi data hanya sekali, daripada rata-rata O(log n) kali untuk setiap elemen), tetapi mungkin sedikit lebih rumit. - person akappa; 10.06.2012
comment
Saya lebih suka melakukan metode 2 karena guru saya menyebutkan di kelas bahwa program kita harus dapat membedakan tipe, tetapi bagaimana Anda mendeteksi tipe pada input pertama?? dan bagaimana kaitannya dengan templat? sepertinya jika saya dapat mendeteksi tipe pada input pertama, setelah input pertama itu saya tinggal membuat vektor dengan tipe tersebut =\ - person Monique; 10.06.2012
comment
@Monique: bit penguraian dijelaskan dalam jawaban bagus Matthieu (Anda dapat menggunakan fungsi guessType()-nya pada input pertama dan kemudian memanggil fungsi template yang tepat dengan tombol untuk mengembalikan fungsi tersebut). Anda dapat melihat bagaimana templat berkaitan dengan diferensiasi tipe dalam kode yang saya lampirkan di pembaruan jawaban saya - person akappa; 10.06.2012
comment
@akappa YA, pengeditan yang Anda lakukan adalah sesuatu yang paling saya pahami, sempurna :D apakah Anda keberatan jika saya menanyakan beberapa pertanyaan saja saat mengobrol dengan Anda? Saya rasa, saya sudah cukup menyumbat komentar - person Monique; 10.06.2012
comment
sebenarnya nvm, saya harus berangkat kerja ›.‹ terima kasih banyak atas bantuan Anda semuanya, saya sangat menghargainya - person Monique; 10.06.2012

Ada dua aspek untuk pertanyaan ini: penguraian & pengurutan.

  • Anda dapat menggunakan ekspresi reguler untuk memeriksa tipe data input pengguna.
  • Anda dapat menggunakan cin untuk mengurai data.

Pertama: sadari bahwa Anda tidak harus mengetahui jenis masukan pengguna Anda sampai Anda menerima semuanya ~misalnya: pertimbangkan daftar pengguna nama :

728278243
390349346
495045594
elizabeth

Oleh karena itu, sebaiknya jangan berasumsi bahwa Andalah yang paling tahu tentang data yang masuk (dapat menyebabkan pengalaman pengguna yang membuat frustrasi) namun sebaliknya, lebih memilih untuk memperlakukan semuanya sebagai sebuah string. Simpan semua masukan mentah sebagai string sehingga Anda dapat menghasilkan keluaran dalam format yang sama dengan masukan. Anda dapat menggunakan, katakanlah, tipe yang disebutkan untuk beralih ke dalam pembanding pengurutan atau pertimbangkan untuk menggunakan mutliset/multimap. di sini Anda akan membuat set terurut. jadi tidak perlu disortir. NB: kompleksitas untuk membangun kumpulan N elemen atau yang terurut, untuk satu pengurutan pada N elemen daftar yang tidak disortir, kira-kira setara ~> NlogN

Untuk tugas yang sedang Anda kerjakan, hal ini tidak menjadi masalah, namun pada kenyataannya tergantung pada bagaimana daftar tersebut digunakan, satu pendekatan atau lainnya akan jauh lebih tepat dalam hal kinerja.

Jika Anda sudah pernah menggunakan yang seperti std::vector maka std::multimap seharusnya tidak terlalu menakutkan. Secara longgar, ini adalah rangkaian pasangan nilai kunci yang terkait. multi di sini artinya dapat menyimpan banyak elemen dengan kunci sama (yang Anda inginkan di sini).


Dalam contoh ini saya menggunakan pustaka regex boost untuk menentukan beberapa tipe data masukan funky.
(misalnya: sudo apt-get install libboost-regex1.46-dev)

regex ini mungkin tampak misterius tetapi ada banyak contoh di i/web untuk hampir semua pola yang bisa dibayangkan. [NB: Regex C++11 merupakan pengganti drop-in untuk boost regex. yaitu: boost regex harus kompatibel dengan standar C++11 yang sedang berkembang]


blah.cpp:

#include <iostream>
#include <sstream>
#include <string>
#include <list>
#include <map>
#include <set>
#include <boost/regex.hpp>    
//NB: GNU gcc added *experimental support for regular expressions in TR1 v 4.3.0.
//    compile with:  -std=c++0x

using namespace std;
using namespace boost;

//some example input data-types (perhaps notably missing a date!) 
const regex re_char("[^0-9]", regex_constants::extended); //non numeric chars
const regex re_digit("[[:digit:]]+", regex_constants::extended); //a string of only digits in range [0..9] ~ie: Z+
const regex re_xdigit("0[xX][[:xdigit:]]+", regex_constants::extended); //support hex iff starts with '0x' or '0X'
const regex re_float("[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?", regex_constants::extended); //all kinds of numbers


int main(int argc, char** argv)
{    
    int i, countc=0;
    double d;
    string str;
    int element_count;    

    do
    {
        cout << "how many elements will there be? "; 
        if (cin >> element_count) break;
        cin.clear();
        cin >> str;
        cout << "\033[A\033[2K" << flush;
    }
    while(13);
    cin.ignore(128,'\n'); 

    multimap<double, string> list_num; 
    multimap<double, string> list_fp; 
    //NB: below, by way of example, construction using the 'greater<int>' comparison class achieves _descending_ order 
    multimap<int, string, greater<int> > list_int; 
    list<string> list_str; 

    for (int next=0; next < element_count; next++)
    {
        cout << "\033[A\033[2K" << flush;
        cout << "enter next element in list ["<< next+1 << "/" << element_count << "] : "; 
        getline (cin,str);

        if (regex_match(str, re_xdigit))
        {
            //see all about manipulators here:
            //http://www.cplusplus.com/reference/iostream/istream/operator%3E%3E/
            stringstream(str) >> hex >> i;            
            list_int.insert(pair<int, string>(i, str)); 
            list_num.insert(pair<double, string>(i, str)); 
        }
        else if (regex_match(str, re_digit))
        {
            stringstream(str) >> i;            
            list_int.insert(pair<int, string>(i, str));            
            list_num.insert(pair<double, string>(i, str)); 
        }
        else if (regex_match(str, re_float))
        {
            stringstream(str) >> d;    
            list_fp.insert(pair<double, string>(d, str));        
            list_num.insert(pair<double, string>(d, str)); 
        } 

        if (regex_match(str, re_char)) countc++;      
        list_str.push_back(str);
    }    

    cout << "\033[A\033[2K" << flush;

    cout << "input: unsorted list:" << endl;
    for (list<string>::iterator it=list_str.begin(); it!=list_str.end(); it++) 
        cout << *it << endl;

    if (list_int.size() == element_count)
    {
        cout << endl << "output: sorted list of Z+ types:" << endl;
        for (multimap<int, string>::iterator it=list_int.begin() ; it != list_int.end(); it++ )
            cout << (*it).second << endl;
    }
    else if (list_fp.size() == element_count)
    {
        cout << endl << "output: sorted list of fp types:" << endl;
        for (multimap<double, string>::iterator it=list_fp.begin() ; it != list_fp.end(); it++ )
            cout << (*it).second << endl;
    }
    else if (list_num.size() == element_count)
    {
        cout << endl << "output: sorted list of numeric types:" << endl;
        for (multimap<double, string>::iterator it=list_num.begin() ; it != list_num.end(); it++ )
            cout << (*it).second << endl;
    }
    else //output as sorted strings ~but in _descending_ order, using reverse iterator, by way of example
    {
        list_str.sort(); //but best to use list_str.sort(greater<string>()); with forward iterators
        cout << endl << "output: sorted list of " <<  (countc == element_count ? "non numeric char" : "string") << " types:" << endl;
        for (list<string>::reverse_iterator it=list_str.rbegin(); it!=list_str.rend(); ++it) 
            cout << *it << endl;        
    }   

    return 0;
}

Contoh telah dikompilasi & dijalankan di Ubuntu. Hal-hal baris perintah:

$
$ lsb_release -d
Description:    Ubuntu 11.10

$ g++ --version
g++ (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1 

$ g++ --pedantic -oblah blah.cpp -lboost_regex
$ ./blah
input: unsorted list:
4.77
2.0e+2
-.3
11
0x10

output: sorted list of numeric types:
-.3
4.77
11
0x10
2.0e+2
$


NB: Ini contoh kodenya:

  • Ada banyak optimasi yang bisa dilakukan di sini. Anda jelas tidak membutuhkan stl container sebanyak yang saya gunakan.
  • Saya tidak secara ketat membahas arah hal tersebut (tetapi tunjukkan beberapa cara yang dapat dicapai).
  • Mungkin juga bagus untuk merangkum fungsionalitas tipe spesifik dalam objek C++; punya kelas dasar & kemudian kelas turunan untuk setiap jenis yang ingin Anda dukung ~tetapi pekerjaan rumah ini kan? -jadi mungkin tidak layak untuk berlebihan;)
person violet313    schedule 13.06.2012