C++ Primer Plus习题及答案-第十二章

习题选自:C++ Primer Plus(第六版)
内容仅供参考,如有错误,欢迎指正 !

  • c++使用new和delete运算符来动态控制内存。
  • 对于静态成员,要在类声明之外使用单独语句进行初始化,因为静态类成员函数是单独存储的,而不是对象的组成部分,而且初始化是在方法文件中,而不是在头文件中,这是因为类声明位于头文件中,程序可能将头文件包括在其他几个文件中,如果在头文件中初始化,将出现多个初始化语句副本,从而引发错误。但如果静态成员是整形或枚举型const,则可以在类声明中初始化。
  • 私有静态变量有且仅在初始化时,才可以在外部访问。
  • 复制构造函数用于将一个对象复制到新创建的对象中,它用于初始化过程中(包括按值传递参数)。

复习题

1. 假设String 类有如下私有成员:
class String
{
   private:
      char * str;  //points to string allocated by new
      int len;    //holds length of string
   //...
};
a. 下述默认构造函数有什么问题?
String ::String() {}
b. 下述构造函数有什么问题?
String:: String (const char* s)
{
     str = s:
     len = strlen(s);
}
c. 下述构造西数有什么问题?
String: :String (const char* s)
{
     strcpy(str, s);
     len = strlen(s);
}

a. 语法是正确的,但该构造函数没有初始化str指针。该构造函数应该使用new[]来初始化它,或者将其设置为NULL。

b. 该构造函数没有创建新的字符串,只是复制了原有字符串的地址,它应当使用new[]和strcpy()。

c. 它虽然复制了字符串,但没有给他分配存储空间,应使用new char[len+1]来分配适当数量的内存。

2. 如果您定义了一个类,其指针成员是使用 new 初始化的,请指出可能出现的3个问题以及如何纠正这些问题。

可能出现的:

  • 问题一:当对象过期的时候,对象的成员指针指向的数据仍保留在内存中,造成内存泄漏。

    在析构函数中删除构造函数中new分配的内存,来解决该问题。

  • 问题二:如果使用对象初1始化为另一个对象2时,采用默认初始化的方式,则在对象1过期后,在对象2过期过程中,其析构函数会对同一块内存释放两次,造成错误。

    定义一个复制构造函数,使初始化复制指针指向的数据,而不是复制指针指向的地址。

  • 问题三:将一个对象赋给另一个对象也将导致两个指针指向同一个数据。

    重载赋值运算符,使之复制数据,而不是指针。

3. 如果没有显式提供类方法,编译器将自动生成哪些类方法?请描述这些隐式生成的函数的行为。

如果没有显示提供方法,c++将自动生成以下成员函数:

  • 构造函数:默认构造函数不完成任何工作,但使得能够声明数组和未初始化对象。
  • 复制构造函数:默认赋值构造函数使用成员赋值。
  • 赋值运算符:默认赋值运算法使用成员赋值。
  • 析构函数:默认析构函数不完成任何工作。
  • 地址运算符:隐式地址运算符返回调用对象的地址(即this指针的值)。
4. 找出并改正下述类声明中的错误:
class nifty
{
    // data
     char personality[];
     int talents;
    // methods
     nifty();
     nifty(char * s);
     ostream & operator<<(ostream & os, nifty & n);
}

nifty:nifty()
{
     personality = NULL;
     talents = 0;
}

nifty:nifty(char * s)
{
     personality = new char [strlen(s)];
     personality = s;
     talents = 0;
}

ostream & nifty:operator<<(ostream & os, nifty & n)
{
     os << n;
}

应将personality成员声明为字符数组或car指针,或者将其声明为String对象。该声明没有将方法设置为公有的。修改后:

#include 
#include 
using namespace std;
class nifty
{
    private: // optional
    char personality[40]; // provide array size
    int talents;
    public: // needed
    // methods
    nifty();
    nifty(const char * s);
    friend ostream & operator<<(ostream & os, const nifty & n);
}; // note closing semicolon
nifty::nifty()
{
    personality[0] = '\0';
    talents = 0;
}
nifty::nifty(const char * s)
{
    strcpy(personality, s);
    talents = 0;
}
ostream & operator<<(ostream & os, const nifty & n)
{
    os << n.personality << '\n';
    os << n.talent << '\n';
    return os;
}
5. 对于下面的类声明:
class Golfer
{
    private:
     char * fullname; // points to string containing golfer's name
     int games; // holds number of golf games played
     int * scores; // points to first element of array of golf scores
    public:
     Golfer();
     Golfer(const char * name, int g= 0);
     // creates empty dynamic array of g elements if g > 0
     Golfer(const Golfer & g);
     ~Golfer();
};
a. 下列各条语句将调用哪些类方法?
Golfer nancy;                     // #1
Golfer lulu(“Little Lulu”);       // #2
Golfer roy(“Roy Hobbs”, 12);      // #3
Golfer * par = new Golfer;        // #4
Golfer next = lulu;               // #5
Golfer hazzard = “Weed Thwacker”; // #6
*par = nancy;                     // #7
nancy = “Nancy Putter”;           // #8
b. 很明显,类需要有另外几个方法才能更有用,但是类需要哪些方法才能防止数据被损坏呢?

a.

Golfer nancy;                     // 默认构造函数
Golfer lulu("Little Lulu");       // Golfer(const char * name, int g)
Golfer roy("Roy Hobbs", 12);      // Golfer(const char * name, int g)
Golfer* par = new Golfer;         // 默认构造函数
Golfer next = lulu;               // Golfer(const Golfer &g)
Golfer hazard = "Weed Thwacker";  // Golfer(const char * name, int g)
*par = nancy;                     // 默认赋值运算符
nancy = "Nancy Putter";           // 先调用Golfer(const char * name, int g), 再默认赋值运算符

b. 有以下两个方法:

  1. 防止拷贝,将赋值运算符(面向对象拷贝给对象的)/复制构造函数,放在私有部分;
  2. 类应定义一个复制数据(而不是地址)的赋值运算符。

编程练习

1. 对于下面的类声明:
class Cow {
    char name[20];
    char * hobby;
    double weight;
  public:
    Cow();
    Cow(const char * nm, const char * ho, double wt);
    Cow(const Cow c&);
    ~Cow();
    Cow & operator=(const Cow & c);
    void ShowCow() const; // display all cow data
};
给这个类提供实现,并编写一个使用所有成员函数的小程序。

cow.h:

#ifndef COW_H_
#define COW_H_

class Cow {
    private:
        char name[20];
        char * hobby;
        double weight;

    public:
        Cow(); 
        Cow(const char * nm, const char * ho, double wt);
        Cow(const Cow & c);
        ~Cow() { delete [] hobby; }
        Cow & operator=(const Cow & c);
        void show() const;
};

#endif

cow.cpp:

#include "cow.h"

#include 
#include 

Cow::Cow() {
  name[0] = '\0';
  hobby = nullptr;
  weight = 0.0;
}

Cow::Cow(const char* nm, const char* ho, double wt) {
  std::strncpy(name, nm, 20);
  int len = std::strlen(ho) + 1;
  hobby = new char[len];
  std::strcpy(hobby, ho);

  weight = wt;
}

Cow::Cow(const Cow& c) {
  std::strncpy(name, c.name, 20);
  int len;
  len = std::strlen(c.hobby);
  hobby = new char[len];
  std::strcpy(hobby, c.hobby);
  weight = c.weight;
}

Cow& Cow::operator=(const Cow& c) {
  if (this == &c) return *this;  // object assigned to itself
  std::strncpy(name, c.name, 20);
  delete[] hobby;
  int len;
  len = std::strlen(c.hobby);
  hobby = new char[len];
  std::strcpy(hobby, c.hobby);
  weight = c.weight;
  return *this;
}

void Cow::show() const {
  std::cout << "name: " << name << std::endl;
  std::cout << "hobby: " << hobby << std::endl;
  std::cout << "weight: " << weight << std::endl;
}

main.cpp:

#include 
#include "cow.h"

int main() {
  Cow c1("xiao", "eating", 100);
  c1.show();
  Cow c2 = c1;
  c2.show();
  Cow c3;
  c3 = c2;
  c3.show();
  return 0;
}
2. 通过下面的工作来改进String类声明(即将String1.h升级为String2.h)。
a. 对+运算符进行重载,使之可将两个字符串合并成一个。
b. 提供一个Stringlow()成员函数,将字符串中所有的字母字符转换为小写(别忘了cctype系列字符函数)。
c. 提供String()成员函数,将字符串中所有字母字符转换成大写。
d. 提供一个这样的成员函数,它接受一个char参数,返回该字符在字符串中出现的次数。
使用下面的程序来测试您的工作:
// pe12_2.cpp
#include 
using namespace std;
#include "string2.h"
int main()
{
    String s1(" and I am a C++ student.");
    String s2 = "Please enter your name: ";
    String s3;
    cout << s2; // overloaded << operator
    cin >> s3; // overloaded >> operator
    s2 = "My name is " + s3; // overloaded =, + operators
    cout << s2 << ".\n";
    s2 = s2 + s1;
    s2.stringup(); // converts string to uppercase
    cout << "The string\n" << s2 << "\ncontains " << s2.has('A')
        << " 'A' characters in it.\n";
    s1 = "red"; // String(const char *),
    // then String & operator=(const String&)
    String rgb[3] = { String(s1), String("green"), String("blue")};
    cout << "Enter the name of a primary color for mixing light: ";
    String ans;
    bool success = false;
    while (cin >> ans)
    {
        ans.stringlow(); // converts string to lowercase
        for (int i = 0; i < 3; i++)
        {
            if (ans == rgb[i]) // overloaded == operator
            {
                cout << "That's right!\n";
                success = true;
                break;
            }
        }
        if (success)
            break;
        else
            cout << "Try again!\n";
    }
    cout << "Bye\n";
    return 0;
}
输出应与下面相似:
Please enter your name: Fretta Farbo
My name is Fretta Farbo.
The string
MY NAME IS FRETTA FARBO AND I AM A C++ STUDENT.
contains 6 'A' characters in it.
Enter the name of a primary color for mixing light: yellow
Try again!
BLUE
That's right!
Bye

string2.h:

#ifndef STRING2_H_
#define STRING2_H_

#include 
using std::istream;
using std::ostream;

class String {
private:
char *str;
int len;
static int num_strings;
static const int CINLIM = 80;

public:
String(const char *s);
String();
String(const String &s);
~String();
int length() const { return len; }
void stringlow();
void stringup();
int has(char x);

String &operator=(const String &s);
String &operator=(const char *s);
char &operator[](int i);
const char &operator[](int i) const;

String operator+(const String &s) const;
String operator+(const char *s) const;

friend bool operator<(const String &s1, const String &s2);
friend bool operator>(const String &s1, const String &s2);
friend bool operator==(const String &s1, const String &s2);
friend ostream &operator<<(ostream &os, const String &st);
friend istream &operator>>(istream &is, String &st);
friend String operator+(const char *, const String &);

static int HowMany();
};

#endif  // STRING2_H_

string.cpp:

#include "string2.h"

// #include 
#include 

// initialize static members
int String::num_strings = 0;

int String::HowMany() { return num_strings; }

String::String(const char *s) {
len = std::strlen(s);
str = new char[len + 1];
std::strcpy(str, s);
num_strings++;
}

String::String() {
len = 1;
str = new char[1];
str[0] = '\0';
num_strings++;
}

String::String(const String &s) {
len = s.len;
str = new char[len + 1];
std::strcpy(str, s.str);
num_strings++;
}

String::~String() {
--num_strings;
delete[] str;
}

void String::stringlow() {
for (int i = 0; i < len; ++i) {
 if (std::isupper(str[1])) str[i] = std::tolower(str[i]);
}
}
void String::stringup() {
for (int i = 0; i < len; ++i)
 if (std::islower(str[i])) str[i] = std::toupper(str[i]);
}

int String::has(char x) {
int count = 0;
for (int i = 0; i < len; ++i) {
 if (str[i] == x) count++;
}
return count;
}

String &String::operator=(const String &s) {
if (this == &s) return *this;
delete[] str;
len = s.len;
str = new char[len + 1];
std::strcpy(str, s.str);
return *this;
}

String &String::operator=(const char *s) {
delete[] str;
len = std::strlen(s);
str = new char[len + 1];
std::strcpy(str, s);
return *this;
}

char &String::operator[](int i) { return str[i]; }

const char &String::operator[](int i) const { return str[i]; }

String String::operator+(const String &s) const {
int total_len = len + s.len;
char *tmp = new char[total_len + 1];
std::strcpy(tmp, str);
std::strcat(tmp, s.str);
String str_new = tmp;
delete[] tmp;
return str_new;
}

String String::operator+(const char *s) const {
String tmp = s;
String sum = *this + tmp;
return sum;
}

bool operator<(const String &s1, const String &s2) {
return (std::strcmp(s1.str, s2.str) < 0);
}
bool operator>(const String &s1, const String &s2) {
return (std::strcmp(s1.str, s2.str) > 0);
}
bool operator==(const String &s1, const String &s2) {
//比较相等的时候不考虑大小写,使用strcasecmp(linux)/stricmp(windows)
return (strcasecmp(s1.str, s2.str) == 0);
}
ostream &operator<<(ostream &os, const String &st) {
os << st.str;
return os;
}
istream &operator>>(istream &is, String &st) {
char tmp[String::CINLIM];
is.get(tmp, String::CINLIM);
if (is) st = tmp;
while (is && is.get() != '\n') continue;
return is;
}
String operator+(const char *s1, const String &s2) { return String(s1) + s2; }
3. 新编写程序清单10.7和程序清单10.8描述的Stock类,使之使用动态分配的内存,而不是string类对象来存储股票名称。另外,使用重

载的operator<<()定义代替show()成员函数。再使用程序清单10.9测试新的定义程序。

stock20.h:

// stock20.h -- augmented version
#ifndef STOCK20_H_
#define STOCK20_H_
#include 

class Stock {
 private:
  char* company;
  int shares;
  double share_val;
  double total_val;
  void set_tot() { total_val = shares * share_val; }

 public:
  Stock();  // default constructor
  Stock(const char* co, long n = 0, double pr = 0.0);
  ~Stock();  // do-nothing destructor
  void buy(long num, double price);
  void sell(long num, double price);
  void update(double price);
  friend std::ostream& operator<<(std::ostream& os, const Stock& st);
  const Stock& topval(const Stock& s) const;
};
#endif

stock.cpp:

// stock20.h -- augmented version
#ifndef STOCK20_H_
#define STOCK20_H_
#include 

class Stock {
 private:
  char* company;
  int shares;
  double share_val;
  double total_val;
  void set_tot() { total_val = shares * share_val; }

 public:
  Stock();  // default constructor
  Stock(const char* co, long n = 0, double pr = 0.0);
  ~Stock();  // do-nothing destructor
  void buy(long num, double price);
  void sell(long num, double price);
  void update(double price);
  friend std::ostream& operator<<(std::ostream& os, const Stock& st);
  const Stock& topval(const Stock& s) const;
};
#endif

usestock20.cpp:

// stock20.cpp -- augmented version
#include "stock20.h"

#include 
// constructors
Stock::Stock()  // default constructor
{
  company = new char[std::strlen("no name") + 1];
  std::strcpy(company, "no name");
  shares = 0;
  share_val = 0.0;
  total_val = 0.0;
}
Stock::Stock(const char* co, long n, double pr) {
  company = new char[std::strlen(co) + 1];
  std::strcpy(company, co);
  if (n < 0) {
    std::cout << "Number of shares can’t be negative; " << company
              << " shares set to 0.\n";
    shares = 0;
  } else
    shares = n;
  share_val = pr;
  set_tot();
}
// class destructor
Stock::~Stock()  // quiet class destructor
{
  delete[] company;
}
// other methods
void Stock::buy(long num, double price) {
  if (num < 0) {
    std::cout << "Number of shares purchased can’t be negative. "
              << "Transaction is aborted.\n";
  } else {
    shares += num;
    share_val = price;
    set_tot();
  }
}
void Stock::sell(long num, double price) {
  using std::cout;
  if (num < 0) {
    cout << "Number of shares sold can’t be negative. "
         << "Transaction is aborted.\n";
  } else if (num > shares) {
    cout << "You can’t sell more than you have! "
         << "Transaction is aborted.\n";
  } else {
    shares -= num;
    share_val = price;
    set_tot();
  }
}
void Stock::update(double price) {
  share_val = price;
  set_tot();
}

std::ostream& operator<<(std::ostream& os, const Stock& st) {
  using std::ios_base;
  // set format to #.###
  ios_base::fmtflags orig = os.setf(ios_base::fixed, ios_base::floatfield);
  std::streamsize prec = os.precision(3);
  os << "Company: " << st.company << " Shares: " << st.shares << '\n';
  os << " Share Price: $" << st.share_val;
  // set format to #.##
  os.precision(2);
  os << " Total Worth: $" << st.total_val << '\n';
  // restore original format
  os.setf(orig, ios_base::floatfield);
  os.precision(prec);
  return os;
}

const Stock& Stock::topval(const Stock& s) const {
  if (s.total_val > total_val)
    return s;
  else
    return *this;
}
4.请看下面程序清单10.10定义的Stack类的变量:
// stack.h -- class declaration for the stack ADT
typedef unsigned long Item;
class Stack
{
    private:
    enum {MAX = 10}; // constant specific to class
    Item * pitems; // holds stack items
    int size; // number of elements in stack
    int top; // index for top stack item
    public:
    Stack(int n = MAX); // creates stack with n elements
    Stack(const Stack & st);
    ~Stack();
    bool isempty() const;
    bool isfull() const;
    // push() returns false if stack already is full, true otherwise
    bool push(const Item & item); // add item to stack
    // pop() returns false if stack already is empty, true otherwise
    bool pop(Item & item); // pop top into item
    Stack & operator=(const Stack & st);
};
正如私有成员表明的,这个类使用动态分配的数组来保存栈项。请重新编写方法,以适应这种新的表示法,并编写一个程序来演示所有的方法,包括复制构造函数和赋值运算符。

stack.h:

// stack.h -- class declaration for the stack ADT
#ifndef STACK_H_
#define STACK_H_
#include 

typedef unsigned long Item;
class Stack {
 private:
  enum { MAX = 10 };  // constant specific to class
  Item* pitems;       // holds stack items
  int size;           // number of elements in stack
  int top;            // index for top stack item
 public:
  Stack(int n = MAX);  // creates stack with n elements
  Stack(const Stack& st);
  ~Stack();
  bool isempty() const;
  bool isfull() const;
  // push() returns false if stack already is full, true otherwise
  bool push(const Item& item);  // add item to stack
  // pop() returns false if stack already is empty, true otherwise
  bool pop(Item& item);  // pop top into item
  Stack& operator=(const Stack& st);
  friend std::ostream& operator<<(std::ostream& os, const Stack& st);
};

#endif  // STACK_H_

stack.cpp:

// stack.cpp -- Stack member functions
#include "stack.h"
Stack::Stack(int n)  // create an empty stack
{
  size = MAX;
  top = 0;
  pitems = new Item[size];
  for (int i = 0; i < size; ++i) pitems[i] = 0;
}

Stack::Stack(const Stack& st) {
  delete[] pitems;
  size = st.size;
  top = st.top;
  pitems = new Item[size];
  for (int i = 0; i < size; ++i) pitems[i] = st.pitems[i];
}

Stack::~Stack() { delete[] pitems; }

bool Stack::isempty() const { return top == 0; }
bool Stack::isfull() const { return top == MAX; }

bool Stack::push(const Item& item) {
  if (top < MAX) {
    pitems[top++] = item;
    return true;
  } else
    return false;
}

bool Stack::pop(Item& item) {
  if (top > 0) {
    item = pitems[--top];
    return true;
  } else
    return false;
}

Stack& Stack::operator=(const Stack& st) {
  if (this == &st) return *this;
  delete[] pitems;
  size = st.size;
  top = st.top;
  pitems = new Item[size];
  for (int i = 0; i < size; ++i) pitems[i] = st.pitems[i];
  return *this;
}

std::ostream& operator<<(std::ostream& os, const Stack& st) {
  for (int i = 0; i < st.top; i++) {
    os << st.pitems[i] << std::endl;
  }
  return os;
}

main.cpp:

// stacker.cpp -- testing the Stack class
#include   // or ctype.h
#include 

#include "stack.h"
int main() {
  using namespace std;
  Stack st;  // create an empty stack
  char ch;
  unsigned long po;
  cout << "Please enter A to add a purchase order,\n"
       << "P to process a PO, or Q to quit.\n";
  while (cin >> ch && toupper(ch) != 'Q') {
    while (cin.get() != '\n') continue;
    if (!isalpha(ch)) {
      cout << '\a';
      continue;
    }
    switch (ch) {
      case 'A':
      case 'a':
        cout << "Enter a PO number to add: ";
        cin >> po;
        if (st.isfull())
          cout << "stack already full\n";
        else
          st.push(po);
        break;
      case 'P':
      case 'p':
        if (st.isempty())
          cout << "stack already empty\n";
        else {
          st.pop(po);
          cout << "PO #" << po << " popped\n";
        }
        break;
    }
    cout << "Please enter A to add a purchase order,\n"
         << "P to process a PO, or Q to quit.\n";
  }
  Stack st2;
  st2 = st;
  cout << "stack2 = stack is:\n" << st2;

  cout << "Bye\n";
  return 0;
}
5. Heather银行进行的研究表明,ATM客户不希望排队时间不超过1分钟。使用程序清单12.10中的模拟,找出要使平均等候时间为1分钟,每小时到达的客户数应为多少(试验时间不短于100小时)?

根据实际情况可知,每小时到达的客户数目越多,则平均等候时间越长,若要求平均等候时间为1分钟(即平均等候时间不超过1分钟时的临界情况)对应的每小时到达客户数,则我们可以让程序从每小时客户数从1开始计算(不小于100小时)其对应的平均排队时间,直到平均等待时间刚好超过1分钟的时候停止,此时对应的客户数(或者对应客户数-1)即为答案。

queue.h(未修改):

// queue.h -- interface for a queue
#ifndef QUEUE_H_
#define QUEUE_H_
// This queue will contain Customer items
class Customer {
 private:
  long arrive;      // arrival time for customer
  int processtime;  // processing time for customer
 public:
  Customer() { arrive = processtime = 0; }
  void set(long when);
  long when() const { return arrive; }
  int ptime() const { return processtime; }
};
typedef Customer Item;

class Queue {
 private:
  // class scope definitions
  // Node is a nested structure definition local to this class
  struct Node {
    Item item;
    struct Node* next;
  };
  enum { Q_SIZE = 10 };
  // private class members
  Node* front;      // pointer to front of Queue
  Node* rear;       // pointer to rear of Queue
  int items;        // current number of items in Queue
  const int qsize;  // maximum number of items in Queue
  // preemptive definitions to prevent public copying
  Queue(const Queue& q) : qsize(0) {}
  Queue& operator=(const Queue& q) { return *this; }

 public:
  Queue(int qs = Q_SIZE);  // create queue with a qs limit
  ~Queue();
  bool isempty() const;
  bool isfull() const;
  int queuecount() const;
  bool enqueue(const Item& item);  // add item to end
  bool dequeue(Item& item);        // remove item from front
};
#endif

queue.cpp(未修改):

// queue.cpp -- Queue and Customer methods
#include "queue.h"

#include   // (or stdlib.h) for rand()
// Queue methods
Queue::Queue(int qs) : qsize(qs) {
  front = rear = NULL;  // or nullptr
  items = 0;
}
Queue::~Queue() {
  Node* temp;
  while (front != NULL)  // while queue is not yet empty
  {
    temp = front;         // save address of front item
    front = front->next;  // reset pointer to next item
    delete temp;          // delete former front
  }
}
bool Queue::isempty() const { return items == 0; }
bool Queue::isfull() const { return items == qsize; }
int Queue::queuecount() const { return items; }
// Add item to queue
bool Queue::enqueue(const Item& item) {
  if (isfull()) return false;
  Node* add = new Node;  // create node
  // on failure, new throws std::bad_alloc exception
  add->item = item;  // set node pointers
  add->next = NULL;  // or nullptr;
  items++;
  if (front == NULL)  // if queue is empty,
    front = add;      // place item at front
  else
    rear->next = add;  // else place at rear
  rear = add;          // have rear point to new node
  return true;
}
// Place front item into item variable and remove from queue
bool Queue::dequeue(Item& item) {
  if (front == NULL) return false;
  item = front->item;  // set item to first item in queue
  items--;
  Node* temp = front;   // save location of first item
  front = front->next;  // reset front to next item
  delete temp;          // delete former first item
  if (items == 0) rear = NULL;
  return true;
}
// customer method
// when is the time at which the customer arrives
// the arrival time is set to when and the processing
// time set to a random value in the range 1 - 3
void Customer::set(long when) {
  processtime = std::rand() % 3 + 1;
  arrive = when;
}

main.cpp:

// bank.cpp -- using the Queue interface
// compile with queue.cpp
#include   // for rand() and srand()
#include     // for time()
#include 

#include "queue.h"
const int MIN_PER_HR = 60;
bool newcustomer(double x);  // is there a new customer?
int main() {
  using std::cin;
  using std::cout;
  using std::endl;
  using std::ios_base;
  // setting things up
  std::srand(std::time(0));  // random initializing of rand()
  cout << "Case Study: Bank of Heather Automatic Teller\n";
  cout << "Enter maximum size of queue: ";
  int qs;
  cin >> qs;
  Queue line(qs);  // line queue holds up to qs people
  cout << "Enter the number of simulation hours: ";
  int hours;  // hours of simulation
  cin >> hours;
  // simulation will run 1 cycle per minute
  long cyclelimit = MIN_PER_HR * hours;  // # of cycles

  double perhour = 1;  // number of customers per hour starts from 1

  double min_per_cust;  // average time between arrivals
  min_per_cust = MIN_PER_HR / perhour;
  Item temp;                // new customer data
  long turnaways = 0;       // turned away by full queue
  long customers = 0;       // joined the queue
  long served = 0;          // served during the simulation
  long sum_line = 0;        // cumulative line length
  int wait_time = 0;        // time until autoteller is free
  long line_wait = 0;       // cumulative time in line
  double average_time = 0;  // average time
  while (perhour++ && average_time <= 1) {
    while (!line.isempty()) {
      line.dequeue(temp);
    }
    min_per_cust = MIN_PER_HR / perhour;

    for (int cycle = 0; cycle < cyclelimit; cycle++) {
      if (newcustomer(min_per_cust)) {
        if (line.isfull())
          turnaways++;
        else {
          customers++;
          temp.set(cycle);
          line.enqueue(temp);
        }
      }
      if (wait_time <= 0 && !line.isempty()) {
        line.dequeue(temp);
        wait_time = temp.ptime();
        line_wait += cycle - temp.when();
        served++;
      }
      if (wait_time > 0) wait_time--;
      sum_line += line.queuecount();
    }

    if (customers > 0) {
      average_time = (double)line_wait / served;
      cout << "customers accepted: " << customers << endl;
      cout << "  customers served: " << served << endl;
      cout << "         turnaways: " << turnaways << endl;
      cout << "average queue size: ";
      cout.precision(2);
      cout.setf(ios_base::fixed, ios_base::floatfield);
      cout << (double)sum_line / cyclelimit << endl;
      cout << " average wait time: " << average_time << " minutes\n";
    } else
      cout << "No customers!\n";
  }
  cout << "When there comes " << perhour
       << " people per hour, the average wait time will be about 1 minute.\n";

  cout << "Done!\n";
  return 0;
}
// x = average time, in minutes, between customers
// return value is true if customer shows up this minute
bool newcustomer(double x) { return (std::rand() * x / RAND_MAX < 1); }

实验过程中,队列最大数为10,模拟小时数为100,结果如下:

Case Study: Bank of Heather Automatic Teller
Enter maximum size of queue: 10
Enter the number of simulation hours: 100
customers accepted: 217
  customers served: 217
         turnaways: 0
average queue size: 0.00
 average wait time: 0.06 minutes
customers accepted: 522
  customers served: 522
         turnaways: 0
average queue size: 0.01
 average wait time: 0.07 minutes
customers accepted: 941
  customers served: 941
         turnaways: 0
average queue size: 0.01
 average wait time: 0.09 minutes
customers accepted: 1465
  customers served: 1465
         turnaways: 0
average queue size: 0.02
 average wait time: 0.10 minutes
customers accepted: 2078
  customers served: 2078
         turnaways: 0
average queue size: 0.04
 average wait time: 0.12 minutes
customers accepted: 2821
  customers served: 2821
         turnaways: 0
average queue size: 0.07
 average wait time: 0.15 minutes
customers accepted: 3640
  customers served: 3640
         turnaways: 0
average queue size: 0.10
 average wait time: 0.17 minutes
customers accepted: 4525
  customers served: 4525
         turnaways: 0
average queue size: 0.14
 average wait time: 0.19 minutes
customers accepted: 5534
  customers served: 5534
         turnaways: 0
average queue size: 0.20
 average wait time: 0.21 minutes
customers accepted: 6617
  customers served: 6617
         turnaways: 0
average queue size: 0.26
 average wait time: 0.24 minutes
customers accepted: 7780
  customers served: 7780
         turnaways: 0
average queue size: 0.35
 average wait time: 0.27 minutes
customers accepted: 9094
  customers served: 9094
         turnaways: 0
average queue size: 0.47
 average wait time: 0.31 minutes
customers accepted: 10427
  customers served: 10427
         turnaways: 0
average queue size: 0.60
 average wait time: 0.34 minutes
customers accepted: 11989
  customers served: 11989
         turnaways: 0
average queue size: 0.82
 average wait time: 0.41 minutes
customers accepted: 13588
  customers served: 13588
         turnaways: 0
average queue size: 1.02
 average wait time: 0.45 minutes
customers accepted: 15277
  customers served: 15277
         turnaways: 0
average queue size: 1.25
 average wait time: 0.49 minutes
customers accepted: 17118
  customers served: 17116
         turnaways: 0
average queue size: 1.55
 average wait time: 0.54 minutes
customers accepted: 19000
  customers served: 18998
         turnaways: 0
average queue size: 1.90
 average wait time: 0.60 minutes
customers accepted: 21012
  customers served: 21009
         turnaways: 0
average queue size: 2.39
 average wait time: 0.68 minutes
customers accepted: 23139
  customers served: 23136
         turnaways: 0
average queue size: 2.94
 average wait time: 0.76 minutes
customers accepted: 25374
  customers served: 25368
         turnaways: 0
average queue size: 3.59
 average wait time: 0.85 minutes
customers accepted: 27661
  customers served: 27653
         turnaways: 0
average queue size: 4.36
 average wait time: 0.95 minutes
customers accepted: 30018
  customers served: 30010
         turnaways: 1
average queue size: 5.32
 average wait time: 1.06 minutes
When there comes 25.00 people per hour, the average wait time will be about 1 minute.
Done!
6.Heather银行想知道,如果再开设一台ATM,情况将如何。请对模拟进行修改,以包含两个队列。假设当第一台ATM前的排队人数少于第二台ATM时,客户将排在第一队,否则将排在第二队。然后再找出要使平均等候时间为1分钟,每小时到达的客户数应该为多少(注意,这是一个非线性问题,即将ATM数量加倍,并不能保证每小时处理的客户数量也翻倍,并确保客户等候的时间少于1分钟)?

queue.h(未修改):

// queue.h -- interface for a queue
#ifndef QUEUE_H_
#define QUEUE_H_
// This queue will contain Customer items
class Customer {
 private:
  long arrive;      // arrival time for customer
  int processtime;  // processing time for customer
 public:
  Customer() { arrive = processtime = 0; }
  void set(long when);
  long when() const { return arrive; }
  int ptime() const { return processtime; }
};
typedef Customer Item;

class Queue {
 private:
  // class scope definitions
  // Node is a nested structure definition local to this class
  struct Node {
    Item item;
    struct Node* next;
  };
  enum { Q_SIZE = 10 };
  // private class members
  Node* front;      // pointer to front of Queue
  Node* rear;       // pointer to rear of Queue
  int items;        // current number of items in Queue
  const int qsize;  // maximum number of items in Queue
  // preemptive definitions to prevent public copying
  Queue(const Queue& q) : qsize(0) {}
  Queue& operator=(const Queue& q) { return *this; }

 public:
  Queue(int qs = Q_SIZE);  // create queue with a qs limit
  ~Queue();
  bool isempty() const;
  bool isfull() const;
  int queuecount() const;
  bool enqueue(const Item& item);  // add item to end
  bool dequeue(Item& item);        // remove item from front
};
#endif

queue.cpp(未修改):

// queue.cpp -- Queue and Customer methods
#include "queue.h"

#include   // (or stdlib.h) for rand()
// Queue methods
Queue::Queue(int qs) : qsize(qs) {
  front = rear = NULL;  // or nullptr
  items = 0;
}
Queue::~Queue() {
  Node* temp;
  while (front != NULL)  // while queue is not yet empty
  {
    temp = front;         // save address of front item
    front = front->next;  // reset pointer to next item
    delete temp;          // delete former front
  }
}
bool Queue::isempty() const { return items == 0; }
bool Queue::isfull() const { return items == qsize; }
int Queue::queuecount() const { return items; }
// Add item to queue
bool Queue::enqueue(const Item& item) {
  if (isfull()) return false;
  Node* add = new Node;  // create node
  // on failure, new throws std::bad_alloc exception
  add->item = item;  // set node pointers
  add->next = NULL;  // or nullptr;
  items++;
  if (front == NULL)  // if queue is empty,
    front = add;      // place item at front
  else
    rear->next = add;  // else place at rear
  rear = add;          // have rear point to new node
  return true;
}
// Place front item into item variable and remove from queue
bool Queue::dequeue(Item& item) {
  if (front == NULL) return false;
  item = front->item;  // set item to first item in queue
  items--;
  Node* temp = front;   // save location of first item
  front = front->next;  // reset front to next item
  delete temp;          // delete former first item
  if (items == 0) rear = NULL;
  return true;
}
// customer method
// when is the time at which the customer arrives
// the arrival time is set to when and the processing
// time set to a random value in the range 1 - 3
void Customer::set(long when) {
  processtime = std::rand() % 3 + 1;
  arrive = when;
}

main.cpp:

// bank.cpp -- using the Queue interface
// compile with queue.cpp
#include   // for rand() and srand()
#include     // for time()
#include 

#include "queue.h"
const int MIN_PER_HR = 60;
bool newcustomer(double x);  // is there a new customer?
int main() {
  using std::cin;
  using std::cout;
  using std::endl;
  using std::ios_base;
  // setting things up
  std::srand(std::time(0));  // random initializing of rand()
  cout << "Case Study: Bank of Heather Automatic Teller\n";
  cout << "Enter maximum size of queue: ";
  int qs;
  cin >> qs;
  Queue line1(qs);  // line1 queue holds up to qs people
  Queue line2(qs);  // line2 queue holds up to qs people
  cout << "Enter the number of simulation hours: ";
  int hours;  // hours of simulation
  cin >> hours;
  // simulation will run 1 cycle per minute
  long cyclelimit = MIN_PER_HR * hours;  // # of cycles

  double perhour = 1;  // number of customers per hour starts from 1

  double min_per_cust;  // average time between arrivals
  min_per_cust = MIN_PER_HR / perhour;
  Item temp;                // new customer data
  long turnaways = 0;       // turned away by full queue
  long customers = 0;       // joined the queue
  long served = 0;          // served during the simulation
  long sum_line = 0;        // cumulative line length
  int line1_size = 0;       // number of people in line1
  int line2_size = 0;       // number of people in line2
  int wait_time1 = 0;       // time until autoteller is free in line1
  int wait_time2 = 0;       // time until autoteller is free in line2
  long line_wait = 0;       // cumulative time in line
  double average_time = 0;  // average time
  while (perhour++ && average_time <= 1) {
    while (!line1.isempty()) {
      line1.dequeue(temp);
    }
    while (!line2.isempty()) {
      line2.dequeue(temp);
    }

    min_per_cust = MIN_PER_HR / perhour;

    for (int cycle = 0; cycle < cyclelimit; cycle++) {
      if (newcustomer(min_per_cust)) {
        if (line1.isfull() && line2.isfull())
          turnaways++;
        else if (line1_size < line2_size) {
          customers++;
          temp.set(cycle);
          line1.enqueue(temp);
          line1_size++;
        } else {
          customers++;
          temp.set(cycle);
          line2.enqueue(temp);
          line2_size++;
        }
      }
      if (wait_time1 <= 0 && !line1.isempty()) {
        line1.dequeue(temp);
        line1_size--;
        wait_time1 = temp.ptime();
        line_wait += cycle - temp.when();
        served++;
      }
      if (wait_time2 <= 0 && !line2.isempty()) {
        line2.dequeue(temp);
        line2_size--;
        wait_time2 = temp.ptime();
        line_wait += cycle - temp.when();
        served++;
      }
      if (wait_time1 > 0) wait_time1--;
      if (wait_time2 > 0) wait_time2--;
      sum_line += line1.queuecount() + line2.queuecount();
    }

    if (customers > 0) {
      average_time = (double)line_wait / served;
      cout << "customers accepted: " << customers << endl;
      cout << "  customers served: " << served << endl;
      cout << "         turnaways: " << turnaways << endl;
      cout << "average queue size: ";
      cout.precision(2);
      cout.setf(ios_base::fixed, ios_base::floatfield);
      cout << (double)sum_line / cyclelimit << endl;
      cout << " average wait time: " << average_time << " minutes\n";
    } else
      cout << "No customers!\n";
  }
  cout << "When there comes " << perhour
       << " people per hour, the average wait time will be about 1 minute.\n";

  cout << "Done!\n";
  return 0;
}
// x = average time, in minutes, between customers
// return value is true if customer shows up this minute
bool newcustomer(double x) { return (std::rand() * x / RAND_MAX < 1); }

实验过程中,队列最大数为10,模拟小时数为100,结果如下:

Case Study: Bank of Heather Automatic Teller
Enter maximum size of queue: 10
Enter the number of simulation hours: 100
customers accepted: 212
  customers served: 212
         turnaways: 0
average queue size: 0.00
 average wait time: 0.03 minutes
customers accepted: 520
  customers served: 520
         turnaways: 0
average queue size: 0.00
 average wait time: 0.06 minutes
customers accepted: 917
  customers served: 917
         turnaways: 0
average queue size: 0.01
 average wait time: 0.06 minutes
customers accepted: 1372
  customers served: 1372
         turnaways: 0
average queue size: 0.02
 average wait time: 0.07 minutes
customers accepted: 1987
  customers served: 1987
         turnaways: 0
average queue size: 0.03
 average wait time: 0.10 minutes
customers accepted: 2715
  customers served: 2715
         turnaways: 0
average queue size: 0.05
 average wait time: 0.11 minutes
customers accepted: 3471
  customers served: 3471
         turnaways: 0
average queue size: 0.07
 average wait time: 0.12 minutes
customers accepted: 4367
  customers served: 4367
         turnaways: 0
average queue size: 0.09
 average wait time: 0.13 minutes
customers accepted: 5368
  customers served: 5368
         turnaways: 0
average queue size: 0.13
 average wait time: 0.14 minutes
customers accepted: 6454
  customers served: 6454
         turnaways: 0
average queue size: 0.17
 average wait time: 0.16 minutes
customers accepted: 7639
  customers served: 7639
         turnaways: 0
average queue size: 0.22
 average wait time: 0.17 minutes
customers accepted: 8909
  customers served: 8909
         turnaways: 0
average queue size: 0.27
 average wait time: 0.18 minutes
customers accepted: 10292
  customers served: 10292
         turnaways: 0
average queue size: 0.33
 average wait time: 0.19 minutes
customers accepted: 11830
  customers served: 11830
         turnaways: 0
average queue size: 0.41
 average wait time: 0.21 minutes
customers accepted: 13347
  customers served: 13347
         turnaways: 0
average queue size: 0.48
 average wait time: 0.21 minutes
customers accepted: 15033
  customers served: 15033
         turnaways: 0
average queue size: 0.57
 average wait time: 0.23 minutes
customers accepted: 16837
  customers served: 16836
         turnaways: 0
average queue size: 0.67
 average wait time: 0.24 minutes
customers accepted: 18717
  customers served: 18716
         turnaways: 0
average queue size: 0.79
 average wait time: 0.25 minutes
customers accepted: 20775
  customers served: 20774
         turnaways: 0
average queue size: 0.91
 average wait time: 0.26 minutes
customers accepted: 22874
  customers served: 22873
         turnaways: 0
average queue size: 1.05
 average wait time: 0.28 minutes
customers accepted: 25038
  customers served: 25037
         turnaways: 0
average queue size: 1.20
 average wait time: 0.29 minutes
customers accepted: 27395
  customers served: 27394
         turnaways: 0
average queue size: 1.37
 average wait time: 0.30 minutes
customers accepted: 29826
  customers served: 29825
         turnaways: 0
average queue size: 1.54
 average wait time: 0.31 minutes
customers accepted: 32313
  customers served: 32312
         turnaways: 0
average queue size: 1.73
 average wait time: 0.32 minutes
customers accepted: 34782
  customers served: 34781
         turnaways: 0
average queue size: 1.90
 average wait time: 0.33 minutes
customers accepted: 37513
  customers served: 37511
         turnaways: 0
average queue size: 2.12
 average wait time: 0.34 minutes
customers accepted: 40250
  customers served: 40248
         turnaways: 0
average queue size: 2.33
 average wait time: 0.35 minutes
customers accepted: 43151
  customers served: 43149
         turnaways: 0
average queue size: 2.56
 average wait time: 0.36 minutes
customers accepted: 46116
  customers served: 46114
         turnaways: 0
average queue size: 2.80
 average wait time: 0.36 minutes
customers accepted: 49234
  customers served: 49232
         turnaways: 0
average queue size: 3.07
 average wait time: 0.37 minutes
customers accepted: 52400
  customers served: 52398
         turnaways: 0
average queue size: 3.35
 average wait time: 0.38 minutes
customers accepted: 55651
  customers served: 55648
         turnaways: 0
average queue size: 3.65
 average wait time: 0.39 minutes
customers accepted: 59012
  customers served: 59008
         turnaways: 0
average queue size: 3.97
 average wait time: 0.40 minutes
customers accepted: 62468
  customers served: 62464
         turnaways: 0
average queue size: 4.29
 average wait time: 0.41 minutes
customers accepted: 66015
  customers served: 66010
         turnaways: 0
average queue size: 4.62
 average wait time: 0.42 minutes
customers accepted: 69696
  customers served: 69691
         turnaways: 0
average queue size: 4.97
 average wait time: 0.43 minutes
customers accepted: 73509
  customers served: 73503
         turnaways: 0
average queue size: 5.38
 average wait time: 0.44 minutes
customers accepted: 77483
  customers served: 77476
         turnaways: 0
average queue size: 5.81
 average wait time: 0.45 minutes
customers accepted: 81552
  customers served: 81544
         turnaways: 0
average queue size: 6.24
 average wait time: 0.46 minutes
customers accepted: 85676
  customers served: 85668
         turnaways: 0
average queue size: 6.70
 average wait time: 0.47 minutes
customers accepted: 89893
  customers served: 89885
         turnaways: 0
average queue size: 7.18
 average wait time: 0.48 minutes
customers accepted: 94185
  customers served: 94177
         turnaways: 0
average queue size: 7.68
 average wait time: 0.49 minutes
customers accepted: 98572
  customers served: 98564
         turnaways: 0
average queue size: 8.22
 average wait time: 0.50 minutes
customers accepted: 103067
  customers served: 103058
         turnaways: 0
average queue size: 8.78
 average wait time: 0.51 minutes
customers accepted: 107697
  customers served: 107688
         turnaways: 0
average queue size: 9.38
 average wait time: 0.52 minutes
customers accepted: 112391
  customers served: 112382
         turnaways: 0
average queue size: 9.98
 average wait time: 0.53 minutes
customers accepted: 117190
  customers served: 117181
         turnaways: 0
average queue size: 10.67
 average wait time: 0.55 minutes
customers accepted: 122085
  customers served: 122075
         turnaways: 0
average queue size: 11.43
 average wait time: 0.56 minutes
customers accepted: 127075
  customers served: 127065
         turnaways: 0
average queue size: 12.17
 average wait time: 0.57 minutes
customers accepted: 132223
  customers served: 132212
         turnaways: 0
average queue size: 13.06
 average wait time: 0.59 minutes
customers accepted: 137410
  customers served: 137398
         turnaways: 0
average queue size: 14.04
 average wait time: 0.61 minutes
customers accepted: 142710
  customers served: 142697
         turnaways: 0
average queue size: 15.11
 average wait time: 0.63 minutes
customers accepted: 148126
  customers served: 148112
         turnaways: 0
average queue size: 16.21
 average wait time: 0.66 minutes
customers accepted: 153631
  customers served: 153617
         turnaways: 0
average queue size: 17.51
 average wait time: 0.68 minutes
customers accepted: 159249
  customers served: 159234
         turnaways: 0
average queue size: 19.50
 average wait time: 0.73 minutes
customers accepted: 164952
  customers served: 164936
         turnaways: 0
average queue size: 22.05
 average wait time: 0.80 minutes
customers accepted: 170746
  customers served: 170720
         turnaways: 0
average queue size: 24.75
 average wait time: 0.87 minutes
customers accepted: 176635
  customers served: 176603
         turnaways: 11
average queue size: 29.79
 average wait time: 1.01 minutes
When there comes 60.00 people per hour, the average wait time will be about 1 minute.
Done

你可能感兴趣的:(C++,Primer,Plus习题及答案,c++,开发语言)