第十六章编程练习

1.回文指的是顺读和逆读都一样的字符串。例如,“tot"和"otto"都是简短的回文。编写一个程序,让用户输入字符串,并将字符串引用传递给一个bool函数。如果字符串是回文,该函数返回true,否则返回false。此时,不要担心诸如大小写、空格和标点符号这些复杂的问题。即这个简单的版本将拒绝"Otto"和"Madam, I’m Adam”。请查看附录F中的字符串方法列表,以简化这项任务。
实现:

#include <algorithm>//reverse()
#include <iostream>
#include <string>
using std::cout;
using std::endl;
using std::string;

bool same_after_reverse(const string str);

int main(void)
{
    string str;
    cout << "Enter a string:";
    cin >> str;

    if(same_after_reverse(str))
    {
        cout << "Palindromic" << endl;
    }
    else
    {
        cout << "Not palindromic" << endl;
    }

    return 0;
}

bool same_after_reverse(const string str)
{
    string temp;
    temp = str;

    reverse(temp.begin(), temp.end());

    return temp == str;
}

2.与编程练习1中给出的题目相同,但要考虑诸如大小写、空格和标点符号这样的复杂问题。即"Madam, I’m Adam"将作为回文来测试。例如,测试函数可能会将字符串缩略为"madamimadam",然后测试倒过来是否一样。不要忘了有用的cctype库,您可能从中找到几个有用的STL函数,尽管不一定非要使用它们。
实现:

#include <algorithm>//reverse()
#include <iostream>
#include <string>
#include <cctype>
using std::cout;
using std::endl;
using std::string;
bool same_after_reverse(const string str);

int main(void)
{
    string str;
    cout << "Enter a string:";
    getline(cin,str);//读取空格

    if(same_after_reverse(str))
    {
        cout << "Palindromic" << endl;
    }
    else
    {
        cout << "Not palindromic" << endl;
    }

    return 0;
}

bool same_after_reverse(const string str)
{
    string temp;
    
    //去掉符号,转换成小写。
    for (int i = 0; i < str.size(); i++)
    {
        if (isalpha(str[i]))
        {
            temp += tolower(str[i]);
        }
    }
    string temp1 =  temp;
    reverse(temp1.begin(), temp1.end());

    return temp == temp1;
}

3.修改程序清单16.3,使之从文件中读取单词。一种方案是,使用vector<string>对象而不是string数组。这样便可以使用push_back()将数据文件中的单词复制到vector<string>对象中,并使用size()来确定单词列表的长度。由于程序应该每次从文件中读取一个单词,因此应使用运算符>>而不是getline()。文件中包含的单词应该用空格、制表符或换行符分隔。
实现:

#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <cstdlib>
using std::string;
using std::vector;
using std::cin;
using std::cout;
using std::endl;
using std::ifstream;

const int NUM = 26;

int main(void)
{
    vector<string> wordlist;

    ifstream fin;
    fin.open("wordlist.txt");
    if (fin.is_open() ==  false)
    {
        cerr << "Can't open file. Bye" << endl;
        exit(EXIT_FAILURE);
    }
    string item;
    while (fin)
    {
        getline(fin, item, ',');
        wordlist.push_back(item);
    }
    fin.close();


    char play;
    cout << "Will you play a word game? <y/n> ";
    cin >> play;
    play = tolower(play);
    while (play == 'y')
    {
        string target = wordlist[std::rand() % NUM];
        int length = target.length();
        string attempt(length, '-');
        string badchars;
        int guesses = 6;
        cout << "Guess my secret word. It has " << length
            << " letters, and you guess\n"
            << "one letter at a time. You get " << guesses
            << " wrong guesses.\n";
        cout << "Your word: " << attempt << endl;
        while (guesses > 0 && attempt != target)
        {
            char letter;
            cout << "Guess a letter: ";
            cin >> letter;
            if (badchars.find(letter) != string::npos
                || attempt.find(letter) != string::npos)
            {
                cout << "You already guessed that. Try again.\n";
                continue;
            }
            int loc = target.find(letter);
            if (loc == string::npos)
            {
                cout << "Oh, bad guess!\n";
                --guesses;
                badchars += letter; // add to string
            }
            else
            {
                cout << "Good guess!\n";
                attempt[loc] = letter;
                // check if letter appears again
                loc = target.find(letter, loc + 1);
                while (loc != string::npos)
                {
                    attempt[loc] = letter;
                    loc = target.find(letter, loc + 1);
                }
            }
            cout << "Your word: " << attempt << endl;
            if (attempt != target)
            {
                if (badchars.length() > 0)
                    cout << "Bad choices: " << badchars << endl;
                cout << guesses << " bad guesses left\n";
            }
        }
        if (guesses > 0)
            cout << "That's right!\n";
        else
            cout << "Sorry, the word is " << target << ".\n";
        cout << "Will you play another? <y/n> ";
        cin >> play;
        play = tolower(play);
    }

    cout << "Bye\n";

    return 0;
}

4.编写一个具有老式风格接口的函数,其原型如下:
int reduce(long ar[], int n);
实参应是数组名和数组中的元素个数。该函数对数组进行排序,删除重复的值,返回缩减后数组中的元素数目。请使用STL函数编写该函数(如果决定使用通用的unique()函数,请注意它将返回结果区间的结尾。)使用一个小程序测试该函数。
实现:

#include <iostream>
#include <algorithm>
using std::cout;
using std::endl;
using std::sort;
using std::unique;

int reduce(long ar[], int n);

int main(void)
{
    long arr[5] = {200,100,300,100,200};
    int size = reduce(arr, 5);
    for (int i = 0; i < size; i++)
    {
        cout << arr[i] << " ";
    }
    cout << endl;

    return 0;
}

int reduce(long ar[], int n)
{
    sort(ar, ar + n);
    long *pt = unique(ar, ar + n);

    return pt - ar;
}

5.问题与编程练习4相同,但要编写一个模板函数:

template <class T>
int reduce(T ar[], int n);

在一个使用long实例和string实例的小程序中测试该函数。
实现:

#include <iostream>
#include <list>
#include <string>
using std::string;
using std::cout;
using std::endl;
using std::list;

template <class T>
int reduce(T ar[], int n);

int main(void)
{
    long arr[5] = {200,100,300,100,200};
    int size = reduce(arr, 5);
    for (int i = 0; i < size; i++)
    {
        cout << arr[i] << " ";
    }
    cout << endl;

    string str[5] = {"hello","world","good","morning","world"};
    size = reduce(str, 5);
    for (int i = 0; i < size; i++)
    {
        cout << str[i] << " ";
    }
    cout << endl;

    return 0;
}

template <class T>
int reduce(T ar[], int n)
{
    list<T> ls;
    for (int i = 0; i < n; i++)
    {
        ls.push_back(ar[i]);
    }
    ls.sort();
    ls.unique();

    //排序后再存入ar[]
    auto pointer = ls.begin();
    for (int i = 0; i < ls.size(); i++, pointer++)
    {
        ar[i] = *pointer;
    }

    return ls.size();
}

6.使用STL queue模板类而不是第12章的Queue类,重新编写程序清单12.12所示的示例。
实现:

#include <iostream>
#include <cstdlib>
#include <queue>
using std::queue;
using std::cout;
using std::endl;
using std::rand;

class Customer
{
private:
    long arrive;
    int processtime;
public:
    Customer() { arrive = processtime = 0; }
    void set(long when);
    long when() const { return arrive; }
    int ptime()const { return processtime; }
};
typedef Customer Item;

void Customer::set(long when)
{
    arrive = when;
    processtime = rand() % 3 + 1;
}

int main(void)
{
    int qs;
    Item temp;
    int i = 0;
    int customers = 0;
    cout << "Enter maximum size of queue:";
    cin >> qs;

    queue<Item> lines;

    while(lines.size() != qs)
    {
        temp.set(i++);
        lines.push(temp);
        customers++;
    }
    cout << "Customers:" << customers << endl;

    while (lines.empty())
    {
        temp = lines.front();
        lines.pop();
        customers--;
    }
    cout << "Now customers:" << customers << endl;

    return 0;
}

7.彩票卡是一个常见的游戏。卡片上是带编号的圆点,其中一些圆点被随机选中。编写一个lotto()函数,它接受两个参数。第一个参数是彩票卡上圆点的个数,第二个参数是随机选择的圆点个数。该函数返回一个vector<int>对象,其中包含(按排列后的顺序)随机选择的号码。例如,可以这样使用该函数:

vector<int> winners;
winners = Lotto(51, 6);

这样将把一个矢量赋给winner,该矢量包含1-51中随机选定的6个数字。注意,仅仅使用rand()无法完成这项任务,因它会生成重复的值。提示:让函数创建一个包含所有可能值的矢量,使用random_shuffle(),然后通过打乱后的矢量的第一个值来获取值。编写一个小程序来测试这个函数。
实现:

#include <iostream>
#include <vector>
using std::cout;
using std::endl;
using std::vector;

vector<int> Lotto(int range, int num);

int main(void)
{
    vector<int> winners;
    winners = Lotto(51, 6);
    //vector<int>::iterator pd;
    for (auto pd = winners.begin(); pd != winners.end(); pd++)
    {
        cout << *pd << " ";
    }
    cout << endl;

    return 0;
}

vector<int> Lotto(int range, int num)
{
    vector<int> temp;
    srand(time(0));
    for (int i = 0; i < num; i++)
    {
        temp.push_back(rand() % range);
    }
    return temp;
}

8.Mat和Pat希望邀请他们的朋友来参加派对。他们要编写一个程序完成下面的任务。
让Mat输入他朋友的姓名列表。姓名存储在一个容器中,然后按排列后的顺序显示出来。
让Pat输入他朋友的姓名列表。姓名存储在一个容器中,然后按排列后的顺序显示出来。
创建第三个容器,将两个列表合并,删除重复的部分,并显示这个容器的内容。
实现:

#include <iostream>
#include <set>
#include <string>
using std::set;
using std::cout;
using std::endl;

int main(void)
{
    set<string> Mat, Pat, Guest;
    string name;

    cout << "Enter the name of Mat's friend(quit to quit):";
    while (getline(cin, name) && name != "quit")
    {
        Mat.insert(name);
    }

    cout << "Enter the name of Pat's friend(quit to quit):";
    while (getline(cin, name) && name != "quit")
    {
        Pat.insert(name);
    }

    Guest.insert(Mat.begin(), Mat.end());
    Guest.insert(Pat.begin(), Pat.end());
    cout << "The Guest's names are:" << endl;
    for (auto pd = Guest.begin(); pd != Guest.end(); pd++)
    {
        cout << *pd << " ";
    }
    cout << endl;


    return 0;
}

9.相对于数组,在链表中添加和删除元素更容易,但排序速度更慢。这就引出了一种可能性:相对于使用链表算法进行排序,将链表复制到数组中,对数组进行排序,再将排序后的结果复制到链表中的速度可能更快;但这也可能占用更多的内存。请使用如下方法检验上述假设。
a.创建大型vector<int>对象vi0,并使用rand()给它提供初始值。
b.创建vector<int>对象vi和list<int>对象li,它们的长度都和初始值与vi0相同。
c.计算使用STL算法sort()对vi进行排序所需的时间,再计算使用list的方法sort()对li进行排序所需的时间。
d.将li重置为排序的vi0的内容,并计算执行以下操作所需的时间:将li的内容复制到vi中,对vi进行排序,并将结果复制到li中。
要计算这些操作所需的时间,可使用ctime库中的clock()。正如程序清单5.14演示的,可使用下面的语句来获取开始时间:

clock_t start = clock();

再在操作结束后使用下面的语句获取经过了多长时间:

clock_t = end = clock();
cout << (double)(end - start)/CLOCK_PER_SEC;

这种测试并非绝对可靠,因为结果取决于很多因素,如可用内存量、是否支持多处理以及数组(列表)的长度(随着排序的元素数增加,数组相对于列表的效率将更明显)。另外,如果编译器提供了默认生成方式和发布生成方式,请使用发布生成方式。鉴于当今计算机的速度非常快,要获得有意义的结果,可能需要使用尽可能大的数组。例如,可尝试包含100000、1000000和10000000个元素。
实现:

#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
#include <cstdlib>
#include <ctime>
using std::cout;
using std::endl;
using std::list;
using std::vector;

int main(void)
{
    srand(time(0));
    const int limit = 1000000;
    vector<int> vi0;
    for (int i = 0; i < limit; i++)
    {
        vi0.push_back(rand() % 1000);
    }

    vector<int> vi(vi0);
    list<int> li(vi0.begin(), vi0.end());

    clock_t start = clock();//vi开始排序的时间
    sort(vi.begin(), vi.end());
    clock_t end = clock();//vi结束排序的时间
    cout << "Vector需要的时间:" << (double)(end - start) / CLOCKS_PER_SEC << endl;

    start = clock();
    li.sort();
    end = clock();
    cout << "List需要的时间:" << (double) (end - start) / CLOCKS_PER_SEC << endl;

    
    copy(vi0.begin(), vi0.end(), li.begin());//li重置为vi0
    start = clock();
    copy(li.begin(), li.end(), vi.begin());//li的内容复制到vi
    sort(vi.begin(), vi.end());//对vi进行排序
    copy(vi.begin(), vi.end(), li.begin());//排序后的结果复制到li中
    end = clock();
    cout << "新的方法后,List需要的时间:" << (double)(end - start) / CLOCKS_PER_SEC << endl;

    return 0;
}

10.请按如下方式修改程序清单16.9(vect3.cpp)
a.在结构Review中添加成员price。
b.不使用vector<Review>来存储输入,而使用vector<shared_ptr<Review>>。别忘了,必须使用new返回的指针来初始化shared_ptr。
c.在输入阶段结束后,使用一个循环让用户选择如下方式之一显示书籍:按原始顺序显示、按字母表顺序显示、按评级升序显示、按评级降序显示、按价格升序显示、按价格降序显示、退出。
下面是一种可能的解决方案:获取输入后,再创建一个shared_ptr矢量,并用原始数组初始化它。定义一个对指向结构的指针进行比较的operator<()函数,并使用它对第二个矢量进行排序,让其中的shared_ptr按其指向的对象中的书名排序。重复上述过程,创建按rating和price排序的shared_ptr矢量。请注意,通过使用rbegin()和rend(),可避免创建按相反的顺序排列的shared_ptr矢量。
实现:

#include <iostream>
#include <memory>
#include <string>
#include <algorithm>
#include <vector>
using std::cin;
using std::cout;
using std::endl;
using std::vector;
using std::shared_ptr;

struct Review
{
    string title;
    int rating;
    int price;
};

bool FillReview(Review& rr);
void ShowReview(const shared_ptr<Review>& pt);
bool worseThan(const shared_ptr<Review>& pt1, const shared_ptr<Review>& pt2);
bool cheaperThan(const shared_ptr<Review>& pt1, const shared_ptr<Review>& pt2);
bool operator<(const shared_ptr<Review>& pt1, const shared_ptr<Review>& pt2);

int main()
{
    vector<shared_ptr<Review>> books;
    Review temp;

    while (FillReview(temp))
    {
        shared_ptr<Review> pd(new Review(temp));
        books.push_back(pd);
    }

    if (books.size() > 0)
    {
        cout << "Choose the way you want to sort the books:" << endl;
        cout << "1: orignal order     2:alphabet order:" << endl;
        cout << "3: rating up order   4:rating down order:" << endl;
        cout << "5: price up order    6:price down order:" << endl;
        cout << "7: quit" << endl;
        int choice;
        while (cin >> choice)
        {
            switch (choice)
            {
            case 1:
                for_each(books.begin(), books.end(), ShowReview);
                break;
            case 2:
                sort(books.begin(), books.end());
                for_each(books.begin(), books.end(), ShowReview);
                break;
            case 3:
                sort(books.begin(), books.end(), worseThan);
                for_each(books.begin(), books.end(), ShowReview);
                break;
            case 4:
                sort(books.begin(), books.end(), worseThan);
                reverse(books.begin(), books.end());
                for_each(books.begin(), books.end(), ShowReview);
                break;
            case 5:
                sort(books.begin(), books.end(), cheaperThan);
                for_each(books.begin(), books.end(), ShowReview);
                break;
            case 6:
                sort(books.begin(), books.end(), cheaperThan);
                reverse(books.begin(), books.end());
                for_each(books.begin(), books.end(), ShowReview);
                break;
            default:
                cout << "Done" << endl;
                break;
            }
        }

    }
    else
        cout << "No entries. ";
    cout << "Bye.\n";
    return 0;
}

bool operator<(const shared_ptr<Review>& pt1, const shared_ptr<Review>& pt2)
{
    if (pt1->title < pt2->title)
        return true;
    else if (pt1->title == pt2->title && pt1->rating < pt2->rating)
        return true;
    else
        return false;
}

bool worseThan(const shared_ptr<Review>& pt1, const shared_ptr<Review>& pt2)
{
    if (pt1->rating < pt2->rating)
        return true;
    else
        return false;
}

bool cheaperThan(const shared_ptr<Review>& pt1, const shared_ptr<Review>& pt2)
{
    if (pt1->price < pt2->price)
        return true;
    else
        return false;
}
bool FillReview(Review& rr)
{
    cout << "Enter book title (quit to quit): ";
    getline(cin, rr.title);
    if (rr.title == "quit")
    {
        return false;
    }
    cout << "Enter book rating: ";
    cin >> rr.rating;

    cout << "Enter book price: ";
    cin >> rr.price;
    if (!cin)
    {
        return false;
    }

    while (cin.get() != '\n')
    {
        continue;
    }

    return true;
}

void ShowReview(const shared_ptr<Review>& pt)
{
    cout << pt->rating << "\t" << pt->title << "\t" << pt->price << endl;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值