問題描寫敘述:
魔術師手中有A、2、3……J、Q、K十三張黑桃撲克牌。在表演魔術前,魔術師已經將他們依照一定的順序疊放好(有花色的一面朝下)。魔術表演過程為:一開始,魔術師數1,然后把最上面的那張牌翻過來,是黑桃A;然后將其放到桌面上;第二次,魔術師數1、2;將第一張牌放到這些牌的最以下,將第二張牌翻轉過來,正好是黑桃2;第三次,魔術師數1、2、3;將第1、2張牌依次放到這些牌的最以下,將第三張牌翻過來正好是黑桃3;……直到將全部的牌都翻出來為止。問原來牌的順序是怎樣的。
/*! * \file 算法之美--4.3.4 魔術師發牌問題.cpp * \date 2017/02/25 15:58 * * \author ranjiewen * * \brief 問題描寫敘述: 魔術師手中有A、2、3……J、Q、K十三張黑桃撲克牌。在表演魔術前,魔術師已經將他們依照一定的順序疊放好(有花色的一面朝下)。 魔術表演過程為:一開始,魔術師數1,然后把最上面的那張牌翻過來,是黑桃A;然后將其放到桌面上;第二次,魔術師數1、2; 將第一張牌放到這些牌的最以下,將第二張牌翻轉過來,正好是黑桃2;第三次,魔術師數1、2、3;將第1、2張牌依次放到這些牌的最以下,將第三張牌翻過來正好是黑桃3; ……直到將全部的牌都翻出來為止。問原來牌的順序是怎樣的。 * * TODO: long description * * \note */ #include <iostream> using namespace std; #define N 13 typedef struct Node { int data; Node* pNext; Node(int data_ = 0, Node* pNext_ = nullptr) :data(data_), pNext(pNext_){} }Node,*LinkList; void InitLinkList(LinkList&L,int n) //創建並初始化循環鏈表,L表示表頭節點,n創建節點元素的個數 { L = (Node*)malloc(sizeof(Node)); L->pNext = L; //頭結點循環 LinkList p; for (int j = 0; j < n; j++) //一直在頭結點插入 { p = (Node*)malloc(sizeof(Node)); p->data = 0; p->pNext = L->pNext;//插入節點指向頭結點 L->pNext = p; //頭結點指向新的節點 } return; } void Magician(LinkList& L, int n) //魔術師問題求解 { LinkList p = L->pNext; p->data = 1;//第一張為1; for (int num = 2; num <= n;num++) //依次找到2-n牌的位置 { int i = 0; while (i<num) { p = p->pNext; if (p->data==0) //跳過有牌的位置,沒有牌的才加1 { i++; } } p->data = num; } } void Print(LinkList&L) { LinkList p = L->pNext; cout << "Print:"; while (p!=L) { cout << p->data << " "; p = p->pNext; } cout << endl; } int main() { LinkList L; InitLinkList(L,N); Magician(L,N); Print(L); return 0; }
通過約瑟夫環和魔術師發牌問題:對基本的鏈表操作熟悉下了,特別是創建過程,對於循環鏈表;循環的方式可以把頭結點放在里面(本題),也可以不放在里面(約瑟夫問題),通過內存可以查看;兩種方式判斷循環結束的方式也有差別。
CirSinglist *p;
p = pHead->pNext;
while (p->pNext!=p) (不帶頭結點)
LinkList p = L->pNext;
cout << "Print:";
while (p!=L)(帶頭結點)