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

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

时间:2016-02-25 11:59:56      阅读:345      评论:0      收藏:0      [点我收藏+]

标签:

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

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

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

技术分享


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

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


P360:  拼写检查问题


dictionary.h文件


#ifndef  _DICTIONARY_H_ 
#define  _DICTIONARY_H_

#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
#include <string>
#include <cstdlib>
#include <fstream>

#include  "hashset.h"
#include  "hashset.cpp"

using namespace std;

//散列函数
class hash_function
{
public:
    hash_function() {}

    unsigned int operator()( const string& s )  const {

		unsigned int res=0;
		for (int i=0; i<s.size(); i++)
		{
			res=res*1000+s[i];
		}
		return res;

    }
};

class equality
{
public:
    equality() {}
    bool  operator()( const string& A, const string& B )  const {
		return  (A == B);
    }
};

//字典类
class Dictionary: public HashSet<string, hash_function, equality> {

protected:
	ifstream infile;
public:
	Dictionary(const string &filename) {
	
		infile.open(filename.c_str());

		if ( !infile ) {
			cerr << "cannot open " << filename << " for input" << endl;
			return;
		}

		string line="";

		while (getline(infile,line)) {

			insert(line);
		}
		infile.close();

	}
};

#endif


hashset.h文件


#ifndef  _HASHSET_H_ 
#define  _HASHSET_H_

#include <iostream>
#include <vector>
#include <algorithm>
#include <stdexcept>

using namespace std;

template<class key_type, class hash_func, class key_equal>
class  HashSet {

protected:

    class Entry {
        public:
        key_type key;
        bool used;

        Entry() : used(false) {}
    };

    int entries;
    int prime;

    vector<Entry> *ht;
    hash_func hf;
    key_equal eq;

    int table_size()  const {return prime_list[prime];}
    float load_factor() const {return float(size()) / table_size();}
    int resize();
    
public:

    HashSet()
		  : entries(0), prime(0), 
          ht(new vector<Entry>(prime_list[0]))
          {}
          
    virtual ~HashSet() { 
		delete ht;
	}

    virtual int size() const {return entries;}
    virtual bool search(const key_type& k);
    virtual void insert(const key_type& k);
    virtual void remove(const key_type& k);
};

#endif

hashset.cpp文件


#include  "hashset.h"

using namespace std;

static const int num_primes = 25;
static const unsigned long prime_list[] = {
    53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593, 49157, 98317,
    196613, 393241, 786433, 1572869, 3145739, 6291469, 12582917, 25165843,
    50331653, 100663319, 201326611, 402653189, 805306457
};

template<class key_type, class hash_func, class key_equal>
bool HashSet<key_type,hash_func,key_equal>::search(const key_type& k) {

    int p = hf(k) % table_size();

    while ((*ht)[p].used) {
        if (eq((*ht)[p].key, k)) {
            return true;
        }
        p++;
        if (p == table_size()) {
            p = 0;
        }
    }

    return false;
}

template<class key_type, class hash_func, class key_equal>
void HashSet<key_type,hash_func,key_equal>::remove(const key_type& k) {

    int p = hf(k) % table_size();

    while ((*ht)[p].used) {
        if (eq((*ht)[p].key, k)) { 
            (*ht)[p].used = false;
			entries--;
			break;
        }
        p++;
        if (p == table_size()) {
            p = 0;
        }
    }
    
}

template<class key_type, class hash_func, class key_equal>
void HashSet<key_type,hash_func,key_equal>::insert(const key_type& k) {

    if (load_factor() > .7) {
        resize();
    }

    int pp = hf(k) % table_size();
    int p = pp;

    while (p < table_size() && (*ht)[p].used) {
        p++;
    }
    
    if (p == table_size()) {
        p = 0;
    }
    
    while ((*ht)[p].used) {
        p++;
    }

    (*ht)[p].key = k;
    (*ht)[p].used = true;
    entries++;

}

template<class key_type, class hash_func, class key_equal>
int HashSet<key_type,hash_func,key_equal>::resize() {

    if (prime == num_primes - 1) {
        cerr << "maximal table size reached, aborting ... " << endl;
        exit(2);
    }

    int mm = prime_list[prime];
    prime++;
    int m = prime_list[prime];
    vector<Entry>* ptr = new vector<Entry>(m);

    for (int i = 0; i < mm; ++i) {
    
        if ((*ht)[i].used) {
            key_type kk = (*ht)[i].key;

            int p = hf(kk) % m;

            while (p < m && (*ptr)[p].used) {
                p++;
            }
            if (p == m) {
                p = 0;
            }
            while ((*ptr)[p].used) {
                p++;
            }

            (*ptr)[p].key = kk;
            (*ptr)[p].used = true;
        }
    }

    delete ht;
    ht = ptr;
    return  m;
}

main.cpp文件


#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <cctype>

#include "dictionary.h"

using namespace std;

void lower(string& s);
string strip_punct(const string& s);
void check_spelling(ifstream& in, Dictionary& dict);

void spellSuggestionOne(Dictionary& dict, const string& word);
void spellSuggestionTwo(Dictionary& dict, const string& word);
void spellSuggestionThr(Dictionary& dict, const string& word);
void spellSuggestionFou(Dictionary& dict, const string& word);

void main() {

	ifstream inf("test.txt");
	if (! inf) {
		cerr << "读入文件失败,请确认后重试!" << endl;
		return;
	}

	cout << "字典载入中,这个过程可能需要几分钟..."<<endl;

	Dictionary d("wordlist.txt");

	check_spelling(inf, d);

	inf.close();
}

void check_spelling(ifstream& in, Dictionary& dict) {

	int line_number = 0;

	while (in) {

		line_number++;

		string line;
		getline(in, line);

  	    stringstream ss (stringstream::in | stringstream::out);
		ss << line;

		string word;
		while (ss >> word) {
			
			word = strip_punct(word);
			lower(word);

			if(!dict.search(word))
			{
				cout<<"line "<<line_number<<":	\‘"<<word<<"\‘"<<endl;
				cout<<"\tsuggestions:"<<endl;

				spellSuggestionOne(dict, word);
				spellSuggestionTwo(dict, word);
				spellSuggestionThr(dict, word);
				spellSuggestionFou(dict, word);
			}

		}

	}

}

void lower(string& s) {

	for (int i = 0; i < s.length(); i++) {
		s[i] = tolower(s[i]);
	}
}

string strip_punct(const string& s) {

	if (ispunct(s[s.length() - 1]) ) {
		return s.substr (0, s.length() - 1);
	}
	else {
		return s;
	}
}

void spellSuggestionOne(Dictionary &dict, const string& word)
{
	string temp="";
	string foregoing="";

	for(int i=0;i<word.size();i++){
		
		temp=word;
		//交换相邻字母
		char tempChar = temp[i];
		temp[i]=temp[i+1];
		temp[i+1]=tempChar;

		if(dict.search(temp)&&temp!=foregoing)
		{
			foregoing=temp;
			cout<<"\t\t"<<temp<<endl;
		}
	}
}

void spellSuggestionTwo(Dictionary& dict, const string& word)
{
	string temp="";
	string foregoing="";

	for(int i=0; i<word.size(); i++)
	{
		temp=word;
		//删除一个字母
		temp.erase(i, 1);

		if(dict.search(temp)&&temp!=foregoing)
		{
			foregoing=temp;
			cout<<"\t\t"<<temp<<endl;
		}
	}
} 

void spellSuggestionThr(Dictionary& dict, const string& word)
{
	string temp="";
	string foregoing="";
	string str="abcdefghijklmnopqrstuvwxyz";

	for(int i=0; i<word.size(); i++)
	{
		temp=word;
		for(int j=0; j<26; j++)
		{
			temp=word;
			temp.replace(i, 1, str.substr(j,1));
			if(dict.search(temp)&&temp!=foregoing)
			{
				foregoing=temp;
				cout<<"\t\t"<<temp<<endl;
			}
		}
	}
} 

void spellSuggestionFou(Dictionary& dict, const string& word)
{ 
	string temp="";
	string foregoing="";
	string str="abcdefghijklmnopqrstuvwxyz";

	for(int i=0; i<word.size(); i++)
	{
		temp = word;
		for(int j=0; j<26; j++)
		{
			temp = word;
			temp.insert(i, str.substr(j,1)); 
			if(dict.search(temp)&&temp!=foregoing)
			{
				foregoing=temp;
				cout<<"\t\t"<<temp<<endl;
			}
		}
	}
}


用于测试的test.txt文件内容


An individual humann existence should be like a rievr, small at first, narrowly contained within its bannks, and rushing passionately past boulders and over waterfalls. Gradually the river grws wider, the banks recede, the waters flow more quietly, and in the end, withut any visible break, they become merged in the ssea, and painlessly lose theur individual being.


wordlist.txt文件百度云下载地址:http://pan.baidu.com/s/1hrtxWR6


P366: 不相交集类的实现


测试程序一并给出。


#include <iostream>
#include <unordered_map>  

using namespace std;

class Disjoint_set{
	unordered_map<int, int> PARENT;
public:
	Disjoint_set(int * array, int len){
		for(int i = 0; i < len; i++)
		PARENT[array[i]]=array[i];
	}
	
	int Find(int item){
		if(PARENT[item] == item)
			return item;
		else
			return Find(PARENT[item]);
	}
	
	void Union(int node1, int node2){
		int set1 = Find(node1);
		int set2 = Find(node2);
		PARENT[set1]=set2;
	}
};

int main(int argc, char** argv) {	

	int array[] = {0, 1, 2, 3, 4, 5, 6};
	int len = sizeof(array)/sizeof(array[0]);
	Disjoint_set dj_set(array, len);

	dj_set.Union(4, 3);
	dj_set.Union(6, 5);
	dj_set.Union(6, 4);
	dj_set.Union(2, 3);
	
	cout<<dj_set.Find(6)<<endl;
	cout<<dj_set.Find(5)<<endl;
	
	return 0;
}

特备说明:上述程序是在Dev C++ 5.11版本(编译器内核为TDM-GCC 4.9.2)上编译运行的。如果出现下面的错误提示:This file requires compiler and library support for the ISO C++ 2011 standard. This support is currently experimental, and must be enabled with the -std=c++11 or -std=gnu++11 compiler options. (这主要是由于使用了头文件unordered_map所导致的)

那么在Dev C++环境下的解决方法为:选择菜单栏中的“Project”,然后再单击下拉菜单中的“Project Options”。然后按下图所示进行必要设置即可。

技术分享


P368:  基于按深度求并改进的不相交集类


为配合测试函数,下述代码较书中之原码略有修改。


#include <iostream>
#include <unordered_map>  

using namespace std;

class Disjoint_set{
	
	unordered_map<int, int> PARENT;
	
public:
		
	Disjoint_set(int * array, int len){
		for(int i = 0; i < len; i++)
			PARENT[array[i]] = -1;
	}
	
	int Find(int item){
		if(PARENT[item] < 0)
			return item;
		else
			return Find(PARENT[item]);
	}
	
	void Union(int node1, int node2){
		int set1 = Find(node1);
		int set2 = Find(node2);
		if(set1==set2)
			return;
		
		if(PARENT[set1] < PARENT[set2])
			PARENT[set2] = set1;
		else
		{
			if( PARENT[set1] == PARENT[set2])
				PARENT[set2]-=1;
			PARENT[set1]=set2;
		}
	}
	
	
	//////////////////////
	unordered_map<int, int> getP()
	{
		return PARENT;
	}
};

int main(int argc, char** argv) {
	
	int array[] = {0, 1, 2, 3, 4, 5, 6};
	int len = sizeof(array)/sizeof(array[0]);
	Disjoint_set dj_set(array, len);

	dj_set.Union(4, 3);
	dj_set.Union(6, 5);
	dj_set.Union(6, 4);
	dj_set.Union(2, 3);
	
	cout<<dj_set.Find(6)<<endl;
	cout<<dj_set.Find(5)<<endl;
	
	unordered_map<int, int> p = dj_set.getP();

	for(int i = 0; i < len; i++)
	{
		cout<<p[i]<<" ";
	}
	cout<<endl;
	
	return 0;
}

P369:犯罪团伙问题


#include <iostream>
#include <unordered_map>  

using namespace std;

class Disjoint_set{
	
	unordered_map<int, int> PARENT;
	
public:
		
	Disjoint_set(int * array, int len){
		for(int i = 0; i < len; i++)
			PARENT[array[i]] = -1;
	}
	
	int Find(int item){
		if(PARENT[item] < 0)
			return item;
		else
			return Find(PARENT[item]);
	}
	
	void Union(int node1, int node2){
		int set1 = Find(node1);
		int set2 = Find(node2);
		if(set1==set2)
			return;
		
		if(PARENT[set1] < PARENT[set2])
			PARENT[set2] = set1;
		else
		{
			if( PARENT[set1] == PARENT[set2])
				PARENT[set2]-=1;
			PARENT[set1]=set2;
		}
	}
};

int main(int argc, char** argv) {
	
	int array[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
	int len = sizeof(array)/sizeof(array[0]);
	Disjoint_set dj_set(array, len);
	
	dj_set.Union(0, 1);
	dj_set.Union(2, 3);	
	dj_set.Union(4, 1);	
	dj_set.Union(3, 5);	
	dj_set.Union(1, 5);		
	dj_set.Union(7, 6);	
	dj_set.Union(8, 6);	
	dj_set.Union(0, 5);
	dj_set.Union(1, 3);
	
	int nums[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
	for(int i = 0; i < len; i++)	
		nums[dj_set.Find(i)]+=1;

	int sum = 0;
	for(int i = 0; i < len; i++)
	{ 
		if(nums[i] != 0)
			sum++;
	}
	cout<<"犯罪团伙数量:"<<sum<<endl;	

	return 0;
}


P372:  STL中set的使用


#include<set>
#include<iostream>
#include<iterator>
#include<algorithm>

using namespace std;

int main(int argc, char** argv) {
	
set<int> mySet2;
	set<int> mySet3;

	set<int>::iterator i;

	int a[] = {1, 2, 3, 4, 5};

	set<int> mySet1( a, a + 5);

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

	i = mySet1.begin();
    cout<<"mySet1 : ";
	//遍历输出
    while( i != mySet1.end() )
    {
		cout<< *i <<" ";
		++ i;
    }

	mySet2.insert(2);
	mySet2.insert(3);
	mySet2.insert(5);
	mySet2.insert(7);

	cout<<endl;

	if (mySet2.find(5) != mySet2.end()) {
		cout << "mySet2 contains 5";
	}

	ostream_iterator<int> out(cout, " ");
	//求集合mySet1与mySet2的交集
	cout << "\nmySet1与mySet2的交集: ";
	set_intersection(mySet1.begin(), mySet1.end(), 
							mySet2.begin(), mySet2.end(),out);
	//求集合mySet1与mySet2的并集
	cout << "\nmySet1与mySet2的并集: ";
	set_union(mySet1.begin(), mySet1.end(), 
							mySet2.begin(), mySet2.end(), out);
	//求集合mySet1与mySet2的差
	cout << "\nmySet1与mySet2的差集: ";
	set_difference(mySet1.begin(), mySet1.end(), 
							mySet2.begin(), mySet2.end(),out);
	//求集合mySet1与mySet2的对称差
	set_symmetric_difference(mySet1.begin(), mySet1.end(), 
							mySet2.begin(), mySet2.end(),
							inserter(mySet3, mySet3.begin()));

	cout << "\nmySet1与mySet2的对称差: ";
	i = mySet3.begin();
	while( i != mySet3.end() )
	{
		cout<< *i <<" ";
		++ i;
	}

	cout<<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


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

标签:

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

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