标签归档:cpp

c++ primer 5 exercise 10.9

c++ primer 5 exercise 10.9

实现自己的elimDups程序。测试你的程序,分别在读取输入后、调用unique后以及调用erase后打印vector
程序实现:

// sort and elimDups
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using std::cin;
using std::cout;
using std::ends;
using std::endl;
using std::string;
using std::vector;
using std::sort;
using std::unique;

vector<string> strToVec(const string line, const string separators);
void show(vector<string> const &words);
void elimDups(vector<string> words);
int main(void)
{
        const string Separators = " \t:;,\n\r\f\v";
        string str("the quick red fox jumps the slow red turtle");

        // string turn on vector<sting>
        vector<string> vec;
        vec = strToVec(str, Separators);

        // show vector<string>
        cout << "string to vector<sting>..." << endl;
        show(vec);

        // elimDups()
        cout << "\nelimDups()..." << endl;
        elimDups(vec);

        return 0;
}

vector<string> strToVec(const string line, const string separators)
{
        vector<string> vec;
        string word;
        std::string::size_type startPos = 0, endPos = 0;
        std::string::size_type wordLen = 0;

        while ((startPos = line.find_first_not_of(separators,
                endPos)) != std::string::npos) {
                endPos = line.find_first_of(separators, startPos);
                if (endPos == std::string::npos)
                        wordLen = line.size() - startPos;
                else
                        wordLen = endPos - startPos;
                word.assign(line.begin() + startPos,
                        line.begin() + startPos + wordLen);
                vec.push_back(word);
        }

        return vec;
}

void show(vector<string> const &words)
{
        for (const auto s : words)
                cout << s << " ";
        cout << endl;

        return;
}

void elimDups(vector<string> words)
{
        sort(words.begin(), words.end());
        show(words);

        auto end_unique = unique(words.begin(), words.end());
        show(words);

        words.erase(end_unique, words.end());
        show(words);

        return;
}

程序测试结果:

[lhf@localhost 10-9]$ ./elimDups
string to vector<sting>...
the quick red fox jumps the slow red turtle

elimDups()...
fox jumps quick red red slow the the turtle
fox jumps quick red slow the turtle the red
fox jumps quick red slow the turtle

hangman猜字游戏

C++ primer plus 16.3例题

实际上,书中的例题是有bug的。下面贴出正确的代码

// hangman.cpp -- some string methods
#include <iostream>
#include <string>
#include <cstdlib>
#include <ctime>
#include <cctype>
using std::string;

const int NUM = 26;
const string wordlist[NUM] = {
	"apiary", "beetle", "cereal", "danger", "ensign", "florid", "garage",
	"health", "insult", "jackal", "keeper", "loaner", "manage", "nonce",
	"onset", "plaid", "quilt", "remote", "stolid", "train", "useful",
	"valid", "whence", "xenon", "yearn", "zippy"
};

int main(void)
{
	using std::cout;
	using std::cin;
	using std::tolower;
	using std::endl;

	std::srand(std::time(0));
	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 may 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;
			}
			unsigned long loc = target.find(letter);// 这里一定要用unsigned long来声明变量
			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;
}

抽象基类(ABC)的应用

该带码依照 C++ primer plus 第5版 13.6.1应用。

头文件

抽象基类,Brass公有派生类和BrassPlus公有派生类

抽象基类简述

类AcctABC为抽象基类,所谓抽象基类不能生成实例,即不能生成对象。
该类有三个私有成员:分别是名字,银行账户,存款金额。
保护成员方法:显示名字,显示账户,以及显示格式重置函数
公有成员方法:构造函数,存款函数,纯虚取款函数,获取存款金额,纯虚账户信息显示函数,虚拟析构函数(必须设置为虚函数,试指针可以准确定析构对于的对象)

Brass派生类

公有成员方法:构造函数,虚拟取款函数(必须,基类定义为纯虚函数),虚拟账户显示函数(必须,基类定义为纯虚函数),虚拟析构函数

BrassPlus派生类

私用成员:最大贷款金额,贷款利率,还贷金额
公有成员方法: 构造函数,虚拟取款函数(必须,基类定义为纯虚函数),虚拟账户显示函数(必须,基类定义为纯虚函数),虚拟析构函数,以及设置最大贷款金额函数,设置贷款利率函数,设置还贷金额函数。

三个类的头文件

// acctabc.h -- bank account classes
#ifndef ACCTABC_H_
#define ACCTABC_H_

// Abstract Base Class
class AcctABC {
private:
	enum {MAX = 32};
	char fullName[MAX];
	long acctNum;
	double balance;
protected:
	const char * FullName(void) const {return fullName;}
	long AcctNum(void) const {return acctNum;}
	std::ios_base::fmtflags SetFormat(void) const;
public:
	AcctABC(const char * s = "Nullbody", long an = -1, double bal = 0.0);
	void Deposit(double amt);
	virtual void Withdraw(double amt) = 0; 	// pure virtual function
	double Balance(void) const {return balance;}
	virtual void ViewAcct(void) const = 0;	// pure virtual function
	virtual ~AcctABC(void) {}
};

// Brass Account Class
class Brass: public AcctABC {
public:
	Brass(const char * s = "NullBody", long an = -1, 
		double bal = 0.0): AcctABC(s, an, bal) {}
	virtual void Withdraw(double amt);
	virtual void ViewAcct(void) const;
	virtual ~Brass(void) {}
};

// Brass Plus Account Class
class BrassPlus: public AcctABC {
private:
	double maxLoan;
	double rate;
	double owesBank;
public:
	BrassPlus(const char * s = "Nullbody", long an = -1, 
		double bal = 0.0, double ml = 500, 
		double r = 0.1);
	BrassPlus(const AcctABC & ba, double ml = 500, double r = 0.1);
	virtual void ViewAcct(void) const;
	virtual void Withdraw(double amt);
	void ResetMax(double m) {maxLoan = m;}
	void ResetRate(double r) {rate = r;}
	void ResetOwes(void) {owesBank = 0;}
};

#endif//ACCTABC_H_

继续阅读

函数声明,原型与定义

函数声明

函数原型能告诉编译程序一个函数将接受什么样的参数,将返回什么样的返回值,这样编译程序就能检查对函数的调用是否正确,是否存在错误的类型转换。函数声明加上分号就是函数原型。函数原型通常放在主函数之前。

函数定义

即函数实现代码,参数传值(变量的值或变量的地址)

函数调用

主程序函数调用,编译器检查函数调用原型,与原型符合,则进入函数定义中执行代码。执行完毕后返回。

函数原型演示:

下面是等同的函数原型。

int sum(int a[], int n);
int sum(int *a, int n);
int sum(int [], int);
int sum(int *, int);

压栈和出栈的类方法演示

什么是堆栈

堆栈(英语:stack),也可直接称栈。台湾作堆叠,在计算机科学中,是一种特殊的串行形式的数据结构,它的特殊之处在于只能允许在链结串行或阵列的一端(称为堆叠顶端指标,英语:top)进行加入资料(英语:push)和输出资料(英语:pop)的运算。另外堆叠也可以用一维阵列或连结串行的形式来完成。堆叠的另外一个相对的操作方式称为伫列。

由于堆叠数据结构只允许在一端进行操作,因而按照后进先出(LIFO, Last In First Out)的原理运作。

堆叠数据结构使用两种基本操作:推入(push)和弹出(pop):

推入:将数据放入堆叠的顶端(阵列形式或串行形式),堆叠顶端top指标加一。
弹出:将顶端数据资料输出(回传),堆叠顶端资料减一。

类方法演示

程序分三个部分:头文件定义类(包括类数据和类方法原型);类实现部分(类方法定义);程序演示部分(演示压栈和出栈行为)

头文件stack.h

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

typedef unsigned long Item;

class Stack {
private:
        enum {MAX = 10};        // constant specific to class
        Item items[MAX];        // holds stack items
        int top;                // index for top stack item
public:
        Stack(void);
        bool isempty(void) const;
        bool isfull(void) 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
};

#endif//STACK_H_

类方法定义

// stack.cpp -- Stack member functions
#include "stack.h"

Stack::Stack(void)      // create an empty stack
{
        top = 0;

        return;
}

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

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

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

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

继续阅读

C++ primer plus 第7章 7.16程序修复版本

7.16程序修复版本

第五版原书的代码是无法显示如下图的所示的。

|                                                               |
|                                                               |
|                               |                               |
|               |               |               |               |
|       |       |       |       |       |       |       |       |
|   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

代码使用了递归。
经过测试,修复代码如下:

#include <iostream>
const int Len = 66;
const int Divs = 6;

void subdivide(char arr[], int low, int high, int level);

int main(void)
{
	char ruler[Len];

	int i;
	for (i = 1; i < Len - 2; i++)
		ruler[i] = ' ';
	ruler[Len - 1] = '\n';
	ruler[Len] = '\0';
	
	int max = Len - 2;
	int min = 0;

	ruler[min] = ruler[max] = '|';
	std::cout << ruler;

	for (i = 0; i <= Divs; i++) {
		subdivide(ruler, min, max, i);
		std::cout << ruler;
		for (int j = 1; j < Len - 2; j++)
			ruler[j] = ' ';			// reset to blank ruler
	}

	return 0;
}

void subdivide(char arr[], int low, int high, int level)
{
	if (level == 0)
		return;
	int mid = (high + low) / 2;
	arr[mid] = '|';

	subdivide(arr, low, mid, level - 1);
	subdivide(arr, mid, high, level - 1);

	return;
}

自己编写的string类

基本上是照着视频写的, 但是使用了自己的算法

功能如下:
/****************************************************************************
*
* 1. 可对字符串初始化
* mystring s1 = “hello world”;
* 2. 可计算字符串的长度
* cout < < s1.get_len() << endl; * 3. 可对字符串进行赋值运算 * mystring s2; * s2 = s1; * 4. 可以重载运算符"<<"输出字符串, 并且可以级联输出 * cout << s1 << s2 <>”输入字符串, 并且可以级联输入
* cin >> s1 >> s2;
* 6. 可将char形字符串直接赋值给mystring形字符串
* char ch[] = “not at all”;
* s1 = ch;
* 7. 可以像构造对象定义字符串
* mystring s3; //定义一个空字符串
* mystring s4(“mother”); //定义一个非空字符串
* 8. 可以通过下标运算符操作字符串
* cout < < s3[999] << endl; //越界安全保护 * 9. 可以比较两个mystring类字符串, 如:s1 == s2, s1 < s2, s1 > s2
* cout < < s3 < s4 ? s3 : s4 << endl; * 10.可以将两个字符串相加 * s3 = s1 + s2; * cout << s3 << endl; * 11.可执行+=操作 * s1+=s2; * cout << s1 << endl; * 12.可以根据字符串的大小自动保存字符串数组的大小 * *******************************************************************************/

继续阅读

兔子问题

兔子问题来源:

根据高德纳(Donald Ervin Knuth)的《计算机程序设计艺术》(The Art of Computer Programming),1150年印度数学家Gopala和金月在研究箱子包装物件长阔刚好为1和2的可行方法数目时,首先描述这个数列。 在西方,最先研究这个数列的人是比萨的列奥那多(意大利人斐波那契 Leonardo Fibonacci),他描述兔子生长的数目时用上了这数列。

  • 第一个月初有一对刚诞生的兔子
  • 第二个月之后(第三个月初)它们可以生育
  • 每月每对可生育的兔子会诞生下一对新兔子
  • 兔子永不死去

假设在n月有可生育的兔子总共a对,n+1月就总共有b对。在n+2月必定总共有a+b对: 因为在n+2月的时候,前一月(n+1月)的b对兔子可以存留至第n+2月(在当月属于新诞生的兔子尚不能生育)。而新生育出的兔子对数等于所有在n月就已存在的a对

求第N个月兔子对数问题

就是一个斐波那契数列中的一个数
费波那契数列由0和1开始,之后的费波那契系数就由之前的两数相加。首几个费波那契系数是:
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233……

使用递归方法实现(C++)

 

/*************************************************

 *	Name:  			求第N个月兔子对数
 *      Date:   		2014-11-4 23:34:45
 *      Author: 		lnesuper
 *      Version:    	V0.1
 *      Discription:    使用递归解决兔子问题
 *      In math:        F(0) = 0
 *                      F(1) = 1
 *                      F(n) = F(n-1) + F(n-2); (n>2)

**************************************************/

#include <iostream>
using namespace std;

int f(int n);

int main(void) {
	int n;
    cout << "请输入所求第n个月的数值: ";
    cin >> n;
    
	cout << "第" << n << "个月的兔子对数: " <<  f(n) << endl;
	
	return 0;
}

/*
	第一个月:  一对兔子
	第二个月:  二对兔子
  	第 N 个月: 第 N-1 个月的兔子数 + 第 N-2 个月兔子对数
*/
int f(int n) {
	if (1 == n)
		return 1;
	else if (2 == n)
		return 2;
	else
		return f(n - 1) + f(n - 2);
}

/*
Result:

请输入所求第n个月的数值: 40
第40个月的兔子对数: 165580141

--------------------------------
Process exited after 5.223 seconds with return value 0
请按任意键继续. . .

*/

继续阅读