面試題1:約瑟夫環
約瑟夫環故事背景:
著名猶太歷史學家 Josephus有過以下的故事:
在羅馬人佔領喬塔帕特後,39 個猶太人與Josephus及他的朋友躲到一個洞中,
39個猶太人決定寧願死也不要被敵人抓到,
於是決定了一個自殺方式,41個人排成一個圓圈,
由第1個人開始報數,每報數到第3人該人就必須自殺,
然後再由下一個重新報數,直到所有人都自殺身亡爲止。
然而Josephus 和他的朋友並不想遵從,Josephus要他的朋友先假裝遵從,
他將朋友與自己安排在第16個與第31個位置,於是逃過了這場死亡遊戲。
問題:怎樣確定16和31的位置
解題思路:
從開始位置遍歷,當指針到報數爲三的位置上時,將第三個位置的節點刪除,然後繼續循環刪除,直到當前節點(指針指向的節點)的後一個節點的next是當前節點時,即留下兩個元素。
如圖所示:
pLinkNode JoseCycle(pList *pHead, int num) { assert(pHead); pLinkNode cur = *pHead; pLinkNode del = NULL; int count = 0; while (1) { count = num; if (cur == cur->next->next) //當前節點的後一個節點的next是當前節點時,結束循環 { break; } while (--count) //找到第num個元素 { cur = cur->next; } del = cur->next; cur->data = cur->next->data; cur->next = cur->next->next; free(del); //刪除第num個元素 del == NULL; } *pHead = cur; return cur; }
測試函數:
void Test13() // 測試約瑟夫環 { pList l1; int i = 0; InitLinkList(&l1); for (i = 1; i <= 41; i++) { PushBack(&l1, i); } pLinkNode pos = Find(l1,41); //查找元素,Find函數在單鏈表的實現中 pos->next = l1; //構建環 pos=JoseCycle(&l1,3); printf(" %d \n", pos->data); printf(" %d \n", pos->next->data); }