本文辑录了《算法之美——隐匿在数据结构背后的语言》(电子工业出版社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 " , num ) ; recursiveFunction1 ( num +1 ) ; } } void recursiveFunction2 ( int num ) { if ( num < 5 ) { recursiveFunction2 ( num +1 ) ; printf ( "%d " , 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