码迷,mamicode.com
首页 > 编程语言 > 详细

算法之美_源代码发布(6)

时间:2016-02-15 16:35:22      阅读:224      评论:0      收藏:0      [点我收藏+]

标签:

本文辑录了《算法之美——隐匿在数据结构背后的语言》(电子工业出版社2016年出版)一书第7章之代码(P184~P230)。全文目录、“45个算法”目录“22个经典问题目录”,以及有奖捉虫活动详情请见如下链接:http://blog.csdn.net/baimafujinji/article/details/50484348

附录中的经典笔试、面试问题参考答案请见:

http://blog.csdn.net/baimafujinji/article/details/50484683

技术分享


In general, 我不太喜欢翻开一本书(技术书),里面密密麻麻的全部都是代码。所以我也希望能够在我的书中留下更多空间去讨论原理和思路。当然,代码也很重要,所有的一切原理最终都要落实到代码上。为此我习惯于在博客中上传代码,而非是把他们全部罗列到书中去挤占篇幅。最后,我仍然建议那些有心学好算法和数据结构的同学彻底击破书中涉及到的算法原理,做到知其然更知其所以然,只有这样你才算是真正学到了东西,也只有这样,你在遇到新的编程问题时才不会束手无策。

如果你是该书的读者,强烈建议你加入算法学习群(495573865),内有更多资源等你,而你在读书中遇到的疑问也将得到我第一时间的解答。更多关注本博客,我将陆续发布该书全部源代码至本博客。


P187  树的抽象数据结构


template<class T> class Tree;
template<class T>
class TreeNode
{

friend class Tree<T>;

private:
	T m_value;
	TreeNode<T> * leftChild;    	//第一个子结点, 即最左子结点
	TreeNode<T> * rightSibling;  	//该结点的右兄弟结点
	
public:

	TreeNode(const T&);	//构造函数
	~TreeNode();		//析构函数
	
	bool isLeaf();		//是否是叶子结点
	
	T getValue();
	TreeNode<T>* getLeftChild();
	TreeNode<T>* getRightSibling();
	
	void setValue(T & value);	//设置该结点值

	//设置该结点的最左子结点
	void setLeftChild(TreeNode<T>* pLeftChild);
	//设置该结点的右兄弟结点
	void setRightSibling(TreeNode<T>* pRightSibling); 
	
};


template<class T>class Tree
{
	TreeNode<T>* root, * parent;

	int getParent(TreeNode<T>* root,TreeNode<T>* current);

public:

	Tree();
	Tree(TreeNode<T>* rt);	//构造函数,生成树的结构
	~Tree();		//析构函数

	TreeNode<T> * getRoot();	//返回树的根结点,若为空树,则返回Null

	//返回结点current的父结点,如果结点n是根结点,则返回Null
	TreeNode<T> * Parent(TreeNode<T> * current);
	
	//返回结点t的第一个子结点,若无则返回Null
	TreeNode<T> * getFirstChild(TreeNode<T> * t);

	//返回结点t的下一个兄弟结点,若无则返回Null
	TreeNode<T> * getNextSibling(TreeNode<T> * t);

	//在结点t下插入一个子结点n
	void insertChild(TreeNode<T> * t, TreeNode<T> * n); 

	void deleteSubTree(TreeNode<T> * t);	//删除以t为根结点的子树
	bool isEmpty();	//判断是否为空树
};

P193  二叉树类的实现


BinaryTreeNode.h


#ifndef BINARYTREENODE_H
#define BINARYTREENODE_H

#include "iostream"

using namespace std;

template <class Type>
class BinaryTreeNode 
{
	Type m_data;      // 存储该节点的数据
	BinaryTreeNode<Type> *m_leftChild; // 存储该节点的左孩子指针
	BinaryTreeNode<Type> *m_rightChild;// 存储该节点的右孩子指针

public:
	BinaryTreeNode(){m_leftChild = m_rightChild = NULL;};
	BinaryTreeNode(const Type &data,
						BinaryTreeNode *leftChild = NULL,
						BinaryTreeNode *rightChild = NULL)
	{
		m_data = data;
		m_leftChild = leftChild;
		m_rightChild = rightChild;
	};

	Type & GetData(){return m_data;};		//返回该节点的数据

	// 返回该节点的左孩子指针
	BinaryTreeNode<Type>* GetLeftChild(){return m_leftChild;};

	// 返回该节点的右孩子指针
	BinaryTreeNode<Type>* GetRightChild(){return m_rightChild;};

	// 设置该节点的数据
	void SetData(const Type & data){m_data = data;};

	// 设置该节点的左孩子指针域
	void SetLeftChild(BinaryTreeNode<Type> *leftChild){m_leftChild = leftChild;};

	// 设置该节点的右孩子指针域
	void SetRightChild(BinaryTreeNode<Type> *rightChild){m_rightChild = rightChild;};
};

#endif


BinaryTree.h


#include"BinaryTreeNode.h"
#include<queue>

using namespace std;

template<class T>
class BinaryTree 
{
		BinaryTreeNode<T> *m_root;

public:

		BinaryTree(){m_root = NULL;};
		BinaryTree(T data){m_root = new BinaryTreeNode<T>(data);};
		virtual ~BinaryTree();
	
		bool IsEmpty() const{return m_root == NULL ? true:false;};// 判断树是否是空树

		//判断一个节点是否是左孩子
		bool IsLeftChild(BinaryTreeNode<T> *p)
			{return p == GetParent(p)->GetLeftChild() ? true:false;};
		//判断一个节点是否是右孩子
		bool IsRightChild(BinaryTreeNode<T> *p)
			{return p == GetParent(p)->GetRightChild() ? true:false;};
    
		//取得整棵树的树根
		BinaryTreeNode<T>* GetRoot(){return m_root;};
		//取得一个节点的父亲节点指针
		BinaryTreeNode<T>* GetParent(BinaryTreeNode<T> *p){return Parent(m_root, p);};
		//取得一个节点的左子树根指针
		BinaryTreeNode<T>* LeftChild(BinaryTreeNode<T> *root) const
		{return root == NULL ? NULL:root->GetLeftChild();};
		//取得一个节点的右子树根指针
		BinaryTreeNode<T>* RightChild(BinaryTreeNode<T> *root) const
		{return root == NULL ? NULL:root->GetRightChild();};

		//取得一个节点的左兄弟指针
		BinaryTreeNode<T>* LeftSibling(BinaryTreeNode<T> *leftChild);
		//取得一个节点的右兄弟指针
		BinaryTreeNode<T>* RightSibling(BinaryTreeNode<T> *rightChild);

		//返回一个节点的数据
		T Retrieve(BinaryTreeNode<T> *p) const {return p->GetData();};
    
		//设置一个节点的数据
		void Assign(BinaryTreeNode<T> *p, const T &d) const {p->SetData(d);};
		//插入右孩子到当前节点下
		void InsertRightChild(BinaryTreeNode<T> *p, const T &d) const;
		//插入左孩子到当前节点下
		void InsertLeftChild(BinaryTreeNode<T> *p, const T &d) const; 

		//删除当前节点的右孩子
		void DeleteRightChild(BinaryTreeNode<T> *p){Destroy(p->GetRightChild());};
		//删除当前节点的左孩子
		void DeleteLeftChild(BinaryTreeNode<T> *p){Destroy(p->GetLeftChild());};
       
		virtual void PreOrderTraverse(BinaryTreeNode<T> *root) const;//先序遍历整棵树
		virtual void InOrderTraverse(BinaryTreeNode<T> *root) const;//中序遍历整棵树
		virtual void PostOrderTraverse(BinaryTreeNode<T> *root) const; //后序遍历整棵树
		virtual void LevelOrderTraverse(BinaryTreeNode<T> *root) const;//按层遍历整棵树

protected:

		BinaryTreeNode<T>* Parent(BinaryTreeNode<T> *root, BinaryTreeNode<T> *p);
		void Destroy(BinaryTreeNode<T> *p);
};

template<class T> 
BinaryTree<T>::~BinaryTree(void)
{
		Destroy(m_root);
		m_root = NULL;
}

template<class T>
BinaryTreeNode<T>* BinaryTree<T>::RightSibling(BinaryTreeNode<T> *p)
{
    BinaryTreeNode<T> *q;
    q = Parent(m_root, p);
    if ((NULL == q) || (p == q->GetRightChild()))
        return NULL;
    else
        return q->GetRightChild();
}

template<class T>
BinaryTreeNode<T>* BinaryTree<T>::LeftSibling(BinaryTreeNode<T> *p)
{
    BinaryTreeNode<T> *q;
    q = Parent(m_root, p);
    if ((NULL == q) || (p == q->GetLeftChild()))
        return NULL;
    else
        return q->GetLeftChild();
}

template<class T>
void BinaryTree<T>::InsertLeftChild(BinaryTreeNode<T> *p, const T &d) const
{
		BinaryTreeNode<T> *q = new BinaryTreeNode<T>(d);
		q->SetLeftChild(p->GetLeftChild());
		p->SetLeftChild(q);
}

template<class T>
void BinaryTree<T>::InsertRightChild(BinaryTreeNode<T> *p, const T &d) const
{
		BinaryTreeNode<T> *q = new BinaryTreeNode<T>(d);
		q->SetRightChild(p->GetRightChild());
		p->SetRightChild(q);
}

template<class T>
void BinaryTree<T>::Destroy(BinaryTreeNode<T> *p)
{
    if (NULL != p)
    {
        Destroy(p->GetLeftChild());
        Destroy(p->GetRightChild());
        delete p;
    }
}

template<class T> BinaryTreeNode<T>* 
BinaryTree<T>::Parent(BinaryTreeNode<T> *root, BinaryTreeNode<T> *p)
{
		BinaryTreeNode<T> *q;
		if (NULL == root)
			return NULL;

		if ((p == root->GetLeftChild()) || (p == root->GetRightChild()))
			return root;

		if (NULL != (q = Parent(root->GetLeftChild(), p)))
			return q;
		else
			return Parent(root->GetRightChild(), p);
}

template<class T>
void BinaryTree<T>::LevelOrderTraverse(BinaryTreeNode<T> *root) const
{
		queue<BinaryTreeNode<T> *> q;
		if (NULL != root)
			q.push(root);

		while (!q.empty())
		{
			root = q.front(), q.pop();
			cout << root->GetData();
			if (root->GetLeftChild())
				q.push(root->GetLeftChild());
			if (root->GetRightChild())
				q.push(root->GetRightChild());
		}
}


P195  二叉树的测试代码


main.cpp


#include"BinaryTreeNode.h"
#include"BinaryTree.h"
#include"iostream"

using namespace std;

int main()
{

	BinaryTree<char> myBinTree(‘a‘);

	myBinTree.InsertLeftChild(myBinTree.GetRoot(), ‘D‘);
	myBinTree.InsertRightChild(myBinTree.GetRoot(), ‘G‘);

	myBinTree.InsertLeftChild(myBinTree.GetRoot(), ‘B‘);
	myBinTree.InsertRightChild(myBinTree.GetRoot()->GetLeftChild(), ‘E‘);

	myBinTree.InsertRightChild(myBinTree.GetRoot(), ‘C‘);
	myBinTree.InsertLeftChild(myBinTree.GetRoot()->GetRightChild(), ‘F‘);


	cout << "该二叉树是否为空? : " << myBinTree.IsEmpty() << endl;
	cout << "该二叉树的根结点中储存的数据是: " 
		<< myBinTree.Retrieve(myBinTree.GetRoot());
	cout << endl << "将二叉树的根结点中的数据赋值为 A!";
	myBinTree.Assign(myBinTree.GetRoot(), ‘A‘);
	cout << "当前二叉树的根结点中储存的数据是: "
		<< myBinTree.Retrieve(myBinTree.GetRoot()) << endl;

	cout << "层次遍历结果如下: " << endl;
	myBinTree.LevelOrderTraverse(myBinTree.GetRoot());
 
	cout << endl;
	return 0;
}


P198-1  递归实现的PreOrderTraverse()函数


template<class T>
void BinaryTree<T>::PreOrderTraverse(BinaryTreeNode<T> *root) const
{

    if (NULL != root)
    {
        cout << root->GetData();

        PreOrderTraverse(root->GetLeftChild());
        PreOrderTraverse(root->GetRightChild());
     }
}



P198-2  基于栈(非递归)实现的PreOrderTraverse()函数


template<class T>
void BinaryTree<T>::PreOrderTraverse(BinaryTreeNode<T> *root)   const
{
	stack<BinaryTreeNode<T>*> s;
	BinaryTreeNode<T> *p=root;
	while(!s.empty()||p!=NULL)
	{
		while(p)
		{
			s.push(p);
			cout<<p->GetData();
			p=p->GetLeftChild();
		}
			p=s.top();
			s.pop();
			p=p->GetRightChild();
	}
}


P199-1  递归实现的InOrderTraverse()函数


template<class T>
void BinaryTree<T>::InOrderTraverse(BinaryTreeNode<T> *root) const
{
    if (NULL != root)
    {
        InOrderTraverse(root->GetLeftChild());
        cout << root->GetData();
        InOrderTraverse(root->GetRightChild());
    }
}


P199-2 基于栈(非递归)实现的InOrderTraverse()函数


template<class T>
void BinaryTree<T>::InOrderTraverse(BinaryTreeNode<T> *root) const
{
	stack<BinaryTreeNode<T>*> s;
	BinaryTreeNode<T> *p=root;
	while(!s.empty()||p!=NULL)
	{
		while(p)
		{
			s.push(p);
			p=p->GetLeftChild();
		}
		
		p=s.top();
		s.pop();
		cout<<p->GetData();
		p=p->GetRightChild();
	}
}

P200  递归实现的PostOrderTraverse()函数


template<class T>
void BinaryTree<T>::PostOrderTraverse(BinaryTreeNode<T> *root) const
{
    if (NULL != root)
    {
        PostOrderTraverse(root->GetLeftChild());
        PostOrderTraverse(root->GetRightChild());

        cout << root->GetData();
    }
}

P206  树的节点类中部分主要成员函数的实现


template<class T>
TreeNode<T>::TreeNode(const T& value)
{
	m_value=value;
	leftChild=rightSibling=NULL;
}

template<class T>
bool TreeNode<T>::isLeaf()
{
	if(NULL==leftChild)
		return true;
	else return false;
}

template<class T>
T TreeNode<T>::getValue()
{
	return m_value;
}

template<class T>
void TreeNode<T>::setValue(T & value)
{
	m_value = value;
}

template<class T>
TreeNode<T>* TreeNode<T>::getLeftChild()
{
	return leftChild;
}

template<class T>
TreeNode<T>* TreeNode<T>::getRightSibling()
{
	return rightSibling;
}

template<class T>
void TreeNode<T>::setLeftChild(TreeNode<T>* pLeftChild)
{
	leftChild = pLeftChild;
}

template<class T>
void TreeNode<T>::setRightSibling(TreeNode<T>* pRightSibling)
{
	rightSibling = pRightSibling;
}

P207  树类中部分主要成员函数的实现


template<class T>
Tree<T>::Tree()
{
	root = NULL;
	parent = NULL;
}

template<class T>
Tree<T>::Tree(TreeNode<T>* rt)
{
	root = rt;
	parent = NULL;
}

template<class T>
TreeNode<T> * Tree<T>::getRoot()
{
	return root;
}

template<class T>
bool Tree<T>::isEmpty()
{
	if(root == NULL)
		return true;
	else 
		return false;
}

template<class T>
int Tree<T>::getParent(TreeNode<T>* t,TreeNode<T>* p)
{
	TreeNode<T>* q = t->getLeftChild();

	while(q!=NULL && q!=p)
	{
		if( getParent(q, p) != 0 )
			return 2;

		q = q->getRightSibling();
	}

	if(q!=NULL && q==p)
	{
		parent = t;
		return 1;
	}
	else return 0;

}

template<class T>
TreeNode<T> * Tree<T>::Parent(TreeNode<T>* current)
{
	TreeNode<T>* pointer=current, *t;

	if(current==NULL||current==root)
	{
		current = NULL;
		return 0;
	}

	t = root;

	getParent(t, pointer);

	return parent;
}

template<class T>
TreeNode<T> * Tree<T>::getFirstChild(TreeNode<T> * t)
{
	return t->getLeftChild();
}

template<class T>
TreeNode<T> * Tree<T>::getNextSibling(TreeNode<T> * t)
{	
	return t->getRightSibling();
}

template<class T>
void Tree<T>::insertChild(TreeNode<T> * t, TreeNode<T> * n)
{
	if(t->getLeftChild()==NULL)
		t->setLeftChild(n);
	else
	{
		TreeNode<T> * p=t->getLeftChild();
		while(p->getRightSibling()!=NULL)
			p=p->getRightSibling();
		p->setRightSibling(n);
	}
}



P218  哈夫曼编码


#include "stdafx.h"
#include <iostream>
#include <string>
#include <queue>
#include <map>
#include <iterator>
#include <algorithm>

using namespace std;
 
typedef vector<bool> HuffCode;
typedef map<char, HuffCode> HuffCodeMap;
 
class INode
{
public:
    const int f;
 
    virtual ~INode() {}
 
protected:
    INode(int f) : f(f) {}
};
 
class InternalNode : public INode
{
public:
    INode *const left;
    INode *const right;
 
    InternalNode(INode* c0, INode* c1) : INode(c0->f + c1->f), left(c0), 

right(c1) {}
    ~InternalNode()
    {
        delete left;
        delete right;
    }
};
 
class LeafNode : public INode
{
public:
    const char c;
 
    LeafNode(int f, char c) : INode(f), c(c) {}
};
 
struct NodeCmp
{
    bool operator()(const INode* lhs, const INode* rhs) const { return 

lhs->f > rhs->f; }
};
 
INode* BuildTree(map<char, int> frequs)
{
    priority_queue<INode*, vector<INode*>, NodeCmp> trees;

	map<char, int>::iterator it = frequs.begin();
	for ( ; it != frequs.end(); it++)
	{
		trees.push(new LeafNode(it->second,  it->first));
	}
 
    while (trees.size() > 1)
    {
        INode* childR = trees.top();
        trees.pop();
 
        INode* childL = trees.top();
        trees.pop();
 
        INode* parent = new InternalNode(childR, childL);
        trees.push(parent);
    }
    return trees.top();
}
 
void GenerateCodes(const INode* node, const HuffCode& prefix, HuffCodeMap& 

outCodes)
{
    if (const LeafNode* lf = dynamic_cast<const LeafNode*>(node))
    {
        outCodes[lf->c] = prefix;
    }
    else if (const InternalNode* in = dynamic_cast<const InternalNode*>

(node))
    {
        HuffCode leftPrefix = prefix;
        leftPrefix.push_back(false);
        GenerateCodes(in->left, leftPrefix, outCodes);
 
        HuffCode rightPrefix = prefix;
        rightPrefix.push_back(true);
        GenerateCodes(in->right, rightPrefix, outCodes);
    }
}
 
int _tmain(int argc, _TCHAR* argv[])
{
	//创建频率表
	map<char, int> frequs;
	cout<<"请输入一行文本数据:"<<endl;
    string str;
	getline(cin, str);
    const char* ptr = str.c_str();
	
    while (*ptr != ‘\0‘)
	{
		if(frequs.find(*ptr)!=frequs.end())
			frequs[*ptr]=frequs[*ptr]+1;
		else
			frequs[*ptr]=1;
		*ptr++;
	}

	INode* root = BuildTree(frequs);
 
    HuffCodeMap codes;
    GenerateCodes(root, HuffCode(), codes);
    delete root;
 
    for (HuffCodeMap::const_iterator it = codes.begin(); it != codes.end(); ++it)
    {
        cout << it->first << " ";
        copy(it->second.begin(), it->second.end(),ostream_iterator<bool>(cout));
        cout << endl;
    }

	system("PAUSE");
    return 0;
}



P224  STL中的vector使用示例


#include <string>
#include <iostream>
#include <vector>

using namespace std;

int main() {

    vector<int> v1(10);
    vector<double> v2;
    vector<string> v3(10, "OK!");
	vector<string> v4(v3);

	v1[1] = 2;
	v1.at(2) = 45;

	for(int i = 0; i < 9; i++)
	{
		v2.push_back(1.0+i);
	}

	v2.pop_back();

	cout<<v2.back()<<endl;
	cout<<v2.front()<<endl;
	cout<<v2.at(5)<<endl;
	cout<<v1[2]<<endl;

	for(i = 0; i < 10; i++)
		cout<<v3[i]<<" ";
	cout<<endl;
	for(i = 0; i < 10; i++)
		cout<<v4[i]<<" ";
	cout<<endl;

	return 0;
}


P226  基于vector实现的树结构


#include<vector> 
#include<iostream>

using namespace std;

class TreeNode
{
	int num;
	vector<TreeNode*> * Sub;

public:

	TreeNode::TreeNode(int n)
	{
		num = n; Sub = NULL;
	}
	int getNum(){return num;}
	vector<TreeNode*> * getSub(){return Sub;}
	void setNum(int n)
	{
		this->num = n;
	}
	void setSub(vector<TreeNode*> * newSub)
	{
		this->Sub = newSub;
	}

	//其它成员方法略
};

class Tree
{
	TreeNode* root;

public:
	Tree(TreeNode* rt){root = rt;}

	void DisplayTree(TreeNode * r)
	{
		cout<<r->getNum()<<endl;

		if(r->getSub()==NULL)
		{
			cout<<"该结点叶子结点!"<<endl;
			return;
		}
		cout<<"该结点的子结点为:"; 
		for(int i = 0; i < (r->getSub())->size(); i++)
		{
			cout<<(r->getSub())->at(i)->getNum()<<" ";
		}

		cout<<endl;

		for(i = 0; i < (r->getSub())->size(); i++)
		{
			DisplayTree((r->getSub())->at(i));
		}
	}
	
	//其它成员方法略
};

int main()
{
	TreeNode treenode0(0);
	TreeNode treenode1(1);
	TreeNode treenode2(2);
	TreeNode treenode3(3);
	TreeNode treenode4(4);
	TreeNode treenode5(5);
	TreeNode treenode6(6);

	vector<TreeNode*> subOfTreeNode0, subOfTreeNode1, subOfTreeNode2;

	subOfTreeNode0.push_back(&treenode1);
	subOfTreeNode0.push_back(&treenode2);

	subOfTreeNode1.push_back(&treenode3);

	subOfTreeNode2.push_back(&treenode4);
	subOfTreeNode2.push_back(&treenode5);
	subOfTreeNode2.push_back(&treenode6);

	treenode0.setSub(&subOfTreeNode0);
	treenode1.setSub(&subOfTreeNode1);
	treenode2.setSub(&subOfTreeNode2);

	Tree tree(&treenode0);
	tree.DisplayTree(&treenode0);

	return 0;
}


P228  STL中的map使用示例


#include<map>
#include<string>
#include<iostream>

using namespace std;

int main()
{
	map<string, string> writer;

	writer["Shakespeare"] = "English writer, 
		his works include ‘Hamlet‘, ‘Othello‘, and ‘King Lear‘, etc.";
	writer["Tagore"] = "India writer, 
		his works include ‘Gitanjali‘, etc.";
	writer["Tolstoy"] = "Russian writer, 
		his works include ‘War and Peace‘, and ‘Anna Karenina‘, etc.";
	writer["Andersen"] = "Danish writer, 
		his works include ‘The Ugly Duckling‘, etc.";
	writer["Dumas"] = "French writer, 
		his works include ‘The Count of Monte Cristo‘, and ‘The Three Musketeers‘, etc.";

	cout<<writer.size()<<endl<<endl;

	int i = 1;

	map<string, string>::iterator it = writer.begin();
	for ( ; it != writer.end(); it++)
	{
		cout << i << " : " <<endl;
		cout << it->first << ": " << it->second << endl;
		i++;
	}

	cout<<endl;
	cout<<(writer.find("Tagore"))->second<<endl<<endl;

	writer.erase(writer.find("Tagore"));
	cout<<writer.size()<<endl<<endl;

	writer.clear();
	cout<<writer.size()<<endl;

	return 0;
}


内容简介:探秘算法世界,求索数据结构之道;汇集经典问题,畅享编程技法之趣;点拨求职热点,敲开业界名企之门。本书围绕算法与数据结构这个话题,循序渐进、深入浅出地介绍了现代计算机技术中常用的四十余个经典算法,以及回溯法、分治法、贪婪法和动态规划等算法设计思想。在此过程中,本书也系统地讲解了链表(包括单向链表、单向循环链表和双向循环链表)、栈、队列(包括普通队列和优先级队列)、树(包括二叉树、哈夫曼树、堆、红黑树、AVL树和字典树)、图、集合(包括不相交集)与字典等常用数据结构。同时,通过对二十二个经典问题(包括约瑟夫环问题、汉诺塔问题、八皇后问题和骑士周游问题等)的讲解,逐步揭开隐匿在数据结构背后的算法原理,力图帮助读者夯实知识储备,激活思维技巧,并最终冲破阻碍编程能力提升的重重藩篱。辅有完整的C++源代码,并穿插介绍了STL中的各种容器。


网上书店:

China-pub中国互动出版网:http://product.china-pub.com/4911922

当当网:http://product.dangdang.com/23851244.html

亚马逊:http://www.amazon.cn/%E7%AE%97%E6%B3%95%E4%B9%8B%E7%BE%8E-%E9%9A%90%E5%8C%BF%E5%9C%A8%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E8%83%8C%E5%90%8E%E7%9A%84%E5%8E%9F%E7%90%86-%E5%B7%A6%E9%A3%9E/dp/B01AGNUIE8/ref=sr_1_8?ie=UTF8&qid=1453527399&sr=8-8&keywords=%E5%B7%A6%E9%A3%9E


算法之美_源代码发布(6)

标签:

原文地址:http://blog.csdn.net/baimafujinji/article/details/50641528

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!