C++笔记(9) 模板,向量和栈

函数模板,类模板

模板功能提供了在函数和类中将类型作为参数的能力,可以设计具有通用类型的函数和类,而编译器在编译时会将通用类型确定为具体类型。

如max()函数:需要比较两个int,double, char, string,需要写四个重载函数

C++允许定义具有通用类型的函数模板

#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <time.h>
#include <string>
 
using namespace std;

// 定义函数模板
template<typename T> 
T maxValue(T a, T b)
{
	if(a>=b)
	   return a;
    else
       return b;
} 

int main(int argc, char *argv[])
{
    cout << "Maxium between 1 and 3 is " << maxValue(1,3) << endl;
    cout << "Maxium between 1.6 and 0.3 is " << maxValue(1.6,0.3) << endl;
    cout << "Maxium between a and c is " << maxValue('a','c') << endl;
    cout << "Maxium between \"NFC\" and \"NBA\" is " << maxValue(string("NFC"), string("NBA")) << endl;
	return 0;
}


关键字:template, 后面是参数列表,参数列表必须有关键字typename

在进行string类型的比较时,如果使用maxValue("NFC", "NBA")的话,参数为C字符串,传递给函数的参数是两个字符串的地址,所以比较的是地址。

例子:一个通用的排序函数:
 

#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <time.h>
#include <string>
 
using namespace std;

// 定义函数模板 一个通用的排序函数 
template<typename T> 
void sortedArray(T array[], int SIZE)
{
    // 选择排序
	for(int i=0; i<SIZE-1; i++)
	{
		T current_min = array[i];
		int current_min_index = i;
		for(int j=i+1; j<SIZE; j++)
		{
		   if(array[j]<current_min)
		   {
   			 current_min = array[j];
   			 current_min_index = j;
   	    	}
		   	
		}
		if(current_min_index!=i)
		{
			T tmp = array[i];
			array[i] = array[current_min_index];
			array[current_min_index] = tmp;
		}
	}	
}

template<typename T>
void printArray(T array[], int SIZE)
{
	for(int i=0; i<SIZE; i++)
	{
		cout << setw(5) << array[i];
	}
	cout << endl;
}

int main(int argc, char *argv[])
{
    int a[] = {3, 5, 2, 6, 9, 4};
	sortedArray(a, 6);
	printArray(a, 6); 
	
	double b[] = {6.3, 4.1, 4.2, 7.9, 0.6, 8.8};
	sortedArray(b, 6);
	printArray(b, 6);
	
	string c[] = {"lanzhou", "student", "wangzi"};
	sortedArray(c, 3);
	printArray(c, 3);  
	return 0;
}


模板类:

除了用类型参数定义模板函数,也可以用类型参数定义模板类,类型参数可以用于类中任何地方

将StackOfInteger修改为通用 的Stack类:  // 对于模板类,将类的定义和实现放在一起更为安全,有的编译器不支持将类的定义和实现分离!

声明模板类对象时,必须指定函数类型

模板类与普通类区别总结:

1. 定义和实现放在一起  h文件

2.类的定义,前面必须有模板前缀   template<typename T>

3.类的实现中每个构造函数和成员函数之前都要有模板前缀 template<typename T>, 类的名称为ClassName<T>::methods

4.声明类的对象时,必须指定参数类型 Class<int/string> object

修改intStack为模板类:

code:

stack.h

// stack 类的定义
#ifndef STACK_H
#define STACK_H
using namespace std;

template<typename T>
class Stack
{
	private: 
		int size;
		T element[100];
	public:
		Stack();     // 构造函数
		bool isEmpty() const;    // 只读函数
		T peek() const;   //返回栈底的元素
		void push(T value);   // 入栈
		T pop();   // 出栈
		int getSize() const; 
};
// 类的实现 
// 类的构造函数和成员函数的实现与模板函数一样,前面要模板前缀,同时类名为Stack<T> 
template<typename T>
Stack<T>::Stack()
{
	size = 0;
}

template<typename T>
bool Stack<T>::isEmpty() const
{
	return size==0;
}

template<typename T>
T Stack<T>::peek() const
{
	return element[size-1];   // 只读函数不能改变数据域 
}

template<typename T> 
void Stack<T>::push(T value)
{
	element[size++] = value;
}

template<typename T>
T Stack<T>::pop()
{
    if(isEmpty())
        cout << "The stack is stack" << endl;
    else
        return element[--size];
}

template<typename T>
int Stack<T>::getSize() const
{
	return size;
}

#endif 
 

main.cpp

#include <iostream>
#include <string>
#include <iomanip>
#include <sstream>   // 将数字转化为字符串 
#include <algorithm> 
#include "E:\back_up\code\c_plus_code\chapter8\external_file\course.h"
#include "E:\back_up\code\c_plus_code\chapter8\external_file\stack.h"

using namespace std;

int main(int argc, char *argv[])
{
   Stack<int> int_stack;  //声明模板类对象。必须指定类型
   for(int i=0; i< 10; i++)
   {
   	   int_stack.push(i);
   } 
   cout << "Peek int_stack " << int_stack.peek() << endl;
   while(!int_stack.isEmpty())
   {
   	  cout << int_stack.pop() << " ";
   }
   cout << endl;
   
   Stack<string> string_stack;
   string_stack.push("Nanhudadao");
   string_stack.push("Helloworld");
   string_stack.push("stongarm");
   
   while(!string_stack.isEmpty())
   {
   	cout << string_stack.pop() << " ";
   }
   cout << endl;
   
   return 0;
}


可以定义一个输出栈中元素的函数模板,函数参数是栈的引用:

#include <iostream>
#include <string>
#include <iomanip>
#include <sstream>   // 将数字转化为字符串 
#include <algorithm> 
#include "E:\back_up\code\c_plus_code\chapter8\external_file\course.h"
#include "E:\back_up\code\c_plus_code\chapter8\external_file\stack.h"

using namespace std;

// 定义一个输出栈中元素的函数
template<typename T>
void printStack(Stack<T>& stack)   // 参数
{
	while(!stack.isEmpty())
	{
		cout << stack.pop() << " ";
	}
	cout << endl;
}
 
int main(int argc, char *argv[])
{
   Stack<int> int_stack;  //声明模板类对象。必须指定类型
   for(int i=0; i< 10; i++)
   {
   	   int_stack.push(i);
   } 
   cout << "Peek int_stack " << int_stack.peek() << endl;
   printStack(int_stack);
   
   Stack<string> string_stack;
   string_stack.push("Nanhudadao");
   string_stack.push("Helloworld");
   string_stack.push("stongarm");
   printStack(string_stack);
   
   return 0;
}


可以为模板类中的类型参数指定一个默认的参数类型作为缺省类型,还可以使用非类型参数。

template<typename T=int, int capacity>  // 默认的参数类型是int
class Stack
{
	private:
	T element[capacity];
	int size;
	public:
	....
}

void main()
{
	Stack<int, 500> int_stack;   // 500哥元素的栈 
}

Stack<> stack;

Stack类的改进:

前面的Stack中数据存储在一个固定大小的数组中,不合理。

改进方法:预先分配一个较小的空间,如果需要,再动态增加数组的大小

思路: 增加一个新的属性capacity,表示保存元素的数组的当前大小,构造函数中先创建一个小的数组,当数组已满时,就增加数组的大小来保存新的元素:

如何增加数组的大小呢?

创建一个新的更大的数组,和将原数组中的元素复制过来,将旧的数组删掉即可。

实现代码

stack_improve.h

#ifndef STACK_IMPRPVE_H
#define STACK_IMPROVE_H
#include <iostream>
using namespace std;

template<typename T=int>
class Stack_improve
{
	private:
		T* elements;
		int size;
		int capacity;
		void ensureCapacity();
	public:
		Stack_improve();   // 构造函数
		Stack_improve(const Stack_improve&);   // 拷贝构造函数
		~Stack_improve();    // 析构函数
		bool isEmpty() const;
		T peek() const;
		void push(T value);
		T pop();
		int getSize() const; 
};

template<typename T>
Stack_improve<T>::Stack_improve()
{
	size = 0;        // 元素个数 
	capacity = 10;   // 栈的初始容量的大小为10 
	elements = new T[capacity]; 
}

template<typename T>
Stack_improve<T>::Stack_improve(const Stack_improve& stack)  // 拷贝构造函数,实现深拷贝 
{
   elements = new T[stack.capacity];   // 分配独立的存储空间
   size = stack.size;
   capacity = stack.capacity;
   for(int i=0; i<size; i++)
   {
   	  elements[i] = stack.elements[i];
   }   	
   
}

template<typename T>
Stack_improve<T>::~Stack_improve()
{
	delete []elements;
}

template<typename T>
bool Stack_improve<T>::isEmpty() const
{
	return size==0;
}

template<typename T>
T Stack_improve<T>::peek() const
{
	return elements[size-1];
}

template<typename T>
void Stack_improve<T>::push(T value)
{
	ensureCapacity();
	elements[size++] = value;
}

template<typename T>
T Stack_improve<T>::pop()
{
	return elements[--size];
}

template<typename T>
int Stack_improve<T>::getSize() const
{
	return size;
}

template<typename T>
void Stack_improve<T>::ensureCapacity()
{
	if(size>=capacity)
	{
		T* old  = elements;
		capacity = 2 * size;  // 改变capacity的大小
		elements = new T[capacity];
		// 将旧的数组的值复制过来
		for(int i=0; i<size; i++)
		{
		   elements[i] = old[i];	
		} 
		delete [] old;
	}
}
  
#endif 

main.cpp

#include <iostream>
#include <string>
#include <iomanip>
#include <sstream>   // 将数字转化为字符串 
#include <algorithm> 
#include "E:\back_up\code\c_plus_code\chapter8\external_file\stack_improve.h"

using namespace std;

// 定义一个输出栈中元素的函数
template<typename T>
void printStack(Stack_improve<T>& stack)
{
	while(!stack.isEmpty())
	{
		cout << stack.pop() << " ";
	}
	cout << endl;
}
 
int main(int argc, char *argv[])
{
   Stack_improve<int> int_stack;  //声明模板类对象。必须指定类型
   for(int i=0; i< 10; i++)
   {
   	   int_stack.push(i);
   } 
   cout << "Peek int_stack " << int_stack.peek() << endl;
   printStack(int_stack);
   
   Stack_improve<string> string_stack;
   string_stack.push("Nanhudadao");
   string_stack.push("Helloworld");
   string_stack.push("stongarm");
   printStack(string_stack);
   
   return 0;
}


c++向量类:

C++提供了通用类Vector.用于存储列表对象    #include<vector>

vector类中的常用函数:

vector<type> Vname()
vector<type> Vname(size)

push_back(element)    // 追加append()

pop_back()                 // 删除最后后一个元素

size()   

at(index)

empty()

clear()

swap()   // 交换两个向量中的内容

#include <iostream>
#include <vector>
#include <string>
using namespace std;

 
int main(int argc, char *argv[])
{
	// 使用atoi将字符串转化为int
    vector<int> intvect;
	
	for(int i=0; i<10; i++)
	{
		intvect.push_back(i*i);
	}
	cout << "Numbers in the vector: " << endl;
	
	for(int i=0; i<intvect.size(); i++)
	{
		cout << intvect[i] << " ";
	}
	cout << endl;
	
	intvect.pop_back();   // 不返回值
	 
	for(int i=0; i<intvect.size(); i++)
	{
		cout << intvect[i] << " ";
	}
	cout << endl;
	
	vector<string> stringvect;
	stringvect.push_back("hello");
	stringvect.push_back("Nananan");
	stringvect.push_back("Crypto");
    
    cout << stringvect.empty() << endl;
	return 0;
}

随机选取四种扑克牌:(将数组替换成向量)

#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <ctime>     // 随机数  ctime
#include <string>
#include <vector>
 
using namespace std;
const int number_of_cards = 52;
string suits[4] = {"Spades", "Hearts", "Diamond", "Clubs"};
string ranks[] = {"Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", 
                "Jack", "Queen", "King"};
 
int main(int argc, char *argv[])
{
    vector<int> deck(number_of_cards);
	// initialize
	for(int i=0; i<number_of_cards; i++)
	{
		deck[i] = i;
	}   
	srand(time(0));  // shuffle
	
	for(int i=0; i<number_of_cards; i++)
	{
		int index = rand() % number_of_cards;
		int temp = deck[i];
		deck[i] = deck[index];
		deck[index] = temp;
	}
	
	// select four cards
	for(int i=0; i<4; i++)
	{
		cout << ranks[deck[i]%13] << " of " << suits[deck[i]/13] << endl;
	}
	return 0;
}


二维数组也可以用向量表示:
 

#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <ctime>
#include <string>
#include <vector>
 
using namespace std;

void printMatrix(vector<vector<int > >& matrix)
{
   for(int i=0; i<matrix.size(); i++)
   {
   	 for(int j=0; j<matrix[i].size(); j++)
   	 {
 	   	 cout << matrix[i][j] << " ";
     }
     cout << endl;
   }	
} 

int main(int argc, char *argv[])
{ 
    vector<vector<int> > matrix(4);   // vector<vector<int> >必须有空格 
    for(int i=0; i<matrix.size(); i++)
    {
    	matrix[i] = vector<int>(3);    // 二维向量初始化 
    }
    
    for(int i=0; i<matrix.size(); i++)
    {
    	for(int j=0; j<matrix[i].size(); j++)
    	{
	    	matrix[i][j] = i+j;
	    }
    }
    printMatrix(matrix);
	return 0;
}


用栈实现表达式计算:
如: 51+(54*93+2))=?

#include <iostream>
#include <string>
#include <iomanip>
#include <sstream>   // 将数字转化为字符串 
#include <algorithm> 
#include "E:\back_up\code\c_plus_code\chapter8\external_file\course.h"
#include "E:\back_up\code\c_plus_code\chapter8\external_file\stack.h"
#include "E:\back_up\code\c_plus_code\chapter8\external_file\stack_improve.h"
#include <vector>
#include <cctype>   // include isdigit()

using namespace std;

// define function split() for split expression into number, operarot, return a vector
vector<string> split(const string& expression);
// calculate the expression
int evaluateExpression(const string& expression);     // return the result 
// process the stack
void processAnOperator(Stack_improve<int> operandStack, Stack_improve<char> operator_stack);

// 定义一个输出栈中元素的函数
template<typename T>
void printStack(Stack_improve<T>& stack)
{
	while(!stack.isEmpty())
	{
		cout << stack.pop() << " ";
	}
	cout << endl;
}
 
int main(int argc, char *argv[])
{
   string expre;
   cout << "Enter the expression: " << endl;
   getline(cin, expre);
   cout << "Expression " << expre << " = " << evaluateExpression(expre) << endl;
   return 0;
   
}


// define function split() for split expression into number, operarot
vector<string> split(const string& expression)
{
	vector<string> v;
	string numberString;
	for(unsigned i=0; i<expression.length(); i++)
	{
	    if(isdigit(expression[i]))   // 开始的时候碰到数字 包含是多位数的可能 
		   numberString.append(1, expression[i]);   // 将数字追加在numberString后 
	    else
		{
			if(numberString.size()>0)
			{
				v.push_back(numberString);   // 考虑是多位数 
				numberString.erase();   // 清空erase 
			}
			if(!isspace(expression[i]))   // 不是数字,则一定是运算符或者括号
			{ 
			    string s;
				s.append(1, expression[i]);
				v.push_back(s); 
	     	} 
		}
	}
	
	//结束的时候碰到数字
	if(numberString.size()>0)
	   v.push_back(numberString);
    return v;
}



// define evualation function
int evaluateExpression(const string& expression)
{
	Stack_improve<int> operand_stack;  // 存储操作数 
	Stack_improve<char> operator_stack;  // 存储运算符
	vector<string> token = split(expression);
	// phase1 scan the token  遍历分割后的表达式
	for(int i=0; i<token.size(); i++)
	{
		if(token[i][0]=='+' || token[i][0]=='-')  // +-运算符
		{
			while(!operator_stack.isEmpty()&&(operator_stack.peek()=='+' || operator_stack.peek()=='-' || operator_stack.peek()=='*' || operator_stack.peek()=='/'))
			{
                processAnOperator(operand_stack, operator_stack);				
   			} 
		operator_stack.push(token[i][0]);
	    }  
	    else if(token[i][0]=='*' || token[i][0]=='/')
	    {
    	    // process * /
			while(!operator_stack.isEmpty() && (operator_stack.peek()=='*' || operator_stack.peek()=='/'))	
  	        {
        	    processAnOperator(operand_stack, operator_stack);  	
	        }
	        operand_stack.push(token[i][0]);
        }
        else if(token[i][0]=='(')
        {
        	operator_stack.push(token[i][0]);
        }
        else if(token[i][0]==')')
        {
        	while(operator_stack.peek()!='(')
        	{
	        	processAnOperator(operand_stack, operator_stack); 
	        }
	        operator_stack.pop();    // pop '(' out of the stack 
        }
        
	    else
	    {
    	   operand_stack.push(atoi(token[i].c_str()));	
    	}
	}
	while(!operator_stack.isEmpty())
	{
		processAnOperator(operand_stack, operator_stack); 
	}
	return operand_stack.pop();
} 


// process operator: take a operator from the operatorStack and 
// apply it on the operands in the operands
void processAnOperator(Stack_improve<int> operandStack, Stack_improve<char> operatorStack)
{
	char op = operatorStack.pop();
	int op1 = operandStack.pop();
	int op2 = operandStack.pop();
	if(op=='+')
        operandStack.push(op1+op2);
    else if(op=='-')
        operandStack.push(op1-op2);
    else if(op=='*')
        operandStack.push(op1*op2);
    else
        operandStack.push(op1/op2);
}

 

 

 

 

 

 

 

posted @ 2018-11-02 10:58  Alpha205  阅读(107)  评论(0编辑  收藏  举报