您的位置:首页 > 编程语言

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

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



In general, 我不太喜欢翻开一本书(技术书),里面密密麻麻的全部都是代码。所以我也希望能够在我的书中留下更多空间去讨论原理。当然,代码也很重要,所有的一切原理最终都要落实到代码上。为此我习惯于在博客中上传代码,而非是把他们全部罗列到书中去挤占篇幅。

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

P327: 向量集合的声明部分

VecSet.h文件

#ifndef VECSET_H
#define VECSET_H
#include <iostream>
#include <assert.h>
using namespace std;

const int DefaultSize = 100;

class VecSet
{
		int* contain;
		int size;
	public:

	VecSet(int MaxSize = DefaultSize);
	~VecSet();
	
	void Add(int add);
	void Del(int del);
	void MakeEmpty();
	int GetSize(){return size;}
	bool IsMember(const int x);
	VecSet& operator+(VecSet& another);
	VecSet& operator-(VecSet& another);
	VecSet& operator*(VecSet& another);
	VecSet& operator=(VecSet& another);
	bool operator==(VecSet& another);
	friend ostream& operator<<(ostream& stream,VecSet& set);
};

#endif


P329: 向量集合的实现部分

VecSet.cpp文件

#include "VecSet.h"

VecSet::~VecSet()
{
	if(contain != NULL)
		delete [] contain;
}

VecSet::VecSet(int MaxSize):size(MaxSize){
	assert(MaxSize>0);
	contain = new int[size];
	assert(contain != NULL); 
    MakeEmpty();
}

void VecSet::Add(int add){
	assert(add>=0 && add<size);
	contain[add]=1;
}

void VecSet::Del(int del){
	assert(del>=0 && del<size);
	contain[del]=0;
}

void VecSet::MakeEmpty(){
	for(int i=0;i<size;i++){
		contain[i]=0;
	}
}

bool VecSet::IsMember(const int x)
{
	assert(x >= 0 && x < size);
	return contain[x] != 0;
}

VecSet& VecSet::operator+(VecSet& another){
	assert(this->GetSize() == another.GetSize());
	VecSet* temp = new VecSet(this->GetSize()); 
	for(int i=0;i<size;i++){
		(*temp).contain[i] = contain[i]||another.contain[i];
	}
	return *temp;
}

VecSet& VecSet::operator-(VecSet& another){
	assert(this->GetSize() == another.GetSize());
	VecSet* temp = new VecSet(this->GetSize()); 
	for(int i=0;i<size;i++){
		(*temp).contain[i] = contain[i]&&(!another.contain[i]);
	}
	return *temp;
}

VecSet& VecSet::operator*(VecSet& another){
	assert(this->GetSize() == another.GetSize());
	VecSet* temp = new VecSet(this->GetSize()); 
	for(int i=0;i<size;i++){
		(*temp).contain[i] = contain[i]&&another.contain[i];
	}
	return *temp;
}

VecSet& VecSet::operator=(VecSet& another){
	assert(this->GetSize() == another.GetSize());
	for(int i=0;i<size;i++){
		contain[i] = another.contain[i];
	}
	return 
		*this;
}

bool VecSet::operator == (VecSet& another){
	assert(this->GetSize() == another.GetSize());
	for(int i=0;i<size;i++){
		if(contain[i] != another.contain[i]){
			return false;
		}
	}
	return true;
}

ostream& operator<<(ostream& stream,VecSet& set){
	for(int i=0;i<set.GetSize();i++){
		if(set.IsMember(i)) cout<<i<<" ";
	}
	cout<<endl;
	return
		stream;
}


向量集合测试程序

#include <iostream>
#include "VecSet.h"

using namespace std;

int main(int argc, char** argv) {
	
	VecSet a(8);
	VecSet b(8);
	VecSet c(8);
	
	for(int i=1; i<=5; i++){
		a.Add(i);
	}
	
	b.Add(2);
	b.Add(3);
	b.Add(4);
	b.Add(5);
	b.Add(7);		
	b.Del(4);
 
	cout<< a * b;
	cout<< a + b;
	cout<< a - b;
	c = b;
	cout<<c;
	cout<<(c==b);
	
	return 0;
}


P332:链表集合的实现

ListSet.h文件

#ifndef LISTSET_H
#define LISTSET_H

#include <iostream>

using namespace std;

template <class T> class ListSet;

template <class T>
class ListSetNode
{
	friend class ListSet<T>;
	T data;
	ListSetNode<T>* link;
public:
	ListSetNode() :link(NULL){}
	ListSetNode(T value) :link(NULL), data(value){}
};

template <class T>
class ListSet
{
	ListSetNode<T>* head;
	ListSetNode<T>* tail;

public:
	ListSet();
	~ListSet();
	ListSet(ListSet & lset);

	void Add(T add);
	void Del(T del);
	bool IsEmpty();
	void MakeEmpty();
	ListSet<T>& operator+(ListSet<T>& another);
	ListSet<T>& operator-(ListSet<T>& another);
	ListSet<T>& operator*(ListSet<T>& another);
	ListSet<T>& operator=(ListSet<T>& another);
	bool operator==(ListSet<T>& another);
	void Output();
	ListSetNode<T>* GetHead(){ return head; }
};

template <class T>
ListSet<T>::ListSet()
{
	this->head = new ListSetNode<T>();
	this->tail = this->head;
}

template <class T>
ListSet<T>::~ListSet()
{
	MakeEmpty();
	delete head;
}

template <class T>
void ListSet<T>::Add(T value)
{
	ListSetNode<T>* add = new ListSetNode<T>(value);
	ListSetNode<T>* preCurrent = head;				//记录当前结点
	ListSetNode<T>* current = preCurrent->link;		//记录当前结点的前驱结点
	while (current != NULL && current->data < value)		//寻找插入位置
	{
		preCurrent = current;
		current = preCurrent->link;
	}
	if (head == tail && current == NULL)				//向空链表中插入结点
	{
		head->link = add;
		tail = add;
	}
	if (head != tail && current == NULL)				//向链表尾插入值add
	{
		preCurrent->link = add;
		add->link = NULL;
		tail = add;
	}
	if (current != NULL && current->data == value)		//链表中已存在值add
	{
		return;
	}
	if (current != NULL && current->data > value)
	{
		preCurrent->link = add;
		add->link = current;
	}
}

template <class T>
void ListSet<T>::Del(T del)
{
	ListSetNode<T>* preCurrent = head;
	ListSetNode<T>* current = preCurrent->link;
	while (current != NULL && current->data != del)				//寻找删除结点
	{
		preCurrent = current;
		current = preCurrent->link;
	}
	if (current != NULL)
	{
		preCurrent->link = current->link;
		if (current->link == NULL){ tail = preCurrent; }		//更新表尾指针
		delete current;
	}
}

template <class T>
bool ListSet<T>::IsEmpty()
{
	return head == tail;								//判断集合是否为空
}

template <class T>
void ListSet<T>::MakeEmpty()
{
	ListSetNode<T>* current = head->link;
	ListSetNode<T>* del = NULL;
	while (head->link != NULL)					//循环删除集合中的元素
	{
		head->link = current->link;
		del = current;
		current = current->link;
		delete del;								//调用delete释放当前结点
	}
	tail = head;
}

template <class T>
ListSet<T>& ListSet<T>::operator=(ListSet<T>& another)
{
	MakeEmpty();
	ListSetNode<T>* current = another.head->link;
	while (current != NULL)
	{
		Add(current->data);
		current = current->link;
	}
	return *this;
}

template <class T>
ListSet<T>::ListSet(ListSet<T>& lset)
{
	this->head = new ListSetNode<T>();
	this->tail = this->head;

	ListSetNode<T>* current = lset.head->link;
	while (current != NULL)
	{
		Add(current->data);
		current = current->link;
	}

}

template <class T>
ListSet<T>& ListSet<T>::operator+(ListSet<T>& another)
{
	ListSet<T>* tmpSet = new ListSet(another);
	ListSetNode<T>* current = this->head->link;
	while (current != NULL)
	{
		tmpSet->Add(current->data);
		current = current->link;
	}

	return *tmpSet;							//返回当前集合的引用
}

template <class T>
ListSet<T>& ListSet<T>::operator-(ListSet<T>& another)
{
	ListSet<T>* tmpSet = new ListSet(*this);
	ListSetNode<T>* current = another.head->link;
	while (current != NULL)
	{
		tmpSet->Del(current->data);
		current = current->link;
	}
	return *tmpSet;
}

template <class T>
ListSet<T>& ListSet<T>::operator*(ListSet<T>& another)
{
	ListSet<T>* tmpSet = new ListSet(*this);
	*tmpSet = *this - another;
	*tmpSet = *this - *tmpSet;
	return *tmpSet;
}

template <class T>
bool ListSet<T>::operator==(ListSet<T>& another)
{
	ListSetNode<T>* current1 = head->link;
	ListSetNode<T>* current2 = another.head->link;
	while (current1 != NULL)
	{
		if (current2 == NULL){ return false; }
		if (current1->data != current2->data){ return false; }
		current1 = current1->link;
		current2 = current2->link;
	}
	if (current2 != NULL){ return false; }
	return true;
}

template <class T>
void ListSet<T>::Output()
{
	ListSetNode<T>* current = this->GetHead()->link;
	while(current != NULL){
		cout << current->data << " ";
		current = current->link;
	}
	cout << endl;
}

#endif


基于链表实现的集合之测试程序

#include "stdafx.h"
#include "ListSet.h"

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
	ListSet<int> listSetA;
	ListSet<int> listSetB;
	ListSet<int> listSetC;
		
	for (int i = 1; i <= 5; i++)
	{
		listSetA.Add(i);
	}
//	cout << listSetA.IsEmpty()<<endl;
//	listSetA.MakeEmpty();
//	cout << listSetA.IsEmpty()<<endl;
//	listSetC = listSetA;
//	listSetC.Output();

	ListSet<int> listSetD(listSetA);
	cout << (listSetA == listSetD) << endl;

	listSetB.Add(2);
	listSetB.Add(3);
	listSetB.Add(5);
	listSetB.Add(7);
	listSetB.Add(8);
	listSetB.Add(5);
	listSetB.Del(8);

	listSetC = listSetA + listSetB;
	listSetC.Output();

	listSetC = listSetA - listSetB;
	listSetC.Output();

	listSetC = listSetA * listSetB;
	listSetC.Output();

	system("PAUSE");
	return 0;
}


P336:字典

Item.h文件

#ifndef _ITEM_H_
#define _ITEM_H_

#include <iostream>
#include <string.h>

using namespace std;

class Item {

	string english;
	string chinese;
	Item*  link;

public:

	Item() : link(NULL){}
	Item(string en, string ch) : link(NULL), english(en),chinese(ch) {}
	~Item(){};
	void SetLink(Item* next);
	Item*  GetLink();
	string GetIndex();
	string GetValue();
};

void Item::SetLink(Item* next){
	link = next;
}

Item* Item::GetLink(){
	return link;
}

string Item::GetIndex(){//返回结点中的数据
	return english;
}

string Item::GetValue(){//返回结点中的数据
	return chinese;
}

#endif

Dictionary.h文件

#ifndef _DICTIONARY_H_
#define _DICTIONARY_H_

#include "Item.h"

class Dictionary{

	Item* head;
	Item* tail;

public:
	Dictionary();
	virtual ~Dictionary();

	bool Add(string en, string ch);
	bool Del(string en);
	string Search(string en);
	int GetCount();
	void RemoveAll();
};

Dictionary::Dictionary()
{
	head = new Item();
	tail = head;
	tail->SetLink(NULL);
}

Dictionary::~Dictionary()
{
	RemoveAll();
	delete head;
}

bool Dictionary ::Add(string en, string ch){
	Item* add = new Item(en, ch);
	tail->SetLink(add);
	tail = tail->GetLink();
	tail->SetLink(NULL);
	if (tail != NULL)
		return true;
	else
		return false;
}

bool Dictionary::Del(string en){

	Item* cur, *curPre;
	cur = head;
	curPre = cur->GetLink();

	while (cur != NULL){
		if (curPre->GetIndex() == en)
			break;
		cur = cur->GetLink();
		if (cur !=NULL)
			curPre = curPre->GetLink();
	}

	if (tail == curPre)
		tail = cur;
	cur->SetLink(curPre->GetLink());  //将被删除结点从链表中摘下
	delete curPre;

	if (curPre != NULL)
		return true;
	else
		return false;
}

string  Dictionary::Search(string en) {

	Item* cur;
	cur = head->GetLink();
	while (cur != NULL){
		if (en == cur->GetIndex())
			break;
		cur = cur->GetLink();
	}
	if (cur != NULL)
		return cur->GetValue(); //返回结点中的 value
	else
		return "Cannot find";
}

int Dictionary::GetCount() {
	int count = 0;
	Item* current = head->GetLink();
	while (current != NULL) {
		++count;
		current = current->GetLink();  //顺序移动cur 
	}
	return count;
}

void Dictionary::RemoveAll() { //删除所有结点
	Item* cur;
	while (head->GetLink() != NULL) {
		cur = head->GetLink();
		head->SetLink(cur->GetLink());
		delete cur;
	}
	tail = head; //置表尾为表头处
}

#endif


字典测试程序

#include "stdafx.h"
#include <iostream>
#include "Dictionary.h"

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
	Dictionary dic;

	dic.Add("box", "盒子");
	dic.Add("apple", "苹果");
	dic.Add("tree", "树");
	dic.Add("good", "好的");
	dic.Add("swim", "游泳");
	dic.Add("interesting", "有趣的");

	cout << dic.Search("good").c_str() << endl;
	cout << dic.Search("interesting").c_str() << endl;

	dic.Del("box");
	dic.Del("interesting");

	cout << dic.Search("box").c_str() << endl;
	cout << dic.Search("interesting").c_str() << endl;
	cout << dic.Search("apple").c_str() << endl;

	system("PAUSE");
	return 0;
}


P343

template <class T>
class Item{
	int key;
	T data;
public:
	Item():key(-1){}
	Item(int keyInput,T value):key(keyInput),data(value){assert(key>=0);}
	int GetKey(){return key;}
	T GetData(){return data;}
	friend ostream& operator<<(ostream& stream,Item<T>& item);
};

template <class T>
class OrderSearch{
	Item<T>* contain;
	int size;
public:
	OrderSearch():contain(NULL),size(0){}
	OrderSearch(int maxSize);
	void Add(Item<T> add);
	int GetSize(){return size;}
	Item<T>* GetContain(){return contain;}
	Item<T>& Search(int k);
	friend ostream& operator<<(ostream& stream,OrderSearch<T>& set);
};


P344

template <class T>
ostream& operator<<(ostream& stream,Item<T>& item){
	cout<<"key:"<<item.GetKey()<<"\t"<<"data:"<<item.GetData()<<endl;
	return stream;
}


P345

template <class T>
OrderSearch<T>::OrderSearch(int maxSize)
{
	contain = new Item<T>[maxSize];					//建立数组,存放二元组
	size = maxSize;									//记录数组大小
	for(int i=0;i<maxSize;i++)						//初始化字典
	{
		Item<T> ini;
		contain[i] = ini;
	}
}

template <class T>
void OrderSearch<T>::Add(Item<T> add)
{
	assert(add.GetKey()>=0 && add.GetKey()<size);		//判断key的合法性
		contain[add.GetKey()] = add;					//添加二元组
}

template <class T>
Item<T>& OrderSearch<T>::Search(int k)
{
	assert(k>=0 && k<size);								//判断key的合法性
	return contain[k];									//返回二元组
}

template <class T>
ostream& operator<<(ostream& stream,OrderSearch<T>& set)
{
	for(int i=0;i<set.GetSize();i++)
	{
		if(set.GetContain()[i].GetKey() != -1)
		{
			cout<<"key:"<<set.GetContain()[i].GetKey()<<"\t";
			cout<<"data:"<<set.GetContain()[i].GetData()<<endl;
		}
	}
	return stream;
}


P346

template <class T>
int BinarySearch(List<T>& dic, T& item) {

	int lowKey = 0;
	int highKey = dic.GetCount() - 1;
	int midKey;

	while (lowKey <= highKey)
	{
		midKey = (lowKey + highKey) / 2;				//寻找中间结点
		if (dic.GetAt(midKey) < item)
		{
			lowKey = midKey + 1;						//在右半集合中搜索
   	    }
		else if (dic.GetAt(midKey) > item)
		{
			highKey = midKey - 1;						//在左半集合中搜索
		}
		else 
			return midKey;
	}
	return -1;
}


P351-1: BKDR散列

连同测试程序一并给出。你会发现这个算法在处理C语言关键字时可以获得非常小的冲突率。例如当我们去HASHSIZE为101时,就可以做到完全没有冲突。

#include <iostream>
#include <string>
#include <iomanip>
#include <stdint.h>

using namespace std;

#define HASHSIZE 101

string keywords[] = {
  "auto",   "break",  "case",     "char",   "const",    "continue", "default",  "do",
  "double", "else",   "enum",     "extern", "float",    "for",      "goto",     "if",
  "int",    "long",   "register", "return", "short",    "signed",   "sizeof",   "static",
  "struct", "switch", "typedef",  "union",  "unsigned", "void",     "volatile", "while"
};

unsigned long BKDRHash(const string& str)  
{
	unsigned long seed = 31;
	unsigned long hashval = 0; 
    
	for(int i = 0; i < str.length(); i++)
		hashval = hashval * seed + str[i];
	return hashval % HASHSIZE;  
}

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

  int size, pos;
  int count[HASHSIZE];
  
  for(int i = 0; i < HASHSIZE; i++)
     count[i] = 0;

  size = sizeof(keywords) / sizeof(keywords[0]);
  for(int i = 0;i < size; i++)
    count[BKDRHash(keywords[i])]++;

  for(int i = 0; i < size; i++) {
    pos = BKDRHash(keywords[i]);
    cout<<setw(8)<<keywords[i]<<setw(5)<<pos<<setw(5)<<count[pos]<<endl;
  }

	return 0;
}


P351-2: RS散列(连同测试程序一并给出)

#include <iostream>
#include <string>
#include <iomanip>
#include <stdint.h>

using namespace std;

#define HASHSIZE 41

string keywords[] = {
  "auto",   "break",  "case",     "char",   "const",    "continue", "default",  "do",
  "double", "else",   "enum",     "extern", "float",    "for",      "goto",     "if",
  "int",    "long",   "register", "return", "short",    "signed",   "sizeof",   "static",
  "struct", "switch", "typedef",  "union",  "unsigned", "void",     "volatile", "while"
};

unsigned long RSHash(const string& str)  
{
	unsigned long a = 31415, b = 27183;  
	unsigned long hashval = 0;  
	for(int i = 0; i < str.length(); i++)  
	{  
		hashval = (hashval * a + str[i])%HASHSIZE;  
		a = a * b % (HASHSIZE-1);  
	}  
	return hashval;  
}

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

	int size, pos;
	int count[HASHSIZE];
  
	for(int i = 0; i < HASHSIZE; i++)
		count[i] = 0;

	size = sizeof(keywords) / sizeof(keywords[0]);
	size = 32;
	for(int i = 0;i < size; i++)
		count[RSHash(keywords[i])]++;

	for(int i = 0; i < size; i++) {
		pos = RSHash(keywords[i]);
		cout<<setw(8)<<keywords[i]<<setw(5)<<pos<<setw(5)<<count[pos]<<endl;
	}

	return 0;
}


P352: FNV散列(连同测试程序一并给出)

#include <iostream>
#include <string>
#include <iomanip>
#include <stdint.h>

using namespace std;

//const long offsetbasis32 = 2166136261;
#define FNV_32_INIT ((uint32_t)0x811c9dc5)
//const long FNVprime32 = 16777619;
#define FNV_32_PRIME ((uint32_t)0x01000193)

unsigned long FNV1a_32_Hash(const string& str)  
{  
	unsigned long hashval = FNV_32_INIT;  
	for(int i = 0; i < str.length(); i++)  
	{  
		hashval = hashval ^ str[i];  
	//	hashval = hashval * FNV_32_PRIME;
	//  上面一句代码等价于下面之位操作 
		hashval += (hashval <<1) + (hashval <<4) 
				+ (hashval <<7) + (hashval <<8) + (hashval <<24);
	
	}
	return hashval;  
}

//const long offsetbasis64 = 14695981039346656037;
//#define FNV_64_INIT ((uint64_t)0x14650FB0739D0383);
#define FNV_64_INIT ((uint64_t)0xcbf29ce484222325ULL);
//const long FNVprime64 = 1099511628211;
#define FNV_64_PRIME ((uint64_t)0x100000001b3ULL)

uint64_t FNV1a_64_Hash(const char* bp, size_t len)  
{  
	uint64_t hval = FNV_64_INIT;  
	const char *be = bp + len;  
	while (bp < be) {  
		hval ^= (uint64_t) *bp++;  
		hval += (hval << 1) + (hval << 4) + (hval << 5) + (hval << 7) + (hval << 8) + (hval << 40);  
	}  
	return hval;  
}

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

	string str = "interesting";
	cout<<hex<<FNV1a_32_Hash(str)<<endl;
	cout<<hex<<FNV1a_64_Hash(str.c_str(), str.length())<<endl;
	
	return 0;
}


内容简介:探秘算法世界,求索数据结构之道;汇集经典问题,畅享编程技法之趣;点拨求职热点,敲开业界名企之门。本书围绕算法与数据结构这个话题,循序渐进、深入浅出地介绍了现代计算机技术中常用的四十余个经典算法,以及回溯法、分治法、贪婪法和动态规划等算法设计思想。在此过程中,本书也系统地讲解了链表(包括单向链表、单向循环链表和双向循环链表)、栈、队列(包括普通队列和优先级队列)、树(包括二叉树、哈夫曼树、堆、红黑树、***L树和字典树)、图、集合(包括不相交集)与字典等常用数据结构。同时,通过对二十二个经典问题(包括约瑟夫环问题、汉诺塔问题、八皇后问题和骑士周游问题等)的讲解,逐步揭开隐匿在数据结构背后的算法原理,力图帮助读者夯实知识储备,激活思维技巧,并最终冲破阻碍编程能力提升的重重藩篱。辅有完整的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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: