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

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

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



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

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

P238 图的抽象数据结构

class Graph()
{
	vector<Vertex> VertexSet;	//点集,这里使用vector作为存储结构
	vector<Edge> EdgeSet;		//边集,这里使用vector作为存储结构

public:
	Graph();										//默认构造函数,创建一个空图
	Graph(vector<Vertex> vertexes, vector<Edge> edges);	//含参数的构造函数
	~Graph();												//析构函数
	
	bool IsEmpty();		//判断图是否为空,若是则返回true,否则返回false

	void InsertVertex(const Vertex& vertex);	//在图中插入新的顶点
	void InsertEdge(const Edge& edge);			//在图中插入新的边

	void DeleteVertex(Vertex& vertex);	//删去图中的一个顶点,以及与该顶点相关联的边
	void DeleteEdge(Edge& edge);		//删去图中的一条边

	Vertex * getVertex(const string& nv);	//获取图中某一顶点,若无此点则返回NULL
	Edge * getEdge(const string& ne);		//获取图中某一条边,若无此边则返回NULL
	
	int getEdgeValue(Edge& edge); 		//返回一条边的权值
	Vertex * getEdgeSrc(Edge& edge);	//返回一条边的起始点
	Vertex * getEdgeDst (Edge& edge);	//返回一条边的终止点
	//获得顶点vertex的首个邻接顶点,若无则返回NULL
	Vertex *	getFirstAdjVex(Vertex& vertex); 
	//获得顶点vertex1的某个邻接顶点vertex2的下一个顶点,若无则返回NULL
	Vertex *	getNextAdjVex(Vertex& vertex1, Vertex& vertex2);
	//从顶点vertex开始对图进行深度遍历
	void DFSTraverse(Vertex& vertex);
	//从顶点vertex开始对图进行广度遍历
	void BFSTraverse(Vertex& vertex);
	//获得从顶点vertex1到顶点vertex2的一条最短路径
	vector<Edge*> getShortPath(Vertex& vertex1, Vertex& vertex2);
}


定义图顶点结构

class Vertex
{
	string name_vertex;

	Vertex(const string * n)
	:name_vertex (n) {}
}


定义图的边结构

class Edge
{
	string name_edge;
	Vertex * src;
	Vertex * dst;
	int cost;

	Edge(const string * n, Vertex * s = NULL, Vertex * d = NULL, int c = 0)
	: name_edge(n), src(s), dst(d), cost(c) {}
}


P241 使用邻接矩阵表示图的存储结构之定义

typedef int Vertex;
typedef int AdjMatrix;
class GraphMatrix
{
	int n;			//图中顶点的数目
	Vertex * vexes;	//图中的顶点被存在一个数组里
	AdjMatrix * arcs[];	//用矩阵存储图中的边
}


P243 使用邻接表表示的图存储结构之定义

class EdgeNode;
typedef EdgeNode * EdgeList;

/*边链表*/
class EdgeNode
{
	int vertexNum;				//边结点在顶点表中的下标
	int weight;					//权值
	EdgeNode * nextEdgeNode;	//指针字段,指向下一个链结点
};

/*顶点表*/
class Vertex
{
	char vertex;			//顶点信息
	EdgeList edgeList;		//边链表头指针
};

class GraphList
{
	int n;					//图中顶点个数
	Vertex * vertexes;		//顶点表
};


P247 经典问题之文字游戏问题

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

using namespace std;

#define N 27

char str[1001];
int v
;
int is

;

int viii
;
int dfs(int);
int counter;

int main() {
	int x
,f
,j,len,y
,i,test,flag,lengths,p,q=0;
	int count=0;

	scanf("%d",&test);
	for(i=0;i<test;i++) {
		memset(x,0,sizeof(x));memset(y,0,sizeof(y));
		memset(f,0,sizeof(f));memset(v,0,sizeof(v));
		memset(is,0,sizeof(is));
		for(j=0;j<N;j++)is[j][j]=1;
		scanf("%d",&len);counter=0;
		memset(viii,0,sizeof(viii));
		count=0;

		for(j=0;j<len;j++){
			scanf("%s",str);
			lengths=strlen(str);
			if(str[lengths-1]!=str[0]){	
				x[str[0]-'a']++;
				y[str[lengths-1]-'a']++;
				v[str[0]-'a']=v[str[lengths-1]-'a']=1;
				count++;
				is[str[0]-'a'][str[lengths-1]-'a']=1;
				is[str[lengths-1]-'a'][str[0]-'a']=1;
			}
			else f[str[0]-'a']=1;
		}

		for(j=0,p=0,q=0,flag=0;j<N;j++){
			if(x[j]!=y[j]) {
				if(x[j]==y[j]+1) p++;else if(x[j]+1==y[j])q++; else 
					flag++;
				
			}
		}

		if(count==0){
			for(j=0;j<N;j++) if(f[j]) count++;
 			if(count==1)
				printf("Ordering is possible.\n");
			else
				printf("The door cannot be opened.\n");
			continue;
		}
		for(j=0;j<N;j++) if(v[j]) break;

		dfs(j);
		for(j=0;j<N;j++)
			if(v[j]&&!viii[j]) {j=N+10;break;}
		if(j==N+10) {
				cout<<"The door cannot be opened."<<endl;continue;
		}
		if(!flag&&(p+q==0||p*q==1)) {
			for(j=0;j<N;j++)
				if(f[j]==1&&v[j]!=1) {j=N+10;break;}
			if(j<N+2) printf("Ordering is possible.\n");
			else printf("The door cannot be opened.\n");
		}
		else printf("The door cannot be opened.\n");
	}
	return 0;
}

int dfs(int index) {
	int i=0;
	counter;viii[index]=1;
	for(i=0;i<N;i++)
		if(!viii[i]&&is[i][index]) {
			dfs(i);
		}
	return 0;
}


P251 骑士周游问题

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

using namespace std;

class Board
{
private:
	int board[8][8];  //棋盘
	int step;         //当前走的步数
	int No;	          //当前解的编号
	int direct[8][2]; //各前进方向的坐标偏移
	int wayCount[8][8];  //棋盘上每个位置可跳出的方向数目
	int startX;          //起始点坐标x
	int startY;			//起始点坐标y
	int dir[8][8][8];   //保存最优的搜索方向顺序
	

	void init() 
	{ 
		int i,j,k;
		int x,y;
		//确定从棋盘上每个位置可跳出的方向数目
		for(j=0;j<8;j++)
		{
			for(i=0;i<8;i++) 
			{
				wayCount[j][i]=0;
				for(k=0;k<8;k++) 
				{  
					x=i+direct[k][0]; 
					y=j+direct[k][1];
					if(check(x,y)) 
						wayCount[j][i]++; 
				} 
			}
		}

		//为棋盘上每个位置确定搜索的方向顺序
		for(y=0;y<8;y++)
		{
			for(x=0;x<8;x++) 
			{
				//默认搜索顺序为顺时针方向
				for(k=0;k<8;k++)
				{
					dir[y][x][k]=k;
				}
				//寻找最优搜索顺序
				for(i=0;i<7;i++)
				{
					k=i;
					int x1=x+direct[dir[y][x][k]][0];
					int y1=y+direct[dir[y][x][k]][1];
					//为各搜索方向按规则排序
					//希望搜索时优先到达下一步可能性较少的位置
					for(j=i+1;j<8;j++)
					{
						int x2=x+direct[dir[y][x][j]][0];
						int y2=y+direct[dir[y][x][j]][1];
						//如果从当前位置出发 方向j优于方向k 则将k替换为j
						if( (!check(x1,y1) && check(x2,y2))
							|| ( check(x1,y1) && check(x2,y2) &&
							wayCount[x1][y1]>wayCount[x2][y2]) )
						{
							k=j;
							x1=x+direct[dir[y][x][k]][0];
							y1=y+direct[dir[y][x][k]][1];
						}
					}
					j=dir[y][x][k];
					dir[y][x][k]=dir[y][x][i];
					dir[y][x][i]=j;
				}
			}
		}
	}

	//检查x,y是否为合法位置
	int check(int x,int y) 
	{ 
		if(x<0||x>7||y<0||y>7)
		{
			return 0;
		}
		else
		{
			return 1;
		}
	}

	//从指定位置(x,y)出发寻找路径
	void dg(int x, int y)
	{
		int i,nx,ny;
		//如果当前为最后一步 则终止递归
		if(step==64)
		{
			printPath();
			return;
		}

		//按照最优的搜索方向顺序 依次向各可能方向搜索
		for(i=0;i<8;i++)
		{
			nx=x+direct[dir[y][x][i]][0];
			ny=y+direct[dir[y][x][i]][1];
			if(nx>=0 && nx<8 && ny>=0 && ny<8)
			{
				//如果成功到达下一位置 则从新位置开始继续搜索
				if(board[ny][nx]<0)
				{
					board[ny][nx]=step;
					step++;
					dg(nx,ny);
					board[ny][nx]=-1;
					step--;
				}
			}
		}
	}

	void printPath()
	{
		int i,j;
		No++;
		cout<<"No"<<No<<":"<<endl;
		for(j=0;j<8;j++)
		{
			for(i=0;i<8;i++)
			{
				cout<<board[j][i]<<" ";
				if(board[j][i]<10) 
					cout<<" "; 
			}
			cout<<endl;
		}
		cout<<"Press anykey to continue...";
		getch();
		cout<<endl;
	}
	void printwc()
	{
		int i,j;
		No++;
		cout<<"No"<<No<<":"<<endl;
		for(j=0;j<8;j++)
		{
			for(i=0;i<8;i++)
			{
				cout<<wayCount[j][i]<<" ";
				if(wayCount[j][i]<10) 
					cout<<" "; 
			}
			cout<<endl;
		}
		cout<<"Press anykey to continue...";
		getch();
		cout<<endl;
	}

public:
	Board(int x, int y)
	{
		int i,j;
		startX=x;
		startY=y;
		direct[0][0]=1;		direct[0][1]=-2;
		direct[1][0]=2;		direct[1][1]=-1;
		direct[2][0]=2;		direct[2][1]=1;
		direct[3][0]=1;		direct[3][1]=2;
		direct[4][0]=-1;	direct[4][1]=2;
		direct[5][0]=-2;	direct[5][1]=1;
		direct[6][0]=-2;	direct[6][1]=-1;
		direct[7][0]=-1;	direct[7][1]=-2;
		step=1;
		No=0;
		for(j=0;j<8;j++)
		{
			for(i=0;i<8;i++)
			{
				board[j][i]=-1;
			}
		}
		board[y][x]=0;
	}

	void GetPath()
	{
		init();
		dg(startX,startY);
		if(No==0)
		{
			cout<<"no result"<<endl;
		}
	}
};

int _tmain(int argc, _TCHAR* argv[])
{
	int x,y;
	cout<<"Please input the start point (x,y)."
		<<endl<<"x=";
	cin>>x;
	getchar();
	cout<<"y=";
	cin>>y;
	getchar();
	Board board(x,y);
	board.GetPath();

	return 0;
}


P256 深度优先遍历 与 广度优先遍历

#include "stdafx.h"
#include <iostream>
#include <cstdlib>
#include <set>
#include <vector>
#include <list>
#include <stack>
#include <queue>

using namespace std;

//BFS
void bfs(vector< list<int> >& adj_lists, int start_node) {

    queue<int> not_yet_explored;
    set<int> discovered;

    // 标记起始结点为已被发现, 并将其放入队列中开始探索
    not_yet_explored.push(start_node);
    discovered.insert(start_node);

    while (! not_yet_explored.empty()) {

        // 获得一个新结点并依此作为基点进行探索
        int node_to_explore = not_yet_explored.front();
        not_yet_explored.pop();
        // 检测该结点的所有边
        list<int>::iterator edges = adj_lists[node_to_explore].begin();
        for ( ; edges != adj_lists[node_to_explore].end(); edges++) {

            if (discovered.count(*edges) == 0) {

                // 发现新结点将其加入队列
                discovered.insert(*edges);
                not_yet_explored.push(*edges);

                cout <<"Found "<< *edges <<" from "<<node_to_explore<<endl;

            }
        }
    }
}

//DFS
void dfs_helper(vector< list<int> >& adj_lists, set<int>& discovered, int node) {

    //  检测该结点的所有边
    list<int>::iterator edges = adj_lists[node].begin();
    for ( ; edges != adj_lists[node].end(); edges++) {
        // 检测某条边是否含有未发现的顶点
        if (discovered.count(*edges) == 0) {
            discovered.insert(*edges);
            cout << "Found " << *edges << " from " << node << endl;
            dfs_helper(adj_lists, discovered, *edges);
        }
    }
}

void dfs(vector< list<int> >& adj_lists, int start_node) {

    //标记起始顶点为已被发现
    set<int> discovered;
    discovered.insert(start_node);
    dfs_helper(adj_lists, discovered, start_node);
}

int _tmain(int argc, _TCHAR* argv[])
{
	//初始化图信息
    vector< list<int> > g(7, list<int>());

    g[0].push_back(2);
    g[0].push_back(1);

    g[1].push_back(0);
    g[1].push_back(2);

    g[2].push_back(4);
    g[2].push_back(3);
    g[2].push_back(0);
    g[2].push_back(1);

    g[3].push_back(2);
    g[3].push_back(4);
    g[3].push_back(5);

    g[4].push_back(6);
    g[4].push_back(5);
    g[4].push_back(3);
    g[4].push_back(2);

    g[5].push_back(4);
    g[5].push_back(3);

    g[6].push_back(4);

    cout << "BFS" <<endl;
    bfs(g, 0);

    cout << endl << "DFS" <<endl;
    dfs(g, 0);

	system("PAUSE");
	return 0;
}


P261 经典问题之旅游交通线路问题

City.h文件

#ifndef _CITY_H_
#define _CITY_H_

using namespace std;

class City {

public:

	// 城镇的名称
	string name;

	// 簿记信息
	bool	visited;
	int total_fee;
	int total_distance;
	string from_city;

	//默认构造函数
	City() : name(""), visited(false), total_fee(0), 

total_distance(0), from_city("") {}

	City(string const &s): name(s), visited(false),
	total_fee(0), total_distance(0), from_city("") {}
};

#endif


Road.h文件

#ifndef _ROAD_H_
#define _ROAD_H_

#include <string>

using namespace std;

class Road {

public:

    int fee;
    int distance;
    string destination;

    Road(string city, int f, int d) : fee(f),
    distance(d), destination(city) {}
}
;

#endif

RoadSystem.h文件

#ifndef _ROADSYSTEM_H_
#define _ROADSYSTEM_H_

#include <iostream>
#include <fstream>
#include <map>
#include <list>
#include <queue>
#include <vector>

#include "Road.h"
#include "City.h"

using namespace std;

class Cheapest {

public:
    Cheapest() {}

    bool operator()(City* city1, City* city2) {

        return city1->total_fee > city2->total_fee;
    }

};

class RoadSystem {

private:
    map<string, list<Road*> > outgoing_roads;
    map<string, City*> cities;

    void load_roads(const string& filename);
    void reset(void);
    string recover_route(const string& city);
    pair<int, int> calc_route(string from, string to);

public:

    RoadSystem(const string& filename);//带参数的构造函数,从文件中读取地图信息
    ~RoadSystem(void);//析够函数

    void output_cheapest_route(const string& from, const string& to, ostream& out);
    bool is_valid_city(const string& name);
};

#endif


RoadSystem.cpp文件

#pragma warning (disable:4786)
#pragma warning (disable:4503)

#include "RoadSystem.h"

void RoadSystem::reset(void) {

	map<string, City*>::iterator it;
    for(it=cities.begin();it!=cities.end();++it) {
		it->second->visited = false;
		it->second->total_fee = INT_MAX;
		it->second->total_distance = INT_MAX;
		it->second->from_city = "";
	}
}

string RoadSystem::recover_route(const string& city) {
	
	string route;
	string current = city;
	
	while (current != "") {

        route = current + route;
		string prev = cities[current]->from_city;

        if (prev != "") {
            route = " -> " + route;
        }
		current = prev;
	} 	

	return route;
}

RoadSystem::RoadSystem(string const &filename) {
    
    load_roads(filename);
}

RoadSystem::~RoadSystem(void) {

    // 释放城市信息
    map<string, City*>::iterator city_it = cities.begin();
    for ( ; city_it != cities.end(); city_it++) {
        delete city_it->second;
    }
    
    // 释放道路信息
    map<string, list<Road*> >::iterator roads_it =
    	outgoing_roads.begin();
    for ( ; roads_it != outgoing_roads.end(); roads_it++) {
    
        list<Road*>::iterator road_it = roads_it->second.begin();
        for ( ; road_it != roads_it->second.end(); road_it++) {
            delete *road_it;        
        }
    }
}

void RoadSystem::load_roads(string const &filename) {

	ifstream inf(filename.c_str());
	string from, to;
	int fee, distance;

	while ( inf.good() ) {

		// 读入出发城市,目的城市,费用和路程信息
		inf >> from >> to >> fee >> distance;

		if ( inf.good() ) {
		
			Road* s = new Road(to, fee, distance);
	
			// 在cities容器中加入实体
			if (cities.count(from) == 0) {
				cities[from] = new City(from);  
				outgoing_roads[from] = list<Road*>();
			} 

			if (cities.count(to) == 0) {
				cities[to] = new City(to);  										
				outgoing_roads[to] = list<Road*>();
			}

			// 为城市添加道路
			outgoing_roads[from].push_back(s);	

		}
	}

	inf.close();
}

//输出结果
void RoadSystem::output_cheapest_route(const string& from,
                const string& to, ostream& out) {

	reset();
	pair<int, int> totals = calc_route(from, to);
	
	if (totals.first == INT_MAX) {
		out <<"从"<< from << "到" << to << "之间不存在可达的路径。"<<endl;
	} else {
		out << "从" << from << "到" << to << "之间最便宜的路径需要花费"<< totals.first << "澳元。"<<endl;
		out << "该路线全长" << totals.second << "千米。" <<endl;
        cout << recover_route(to) << endl << endl;
	}
}

bool RoadSystem::is_valid_city(const string& name) {

	return cities.count(name) == 1;
}

//迪克斯特拉算法计算最短路径
pair<int, int> RoadSystem::calc_route(string from, string to) {

	// 用优先队列来获得下一个费用最低的城市
	priority_queue<City*, vector<City*>, Cheapest> candidates;
	City* start_city = cities[from];
	
	// 将起始城市添加到队列中
	start_city->total_fee = 0;
	start_city->total_distance = 0;
	candidates.push(start_city);

	// 如果优先队列不空则循环
	while(!candidates.empty()) {

        City* visiting_city;
		visiting_city = candidates.top();
		candidates.pop();

  		if (! visiting_city->visited) {
  			visiting_city->visited = true;

     		// 循环检查与该城市相连的各条公路
 		 	list<Road*>::iterator it;
 		 	for(it= outgoing_roads[visiting_city->name].begin();
		    	it != outgoing_roads[visiting_city->name].end(); ++it) {

		    	City* next_city = cities[(*it)->destination];
		    	int next_fee = (*it)->fee + visiting_city->total_fee;

		    	// 迪克斯特拉算法修改标记处
		    	if((next_fee < next_city->total_fee)
       				&& next_city->name != from ) {
       				next_city->total_fee = next_fee;
       				next_city->total_distance =
       					(*it)->distance + visiting_city->total_distance;
					next_city->from_city = visiting_city->name;
					candidates.push(next_city);
       			}
  			}
  		}
	}

	// 返回总的费用和总的路程
	if (cities[to]->visited) {
		return pair<int,int>(cities[to]->total_fee, cities[to]->total_distance);
	} else {
		return pair<int,int>(INT_MAX, INT_MAX);
 	}
}


main文件

#pragma warning (disable:4786)
#pragma warning (disable:4503)

#include <iostream>
#include <fstream>
#include <string>
#include <list>
#include <map>
#include <queue>

#include "City.h"
#include "Road.h"
#include "RoadSystem.h"

using namespace std;

int main() {

    try {

        RoadSystem rs("MapInformation.txt");

        while (true) {

            cerr << endl << endl <<"请输入起点城市和终点城市: (退出请输入'quit')"<<endl;

            string from, to;
            cin >> from;
            if (from == "quit") break;
            cin >> to;

            if (rs.is_valid_city(from) && rs.is_valid_city(to)) {
                rs.output_cheapest_route (from, to, cout);
            }
            else {
                cout << "无此城市, 请确认后重试!"<<endl<<endl;
            }

        }

        return EXIT_SUCCESS;

    }
    catch (exception& e) {
        cerr << e.what() << endl;
    }
    catch (...) {
        cerr << "程序出现异常, 请退出程序后重试。"<<endl;
    }

    return EXIT_FAILURE;
}


MapInformation.txt文件

Deloraine Queenstown 42 176
Deloraine Oatlands 25 84
Deloraine Launceston 12 50
Hobart Oatlands 18 84
Launceston Deloraine 12 50
Launceston Swansea 35 134
Oatlands Deloraine 25 84
Oatlands Hobart 18 84
Oatlands Queenstown 60 260
Oatlands Swansea 22 113
Queenstown Oatlands 60 260
Queenstown Deloraine 42 176
Swansea Launceston 35 134
Swansea Oatlands 22 113
Burnie Devonport 10 49
Devonport Burnie 10 49


内容简介:探秘算法世界,求索数据结构之道;汇集经典问题,畅享编程技法之趣;点拨求职热点,敲开业界名企之门。本书围绕算法与数据结构这个话题,循序渐进、深入浅出地介绍了现代计算机技术中常用的四十余个经典算法,以及回溯法、分治法、贪婪法和动态规划等算法设计思想。在此过程中,本书也系统地讲解了链表(包括单向链表、单向循环链表和双向循环链表)、栈、队列(包括普通队列和优先级队列)、树(包括二叉树、哈夫曼树、堆、红黑树、***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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: