本文辑录了《算法之美——隐匿在数据结构背后的语言》(电子工业出版社2016年出版)一书第5~6章之代码(P149~P183)。全文文件夹、“45个算法”文件夹、“22个经典问题文件夹”,以及有奖捉虫活动详情请见例如以下链接:http://blog.csdn.net/baimafujinji/article/details/50484348
附录中的经典笔试、面试问题參考答案请见:
http://blog.csdn.net/baimafujinji/article/details/50484683
In general。 我不太喜欢翻开一本书(技术书),里面密密麻麻的所有都是代码。所以我也希望可以在我的书中留下很多其它空间去讨论原理。当然,代码也非常重要。所有的一切原理终于都要落实到代码上。为此我习惯于在博客中上传代码。而非是把他们所有罗列到书中去挤占篇幅。
假设你是该书的读者,强烈建议你加入算法学习群(495573865)。内有很多其它资源等你,而你在读书中遇到的疑问也将得到我第一时间的解答。
很多其它关注本博客,我将陆续公布该书所有源码至本博客。
P149:优先级队列的实现
template <class T>
class PriQueueNode{
public:
T data;
PriQueueNode<T>* link;
PriQueueNode(T& value):data(value),link(NULL){}
};
template <class T>
class PriQueue{
PriQueueNode<T>* front;
PriQueueNode<T>* back;
public:
PriQueue():front(NULL),back(NULL){}
void EnQueue(T& element);
T DelQueue();
T& GetFront();
void MakeEmpty();
bool IsEmpty();
};
template <class T>
void PriQueue<T>::EnQueue(T& value)
{
PriQueueNode<T>* add = new PriQueueNode<T>(value);
if(front == NULL)
front = back = add;
else
{
back->link = add;
back = back->link;
}
}
template <class T>
T PriQueue<T>::DelQueue()
{
PriQueueNode<T>* seek = front->link; //遍历队列。寻找最小元素的指针
PriQueueNode<T>* min = front; //指向最小元素的指针
T minData; //记录最小元素的数据
while(seek!=NULL){
if(seek->data < min->data) //寻找最小元素
min = seek;
seek = seek->link;
}
seek = front; //指针重回队列头部
while(seek!=NULL&&seek->link!=min) //寻找最小元素的前驱结点
{
seek = seek->link;
}
if(seek == NULL){ //假设最小元素位于队列头部
minData = front->data;
front = front->link; //更新队头指针
delete min;
}
if(min->link == NULL) //假设最小元素位于队列尾部
back = seek; //更新队尾指针
if(seek!=NULL){ //假设最小元素位于队列中间,无需更新
minData = min->data; //队头指针与队尾指针。直接删除就可以
seek->link = min->link;
delete min;
}
return minData; //返回数据
}
template<class T>
T& PriQueue<T>::GetFront(){
assert(!this->IsEmpty());
return front->data;
}
template<class T>
void PriQueue<T>::MakeEmpty(){
while(!IsEmpty()){
this->DelQueue();
}
}
template<class T>
bool PriQueue<T>::IsEmpty()
{
return front == NULL;
}
P151:STL中的Stack应用演示样例1
#include "stdafx.h"
#include <iostream>
#include <cstdlib>
#include <stack>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
stack<int> myStack;
//入栈与出栈
myStack.push(5);
myStack.push(6);
myStack.push(7);
myStack.pop();
cout << myStack.top() << endl;
cout << myStack.size() << endl;
cout << myStack.empty() << endl;
system("PAUSE");
return 0;
}
P152:STL中的Stack应用演示样例2
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
#include <stack>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
ifstream inf;
inf.open("temp.txt");
if ( !inf ) {
cerr << "cannot open file for input!" << endl;
return EXIT_FAILURE;
}
stack<string> s;
string line;
while (getline(inf, line)) {
s.push(line);
}
inf.close();
while (!s.empty()) {
cout << s.top() << endl;
s.pop();
}
system("PAUSE");
return 0;
}
P153: STL中的queue使用演示样例
#include "stdafx.h"
#include <iostream>
#include <cstdlib>
#include <queue>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
queue<int> myQueue;
//加入元素与删除元素
myQueue.push(5);
myQueue.push(6);
myQueue.push(7);
myQueue.pop();
cout << myQueue.front() << endl;
cout << myQueue.back() << endl;
cout << myQueue.size() << endl;
cout << myQueue.empty() << endl;
system("PAUSE");
return 0;
}
P154:基于FIFO策略的内存页面淘汰过程模拟
#include "stdafx.h"
#include <iostream>
#include <cstdlib>
#include <queue>
using namespace std;
bool existOrNot(int num, queue<int> myQueue)
{
while(!myQueue.empty())
{
if(myQueue.front()==num)
return true;
else myQueue.pop();
}
return false;
}
int _tmain(int argc, _TCHAR* argv[])
{
queue<int> memQueue;
int page[] ={4, 3, 2, 1, 4, 3, 5, 4, 3, 2, 1, 5};
int times = 12;
int tmpValue;
for(int i = 0; i < 12; i++)
{
if(memQueue.size()<3)
memQueue.push(page[i]);
else
{
if(existOrNot(page[i], memQueue))
{
times--;
}
else
{
memQueue.pop();
memQueue.push(page[i]);
}
}
int size = memQueue.size();
while(size>0)
{
cout<<memQueue.front()<<" ";
tmpValue = memQueue.front();
memQueue.pop();
memQueue.push(tmpValue);
size--;
}
cout<<endl;
}
cout<<"使用FIFO策略时。共发生缺页中断"<<times<<"次."<<endl;
system("PAUSE");
return 0;
}
P156:STL中的priority_queue使用演示样例1
#include "stdafx.h"
#include <iostream>
#include <cstdlib>
#include <queue>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
priority_queue<int> Q;
Q.push(1);
Q.push(5);
Q.push(2);
Q.push(4);
Q.push(6);
Q.push(3);
int size = Q.size();
for(int i = 0; i< size; i++)
{
cout<<Q.top()<<endl;
Q.pop();
}
cout<< endl << Q.empty() <<endl;
system("PAUSE");
return 0;
}
P157:STL中的priority_queue使用演示样例2
#include "stdafx.h"
#include <iostream>
#include <cstdlib>
#include <queue>
using namespace std;
class myCompare{
public:
bool operator () (const int& a,const int& b)
{
return a > b;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
priority_queue<int, vector<int>, myCompare> Q;
Q.push(1);
Q.push(5);
Q.push(2);
Q.push(4);
Q.push(6);
Q.push(3);
int size = Q.size();
for(int i = 0; i < size; i++)
{
cout<<Q.top()<<endl;
Q.pop();
}
cout<< endl << Q.empty() <<endl;
system("PAUSE");
return 0;
}
P161:阶乘的递归求解函数
int factorial(int n) {
if (n == 0) {
return 1;
}
else {
int value = factorial(n - 1);
return n * value;
}
}
P163:递归实现的二分查找
#include "stdio.h"
#include <vector>
#include <iostream>
using namespace std;
int binarySearch(const vector<int> & a, const int & x, int low, int high)
{
if(low>high)
return -1;
int mid = (low + high)/2;
//二分查找法的递归核心部分
if(a[mid]<x)
return binarySearch(a, x, mid+1, high);
else if(x<a[mid])
return binarySearch(a, x, low, mid-1);
else
return mid;
}
int Search(const vector<int> & a, const int & x)
{
return binarySearch(a, x, 0, a.size()-1);
}
void main()
{
vector<int> box;
box.push_back(1);
box.push_back(4);
box.push_back(6);
box.push_back(7);
box.push_back(8);
box.push_back(10);
box.push_back(13);
box.push_back(21);
box.push_back(22);
box.push_back(30);
const int searchValue = 22;
int result = Search(box, searchValue);
if(result == -1)
cout<<"要查的数字不在数组内。"<<endl;
else
cout<<searchValue<<"的位置在第"<<++result<<"位"<<endl;
}
P164:斐波那契数列的递归实现
int Fib(int n){
if(n<=1) return n;
else return Fib(n-1)+Fib(n-2);
}
P165:递归的顺序演示样例程序
#include "stdio.h"
void recursiveFunction1 ( int num )
{
if ( num < 5 )
{
printf ( "%d \n" , num ) ;
recursiveFunction1 ( num +1 ) ;
}
}
void recursiveFunction2 ( int num )
{
if ( num < 5 )
{
recursiveFunction2 ( num +1 ) ;
printf ( "%d \n" , num ) ;
}
}
void main()
{
recursiveFunction1(0);
recursiveFunction2(0);
}
P168-1:求和函数的递归实现
int Sum( int n )
{
if ( n==1 )
return 1;
else
return Sum(n-1)+n;
}
P168-2:斐波那契数列的迭代实现
int Fib ( int n ) {
if ( n <= 1 ) return n;
int twoback = 0;
int oneback = 1;
int Current;
for ( int i = 2; i <= n; i++ ) {
Current = twoback + oneback;
twoback = oneback;
oneback = Current;
}
return Current;
}
P169:阶乘函数的尾递归实现
int factorial(int acc , int x)
{
if (x <= 1)
return acc;
else
return factorial ( x * acc, x - 1 );
}
P170-1:求解最大公约数的欧几里德算法(尾递归实现)
int gcd(int a, int b)
{
if (b == 0)
return a;
else
return gcd(b, a%b);
}
P170-2:求解最大公约数的欧几里德算法(非递归实现)
int gcd ( int a, int b )
{
while ( b != 0 )
{
int r = a % b;
a = b;
b = r;
} return a;
}
P173: 汉诺塔问题
#include "stdafx.h"
#include <fstream>
#include <iostream>
using namespace std;
//盘子的数目
#define numOfDisks 10
//在文本文件out.txt中输出结果
ofstream fout("out.txt");
void Move(int n,char x,char y)
{
fout<<"move "<<n<<" from "<<x<<" to "<<y<<endl;
}
//递归求解
void Hannoi(int n,char a,char b,char c)
{
if(n==1)
Move(1,a,c);
else
{
Hannoi(n-1,a,c,b);
Move(n,a,c);
Hannoi(n-1,b,a,c);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
fout<<"The solution for Hanoi, when the number of disks is "<<
numOfDisks<<endl;
Hannoi(numOfDisks,'a','b','c');
fout.close();
cout<<"The End! Please Check out.txt."<<endl;
system("pause");
return 0;
}
P175:传染病问题
main.cpp文件
#include <iostream>
#include <string>
#include <cstdlib>
#include "grid.h"
using namespace std;
#define ROWS 6
#define COLS 6
#define TOTAL 13 // 被感染点的总数
// 标记被感染点的坐标的数组
int theCity[TOTAL][2] = {
{0,0},
{1,1},
{2,2},
{2,3},
{2,5},
{3,2},
{3,3},
{3,5},
{4,0},
{4,2},
{4,3},
{4,5},
{5,0}
};
int main () {
grid *g;
int col;
int row;
g = new grid ((int*)theCity, ROWS, COLS, TOTAL);
cout << "请输入要检測点的坐标 格式: x,y" << endl;
scanf("%d,%d", &row, &col);
cout << "The colony including the cell at "
<< "(" << row << "," << col << ")"
<< " has an area of " << g->count (row,col) << " units." << endl;
cout << *g << endl;
delete g;
return EXIT_SUCCESS;
}
grid.h文件
#ifndef GRID_H
#define GRID_H
#include <string>
#include <vector>
using namespace std;
const bool INFECTED = true;
const bool NOT_INFECTED = false;
class grid;
class grid {
int rows;
int cols;
int number;
vector<bool> *area;
vector<bool> *marked_area;
int indexof (int row, int col) const;
bool infected(int row, int col) const;
void caculate(int row,int col);
public:
grid (int* theCity, int, int, int);
~grid ();
int count (int row, int col);
friend ostream &operator<<(ostream &stream, const grid& ob);
};
#endif
grid.cpp文件
#include <iostream>
#include <fstream>
using namespace std;
#include "grid.h"
int grid::indexof (int row, int col) const {
return row*cols+col;
}
bool grid::infected(int row, int col) const {
return (area->operator[](indexof(row, col)) == INFECTED);
}
//构造函数
grid::grid (int* theCity, int row, int col, int total) {
number=0;
rows = row;
cols = col;
area = new vector<bool>(rows*cols, NOT_INFECTED);
marked_area = new vector<bool>(rows*cols, NOT_INFECTED);
for (int i=0; i<total; i++) {
int blob_row;
int blob_col;
blob_row = theCity[i*2];
blob_col = theCity[i*2+1];
area->operator[](indexof(blob_row,blob_col)) = INFECTED;
}
}
//析构函数
grid::~grid () {
delete area;
delete marked_area;
}
//在被感染的细胞处加入一个(+),运算符重载
ostream &operator<<(ostream &stream, const grid& ob) {
for (int row=0; row < ob.rows; row++) {
for (int col=0; col < ob.cols; col++) {
stream << ob.area->operator[](ob.indexof(row, col));
if(ob.marked_area->operator[](ob.indexof(row, col)))
stream << "+ ";
else
stream << " ";
}
stream << endl;
}
stream << endl;
return stream;
}
int grid::count (int row, int col)
{
caculate(row,col);
return number;
}
//递归核心部分,进行八个方向的检查
void grid::caculate(int row,int col)
{
if (row<0||col<0||row>=rows||col>=cols||marked_area->operator [](indexof(row,col)))
return;
if (infected(row,col))
{
marked_area->operator[](indexof(row, col)) = INFECTED;
number++;
caculate(row,col+1);
caculate(row,col-1);
caculate(row+1,col);
caculate(row-1,col);
caculate(row+1,col+1);
caculate(row-1,col-1);
caculate(row+1,col-1);
caculate(row-1,col+1);
}
}
sample.grid 文件内容
6 6
0 0
1 1
2 2
2 3
2 5
3 2
3 3
3 5
4 0
4 2
4 3
4 5
5 0
P177:迷宫问题
#include <vector>
#include <iostream>
using namespace std;
// 把迷宫表示为n个有编码路口的集合
// 定义路口类
class Crossing
{
public:
// 0为不通 路口的三个方向
int turn1;
int turn2;
int turn3;
public:
Crossing(int turn1, int turn2, int turn3)
{
Crossing::turn1 = turn1;
Crossing::turn2 = turn2;
Crossing::turn3 = turn3;
}
};
// 定义迷宫类
class Maze
{
private:
int exit; //出口编码
vector<Crossing> crossings; //路口集合
vector<int> result;
public:
Maze(int the_exit, vector<Crossing> the_crossings)
{
exit = the_exit;
crossings = the_crossings;
}
findExit(int entrance); //迷宫求解
getResult(); //取得迷宫解并打印
};
//迷宫求解核心算法
Maze::findExit(int entrance)
{
if(entrance > 0)
{
if(entrance == Maze::exit)
{
result.push_back(entrance);
return 1;
}
if(findExit(crossings[entrance].turn1))
{
result.push_back(entrance);
return 1;
}
if(findExit(crossings[entrance].turn2))
{
result.push_back(entrance);
return 1;
}
if(findExit(crossings[entrance].turn3))
{
result.push_back(entrance);
return 1;
}
}
return 0;
}
Maze::getResult()
{
findExit(1);
for(int i = result.size(); i>0; i--)
cout << result[i-1] << "->";
cout << "Exit" << endl;
}
void main()
{
// 创建一个迷宫 9个路口 出口为10
Crossing c1(2,0,0);
Crossing c2(4,0,0);
Crossing c3(0,0,0);
Crossing c4(3,5,0);
Crossing c5(6,0,0);
Crossing c6(7,0,0);
Crossing c7(8,9,0);
Crossing c8(0,0,0);
Crossing c9(10,0,0);
Crossing c0(0,0,0);
vector<Crossing> crossings;
crossings.push_back(c0);
crossings.push_back(c1);
crossings.push_back(c2);
crossings.push_back(c3);
crossings.push_back(c4);
crossings.push_back(c5);
crossings.push_back(c6);
crossings.push_back(c7);
crossings.push_back(c8);
crossings.push_back(c9);
Maze newMaze(10, crossings);
newMaze.getResult();
return;
}
P182:八皇后问题
#include <conio.h>
#include <iostream>
using namespace std;
// 首先 要求皇后不冲突,那么每行仅仅应该有一个皇后
// 用queens[]数组在存储每一个皇后的位置
// 比如: queens[m] = n 表示 第m行的皇后放在第n列上
#define MAX 8
int sum = 0;
class QueenPuzzle
{
int queens[MAX]; // 存储每行皇后的列标
public:
void printOut(); // 打印结果
int IsValid(int n); //推断第n个皇后放上去之后。是否合法
void placeQueen(int i); // 递归算法 放置皇后
};
void QueenPuzzle::printOut()
{
for(int i=0; i<MAX; i++)
{
for(int j=0; j<MAX; j++)
{
if(j == queens[i])
cout << "Q ";
else
cout << "0 ";
}
cout << endl;
}
cout << endl << "按q键盘退出,按其它键继续" << endl << endl;
if(getch() == 'q')
exit(0);
}
// 在第i行放置皇后
void QueenPuzzle::placeQueen(int i)
{
for(int j=0; j<MAX; j++)
{
// 假设所有放完了 输出结果
if(i == MAX)
{
sum ++;
cout << "第" << sum << "组解:" << endl;
printOut();
return;
}
// 放置皇后
queens[i] = j;
// 此位置不能放皇后 继续试验下一位置
if(IsValid(i))
placeQueen(i+1);
}
}
//推断第n个皇后放上去之后。是否合法,即是否无冲突
int QueenPuzzle::IsValid(int n)
{
//将第n个皇后的位置依次于前面n-1个皇后的位置比較。
for(int i = 0 ; i < n ; i++)
{
//两个皇后在同一列上,返回0
if(queens[i] == queens[n])
return 0;
//两个皇后在同一对角线上,返回0
if(abs(queens[i] - queens[n]) == (n - i))
return 0;
}
//没有冲突。返回1。
return 1; } void main() { QueenPuzzle queen; queen.placeQueen(0); cout << "共" << sum << "组解" << endl; }
内容简单介绍:探秘算法世界,求索数据结构之道。汇集经典问题。畅享编程技法之趣;点拨求职热点,敲开业界名企之门。
本书环绕算法与数据结构这个话题,循序渐进、深入浅出地介绍了现代计算机技术中经常使用的四十余个经典算法,以及回溯法、分治法、贪婪法和动态规划等算法设计思想。
在此过程中,本书也系统地解说了链表(包含单向链表、单向循环链表和双向循环链表)、栈、队列(包含普通队列和优先级队列)、树(包含二叉树、哈夫曼树、堆、红黑树、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