标签:
本文辑录了《算法之美——隐匿在数据结构背后的语言》(电子工业出版社2016年出版)一书第4章之代码(P91~P117)。全文目录、“45个算法”目录、“22个经典问题目录”,以及有奖捉虫活动详情请见如下链接:http://blog.csdn.net/baimafujinji/article/details/50484348
附录中的经典笔试、面试问题参考答案请见:
http://blog.csdn.net/baimafujinji/article/details/50484683
内容简介:探秘算法世界,求索数据结构之道;汇集经典问题,畅享编程技法之趣;点拨求职热点,敲开业界名企之门。本书围绕算法与数据结构这个话题,循序渐进、深入浅出地介绍了现代计算机技术中常用的四十余个经典算法,以及回溯法、分治法、贪婪法和动态规划等算法设计思想。在此过程中,本书也系统地讲解了链表(包括单向链表、单向循环链表和双向循环链表)、栈、队列(包括普通队列和优先级队列)、树(包括二叉树、哈夫曼树、堆、红黑树、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
如果你是该书的读者,请务必加算法学习群(495573865),内有更多资源等你,而你在读书中遇到的疑问也将得到我第一时间的解答。更多关注本博客,我将陆续发布该书全部源代码至本博客。
// #ifndef _LISTNODE_H_ // #define _LISTNODE_H_ template <class T> class ListNode { T data; ListNode<T>* link; public: ListNode() : link(NULL){} ListNode (T value) : link(NULL) , data(value) {} ~ListNode(){}; void SetLink(ListNode<T>* next); void SetData(T value); ListNode<T>* GetLink (); T& GetData (); }; template <class T> void ListNode<T>::SetLink(ListNode<T>* next){ link = next; } template <class T> void ListNode<T>::SetData(T value){ data = value; } template <class T> ListNode<T>* ListNode<T>::GetLink(){ return link; } template <class T> T& ListNode<T>::GetData(){//返回结点中的数据 return data; } //#endif
P96:链表类
#ifndef _LIST_H_ #define _LIST_H_ #include "ListNode.h" template <class T> class List{ ListNode<T>* head; ListNode<T>* tail; public: List (); virtual ~List (); bool AddTail (T value); bool RemoveTail (); bool InsertAt (int index , T value); bool RemoveAt (int index); T& GetAt (int index); bool IsEmpty (); int GetCount (); void RemoveAll (); ListNode<T>* GetHead(); ListNode<T>* GetTail(); ListNode<T>* GetNodeAt(int index); ListNode<T>* GetCur(); ListNode<T>* TowardCur(); }; template<class T> List<T>::List() { head=new ListNode<T>(); tail=head; tail->SetLink (NULL); } template<class T> List<T>::~List() { RemoveAll(); delete head; } template <class T> bool List<T> :: AddTail (T value){ ListNode<T>* add = new ListNode<T> (value); tail->SetLink (add); //把新建结点链入表尾,成为新表尾 tail = tail->GetLink(); //移动表尾指 针置新表尾处 tail->SetLink (NULL); if (tail != NULL) return true; else return false; } template <class T > bool List< T >::InsertAt ( int index,T value ) { //判断索引值是否正确 if(index > this->GetCount ()-1 || index<0 ) { cout<<"A wrong position!\n"; return false; } ListNode<T>* current = head; //从头开始寻找出入地点 while(index) { current = current->GetLink (); //如果没找到,则顺序移动cur --index; } ListNode<T>* add = new ListNode<T> (value); add->SetLink (current->GetLink ()); //将新建结点链入链表 current->SetLink (add); if (current->GetLink () != NULL) return true; else return false; } template <class T> bool List<T>::RemoveTail() {//删除表尾结点 //利用RemoveAt(int index)实现 return RemoveAt(this->GetCount()-1); } template <class T> bool List<T>::RemoveAt(int index){ //按照索引值删除结点 if(index > this->GetCount ()-1 || index<0){ cout<<"A wrong position!\n"; return false; } //用两个结点指针协作完成删除。其中,cur指向要删除结点的前一个结点 //preCur指向要删除的结点 ListNode<T>* cur,* curPre; cur = head; //从链表头开始寻找index 指向的结点 curPre = cur->GetLink(); //置preCur到cur 后 while(index){ cur = cur->GetLink(); //如果没找到,则cur 与preCur继续后移 curPre = curPre->GetLink(); --index; } //如果要删除的结点位于链表尾,则把cur 置为新的表尾 if(tail == curPre) tail = cur; cur->SetLink (curPre->GetLink()); //将被删除结点从链表中摘下 delete curPre; if(curPre != NULL) return true; else return false; } template <class T> T& List<T>::GetAt(int index) { //返回索引值结点中的 value if (index > this->GetCount()-1 || index<0) { cout<<"A wrong position!\n"; } ListNode<T>* cur; cur = head->GetLink(); while(index){ //如果没找到,cur顺序后移 cur = cur->GetLink(); --index; } return cur->GetData (); //返回结点中的 value } template <class T> bool List< T >::IsEmpty ( ) { //判空函数 return head ->GetLink()==NULL ; } template <class T> int List< T >::GetCount() { //返回链表中结点的个数(表头结点除外) int count = 0; //用count记录结点个数 //初始化指针指向第一个结点(不是表头结点) ListNode<T>* current = head->GetLink ( ); while(current != NULL) { ++count; current = current->GetLink ( ); //顺序移动cur } return count; } template <class T> void List< T >::RemoveAll() { //删除所有结点 ListNode<T>* cur; //当表头结点后还有其他结点时,删除这些结点 while(head->GetLink() != NULL) { cur = head->GetLink(); head->SetLink (cur->GetLink()); delete cur; } tail = head; //置表尾为表头处 } template <class T> ListNode<T>* List<T>::GetHead(){//返回头指针 return head; } template <class T> ListNode<T>* List<T>::GetTail(){//返回尾指针 return tail; } //返回指向索引值为index 的结点的指针 template <class T > ListNode< T >* List< T >::GetNodeAt(int index){ //判断索引值是否正确 if(index > this->GetCount()-1 || index<0){ cout<<"A wrong position!\n"; } //handle 即为所求指针,它指向索引值是index 的结点。 ListNode< T >* handle = head->GetLink(); while(index){ //寻找索引值为index 的结点 handle = handle->GetLink(); --index; } return handle; } template <class T> ListNode<T>* List<T>::GetCur(){ return cur; } template <class T> ListNode<T>* List<T>::TowardCur(){ cur = cur->GetLink(); return cur } #endif
#include "stdafx.h" #include "List.h" #include <iostream> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { List<int> list; for(int i = 0; i <9; i++) list.AddTail(i); cout<<list.GetCount()<<endl; cout<<list.GetAt(3)<<endl; list.RemoveAt(3); cout<<list.GetCount()<<endl; cout<<list.GetAt(3)<<endl; list.RemoveAll(); cout<<list.GetCount()<<endl; system("PAUSE"); return 0; }
P101:有序链表的合并
#include "stdafx.h" #include "List.h" #include <iostream> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { //创建两个链表listFirst, listSecond List<int> listFirst; List<int> listSecond; //初始化链表listFirst listFirst.AddTail(1); listFirst.AddTail(6); listFirst.AddTail(8); listFirst.AddTail(9); listFirst.AddTail(13); //初始化链表listSecond listSecond.AddTail(0); listSecond.AddTail(3); listSecond.AddTail(4); listSecond.AddTail(6); listSecond.AddTail(11); listSecond.AddTail(17); while (listSecond.GetCount() != 0){ //当listSecond 非空时持续循环 int indexFirst = 0; //每次把listSecond 中的第一个数按序插入到listFirst 中 //用while循环语句寻找插入位置 while (listSecond.GetAt(0)>listFirst.GetAt(indexFirst)){ ++indexFirst; //如果listFirst 已到链表尾,结束本次循环 if (indexFirst == listFirst.GetCount()){ break; } } if (indexFirst == listFirst.GetCount()){//插入位置在listFirst 链表尾 listFirst.AddTail(listSecond.GetAt(0)); listSecond.RemoveAt(0); } else{//插入位置在listFirst 链表中 listFirst.InsertAt(indexFirst, listSecond.GetAt(0)); listSecond.RemoveAt(0); } } ListNode<int> * curNode = listFirst.GetHead(); while (curNode != listFirst.GetTail()) { curNode = curNode->GetLink(); cout << curNode->GetData() << endl; } system("PAUSE"); return 0; }
P104:单向循环链表类
//#ifndef _CIRLIST_H_ //#define _CIRLIST_H_ #include "ListNode.h" template <class T > class CirList{ ListNode<T>* head; ListNode<T>* tail; ListNode<T>* cur; public : CirList(); ~CirList(); bool AddTail(T value); void RemoveThis(); void RemoveAll(); void SetBegin(); int GetCount(); ListNode<T>* GetCur(); bool IsEmpty(); T GetNext(); }; template <class T > CirList<T>::CirList(){//默认的构造函数 head = tail = new ListNode<T>; //新建结点,并初始化head 与 tail cur = head; head->SetLink(head); } template <class T> CirList<T>::~CirList(){ RemoveAll(); delete head; } template <class T> bool CirList< T >::AddTail(T value){ //在链表尾插入新结点 //新建结点,存储数据 value ListNode<T>* add = new ListNode<T>(value); tail->SetLink(add); //把新结点链入链表 tail = tail->GetLink(); //移动tail 至新表尾处 tail->SetLink(head); //使表尾指针指向表头 if(tail != NULL) return true; else return false; } template <class T> void CirList<T>::RemoveThis(){//把cur 指向的结点删除 if(cur == head){ //如果当前cur在head 处,由于表头结点不可删除,顺序移动cur 至下一结 //点处。 cur = cur->GetLink(); } //用指针preCur标记cur的前一结点, node_del标记要删除的结点 ListNode<T>* node_del = cur; ListNode<T>* preCur = cur; //寻找cur的前一结点,并用preCur记录下来 for(int i=0;i<this->GetCount();i++){ preCur = preCur->GetLink(); } //使cur前一结点的指针指向cur后一结点,即跳过cur所在的结点 preCur->SetLink(cur->GetLink()); delete node_del; //删除后cur顺序移动一个结点。 cur = preCur->GetLink(); preCur = NULL; } template <class T> void CirList< T >::RemoveAll(){//删除所有结点 SetBegin();//开始从第一个结点删除 int length = GetCount();//获取链表长度 for(int i=0;i<length;i++){ RemoveThis(); } cur = head; //置cur 到head 处 } template <class T> void CirList< T >::SetBegin(){//置cur 到head 处,表示链表的开始 cur = head; } template <class T> int CirList<T>::GetCount(){//获得链表长度 int num = 0; if (cur==NULL) this->SetBegin(); ListNode<T>* here = cur; //记录当前结点位置 while(cur->GetLink() != here){ //遍历整个链表,记录结点个数 cur = cur->GetLink(); ++num; } //cur = cur->GetLink();//使cur 回到遍历前的位置 cur = here; return num; } template <class T> ListNode<T>* CirList< T >::GetCur(){//返回当前指针 cur return cur; } template <class T > bool CirList< T >::IsEmpty(){//判断链表是否为空 return head->GetLink() == head; } //返回当前结点中的数据,并使cur顺序移动一个位置 template <class T> T CirList< T >::GetNext(){ if(cur == head){ //跳过表头结点,因为表头结点中不存储有效数据 cur = cur->GetLink(); } T num = cur->GetData(); //获得数据 cur = cur->GetLink(); //顺序移动cur 至下一个结点 return num; } //#endif
P107:约瑟夫环问题
#include "stdafx.h" #include "CirList.h" #include <iostream> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { CirList<int> jos; //新建单向循环链表,模拟约瑟夫问题 //向链表中加入1~15 ,代表编号为1~15 的人 for(int i=1;i<16;i++){ jos.AddTail(i); } jos.SetBegin();//开始模拟约瑟夫问题 //记录原始队列的人数,用此人数减一即可得到要删去多少人 //本题中要删去14人 int length = jos.GetCount(); for(int i=1;i<length;i++) { for(int j=0;j<3;j++) jos.GetNext(); jos.RemoveThis(); } cout<<jos.GetNext()<<endl; system("PAUSE"); return 0; }
P108:魔术师发牌问题
#include "stdafx.h" #include "CirList.h" #include <iostream> //#include "vld.h" using namespace std; int _tmain(int argc, _TCHAR* argv[]) { CirList<int> poker; for(int i=0;i<13;i++){ poker.AddTail(0); //创建循环链表,存储13张扑克牌 } cout<<poker.GetCount()<<endl; poker.SetBegin(); poker.GetCur()->GetLink()->SetData(1); for(int i=2;i<14;i++){ for(int j=0;j<i;j++){ poker.GetNext(); //寻找插牌位置 if(poker.GetCur()->GetData() != 0){ j--; //若当前位置中已有牌,则顺序查找下一个位置 } } poker.GetCur()->SetData(i); } poker.SetBegin(); for(int i=0;i<13;i++){ cout<<poker.GetNext()<<"*"; } cout<<endl; system("PAUSE"); return 0; }
#include "stdafx.h" #include "CirList.h" #include <iostream> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { int num; cout<<"请输入拉丁方阶数(2<=N<=9):"; cin>>num; CirList<int> latin; for(int i=1;i <= num; i++){ latin.AddTail(i); //创建循环链表 } latin.SetBegin(); for(int i=1; i<=num; i++){ for(int j=1; j<=num; j++){ cout<<latin.GetNext()<<" "; //输出循环链表中数据 } cout<<endl; latin.GetNext(); //顺序移动循环链表中所有数据 } system("PAUSE"); return 0; }
P111:双向循环链表节点类
#ifndef _DOULISTNODE_H #define _DOULISTNODE_H template <class T > class DouListNode{ T data; DouListNode<T>* link; DouListNode<T>* prior; public : DouListNode() : link(NULL),prior(NULL){} DouListNode(T value) : link(NULL),prior(NULL),data(value){} ~DouListNode(){}; void SetLink(DouListNode<T>* next); void SetPrior(DouListNode<T>* pre); DouListNode<T>* GetLink(); DouListNode<T>* GetPrior(); T& GetData(); }; template <class T > void DouListNode< T >::SetLink( DouListNode<T>* next ){ //设置link 值 link = next; } template <class T > void DouListNode< T >::SetPrior( DouListNode<T>* pre ){ //设置prior 值 prior = pre; } //返回指向当前结点的后继结点的指针 template <class T > DouListNode<T>* DouListNode< T >::GetLink(){ return link; } //返回指向当前结点的前驱结点的指针 template <class T > DouListNode<T>* DouListNode< T >::GetPrior(){ return prior; } template <class T > T& DouListNode< T >::GetData(){//返回结点中保存的数据 return data; } #endif
P114:双向循环链表类
#ifndef _DOULIST_H #define _DOULIST_H #include "DouListNode.h" template <class T> class DouList{ DouListNode<T>* head; DouListNode<T>* tail; DouListNode<T>* cur; public : DouList(); ~DouList(); bool AddTail(T value); bool AddHead(T value); void RemoveThis(bool direction); void RemoveAll(); void SetBegin(); int GetCount(); void TowardCur(); void BackCur(); DouListNode<T>* GetCur(); DouListNode<T>* GetHead(); DouListNode<T>* GetTail(); void InsertAfter(T value); bool IsEmpty(); T GetNext(); T GetPrior(); }; template <class T> DouList<T>::DouList(){//默认的构造函数 //创建表头结点,并初始化head 指针与tail 指针 head = tail = new DouListNode<T>; cur = head; head->SetLink(head); //创建初始循环。 head->SetPrior(tail); } template <class T> DouList<T>::~DouList(){ RemoveAll(); delete head; } template <class T> bool DouList<T>::AddTail(T value){ //在表尾插入一个新结点 //创建新结点,结点存储的数据由value 决定 DouListNode<T>* add = new DouListNode<T>(value); tail->SetLink(add); //使新结点成为表尾结点的后继结点 add->SetPrior(tail); tail = tail->GetLink(); tail->SetLink(head); //使表尾结点指向表头结点 //设置表头结点的前驱为表尾结点,至此插入操作完成 head->SetPrior(add); //如果新的表尾结点指针为空,则插入失败。 if(tail != NULL){ return true; } else return false; } //此函数用来向表头结点与链表中第一个结点之间插入新结点 template <class T> bool DouList<T>::AddHead(T value){ //创建新结点,保存数据value DouListNode<T>* add = new DouListNode<T>(value); add->SetPrior(head); add->SetLink(head->GetLink()); //置链表中第一个结点的前驱为add //此时add 成为链表中第一个结点 head->GetLink()->SetPrior(add); head->SetLink(add); //如果对空链表应用这个函数,则应该更新尾指针tail if(tail == head){ tail = head->GetLink(); } if(add != NULL){ return true; } else return false; } //把当前cur 指向的结点删除,删除后cur 的移动方向由direction 决定 template <class T> void DouList<T>::RemoveThis(bool direction){ //如果当前cur 位于表头处,由于表头结点不能被删除,顺序移动cur //至下一个位置 if(cur == head){ //如果direction==0,顺着link 方向移动cur if(direction == 0) cur = cur->GetLink(); //如果direction==1,顺着prior 方向移动 cur if(direction == 1) cur = cur->GetPrior(); } //新建指针preCur 与 nextCur。 //preCur 指向cur 的前驱结点 //nextCur 指向 cur 的后继结点 DouListNode<T>* preCur = NULL; DouListNode<T>* nextCur = NULL; preCur = cur->GetPrior(); nextCur = cur->GetLink(); DouListNode<T>* node_del = cur; preCur->SetLink(cur->GetLink()); //使cur 的前驱结点直接指向后继结点 nextCur->SetPrior(cur->GetPrior()); //是cur 的后继结直接指向前驱结点 //根据direction 的值判断cur 的移动方向 //若direction ==0,则向link 方向移动cur if(direction == 0) cur = nextCur; //若direction ==1,则向prior 方向移动cur if(direction == 1) cur = preCur; delete node_del; } template <class T > void DouList<T>::RemoveAll(){//删除所有结点(保留表头结点) SetBegin(); //从头开始删除 int length = GetCount(); //记录当前链表长度 for(int i=0;i<length;i++){ //循环删除 RemoveThis(0); } cur = head; } template <class T > void DouList<T>::SetBegin(){//置cur 到表头处 cur = head; } //获得当前链表中结点个数(不计表头结点) template <class T > int DouList<T>::GetCount(){ int num = 0; //记录链表长度的变量 DouListNode<T>* here = cur; //用here 指针完成对链表的遍历 while(cur->GetLink() != here){ //遍历链表 cur = cur->GetLink(); ++num; } cur = cur->GetLink(); //遍历完成后,置cur到原来的位置 //返回链表长度 return num; } template <class T> void DouList<T>::TowardCur(){//使cur向link方向移动 cur = cur->GetLink(); } template <class T > void DouList<T>::BackCur(){//使cur向prior方向移动 cur = cur->GetPrior(); } template <class T > DouListNode<T>* DouList<T>::GetCur(){//返回指针cur return cur; } template <class T > DouListNode<T>* DouList<T>::GetHead(){ return head; } template <class T > DouListNode<T>* DouList<T>::GetTail(){ return tail; } //判断链表是否为空。 template <class T > bool DouList<T>::IsEmpty(){ //链表为空的条件是链表仅有表头结点 return head->GetLink() == head; } //向cur 指向的结点后插入一个数据成员为value 的新结点 //当对空链表应用这个函数时,作用相当于AddTail( T value ) template <class T > void DouList<T>::InsertAfter(T value){ DouListNode<T>* add = new DouListNode<T>(value); DouListNode<T>* nextCur = cur->GetLink(); //获得cur 的后继结点 cur->SetLink(add); //置cur 的后继结点为要加入的结点 add->SetLink(nextCur); nextCur->SetPrior(add); //置cur 后继结点的前驱为新加结点 add->SetPrior(cur); if(cur==tail){ tail = cur->GetLink(); } } //获得cur指向的结点中的数据,并将cur 向link 方向移动 template <class T > T DouList<T>::GetNext(){ //如果cur位于表头处,则顺序移动cur if(cur == head){ cur = cur->GetLink(); } T num = cur->GetData(); //返回当前结点中的数据 cur = cur->GetLink();//返回数据后移动cur(link 方向) return num; } //获得cur指向的结点中的数据,并将cur 向prior 方向移动 template <class T > T DouList<T>::GetPrior(){ //如果cur位于表头处,则顺序移动cur if(cur == head){ cur = cur->GetPrior(); } T num = cur->GetData(); //返回当前结点中的数据 cur = cur->GetPrior(); //返回数据后移动cur (prior 方向) return num; } #endif
#include "stdafx.h" #include "DouListNode.h" #include "DouList.h" #include <iostream> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { DouList<char> planText; DouList<char> cryptograph; DouList<int> key; DouList<char> trans; planText.SetBegin(); planText.AddTail(‘y‘); planText.AddTail(‘o‘); planText.AddTail(‘u‘); planText.AddTail(‘a‘); planText.AddTail(‘r‘); planText.AddTail(‘e‘); planText.AddTail(‘i‘); planText.AddTail(‘n‘); planText.AddTail(‘d‘); planText.AddTail(‘a‘); planText.AddTail(‘n‘); planText.AddTail(‘g‘); planText.AddTail(‘e‘); planText.AddTail(‘r‘); planText.SetBegin(); cout<<"明文:"<<‘\t‘; for(int z=0;z<planText.GetCount();z++){ cout<<planText.GetNext()<<" "; } cout<<endl<<endl; key.SetBegin(); //产生密钥链表 for(int i=0;i<6;i++){ key.AddTail(1+rand()%9); } cout<<"密钥:"<<‘\t‘; for(int i=0;i<key.GetCount();i++){ cout<<key.GetNext()<<" "; } cout<<endl<<endl; planText.SetBegin(); key.SetBegin(); cryptograph.SetBegin(); for(int i=0;i<planText.GetCount();i++){ char c = planText.GetNext(); int num = key.GetNext(); if(‘a‘<=c&&c<=‘z‘-num) c=c+num; else if(‘z‘-num<c&&c<=‘z‘) c = c+num-1-‘z‘+‘a‘; cryptograph.AddTail(c); } cryptograph.SetBegin(); cout<<"密文:"<<‘\t‘; for(int j=0; j<cryptograph.GetCount(); j++){ cout<<cryptograph.GetNext()<< " "; } cout<<endl<<endl; trans.SetBegin(); planText.SetBegin(); key.SetBegin(); for(int k=0; k<planText.GetCount(); k++){ char c = cryptograph.GetNext(); int num = key.GetNext(); if(‘a‘<=c-num && c-num<=‘z‘) c=c-num; else if(‘a‘>c-num && c>=‘a‘) c = ‘z‘-(‘a‘-c+num)+1; cryptograph.AddTail(c); trans.AddHead(c); } trans.SetBegin(); cout<<"解密:"<<‘\t‘; for(int k=0;k<trans.GetCount();k++){ cout<<trans.GetPrior()<<" "; } cout<<endl<<endl; system("PAUSE"); return 0; }
标签:
原文地址:http://blog.csdn.net/baimafujinji/article/details/50485557