[C/C++] 環狀鏈結:尋找特別數

【輸入】

輸入任意男女名單,O為男;X為女,並找出一個特別數,從環狀鏈結依序點人,點到的人可以登船,並且這個特別數要能滿足讓所有的男性登船。

【輸出】

特別數

【完整程式碼】

#include <stdlib.h>
#include <iostream> 
#include <algorithm>
#include <string> 
using namespace std;

/*-------------------- 定義環狀串列結構 --------------------*/
// 定義節點結構
class Node{
    public:
        char sex;
        Node *next;
        // Constructor
        Node(char c){ sex = c; next = NULL; }
};

// 定義串列結構
class CircularList{
    public:
        Node *rear;
        
        CircularList(){ rear = NULL; }
        
        // 清空節點方法
        void clearNode(){
            if(rear != NULL){
                Node *ptr, *lnk;                //ptr是存取的指針,從頭(rear->next)開始存取
                for(ptr = rear->next; ptr != rear; ptr = lnk){
                    lnk = ptr->next;            //lnk暫存下個節點的指針
                    delete ptr;                 //刪除目前節點
                }
                delete ptr;                     //刪除最後一個節點
                rear = NULL;                    //重新初始化串列
            }
        }
        // 加入新節點
        void addNode(char c){
            Node *newp = new Node(c);
            if(rear == NULL)            //若環狀串列為空,則自己連到自己
                rear = newp->next = newp;
            else {                      //否則
                newp->next = rear->next;    //新節點的下個節點連到頭節點
                rear = rear->next = newp;   //原本的尾的下一個連到新節點,再把尾改成新節點
            }
        }
        // 移除節點
        void deleteNode(Node *target){
            Node *prev = rear;
            while(prev->next != target)     //從頭節點(rear->next)開始找
                prev = prev->next;

            prev->next = target->next;      //若在A->B->C中找到B,目前prev是A,target是B,將A的next重新指向C
            if(target == rear)              //若B是尾,
                rear = prev;                    //則將尾指定給A
            
            delete target;
        }
};

CircularList circularList;  //宣告並初始化環狀鏈結

/*-------------------- 特別數驗證 --------------------*/
bool isTrue(int num, int ALL_MALE){
    int count = 0;                          //已登船的人數
    Node *ptr = circularList.rear, *tbk;    //ptr == 第一次被計算的人之前的人 == 被允許登船的人之前的人
    while(count != ALL_MALE) {              //【若 NUMBERS_OF_ON_BOARD != ALL_MALE】
        /*--- Counting ---*/
        for(int i = 1; i < num; i++)                //只找N-1次,因為只有N個人可以登船,所以PTR是N-1位.
            ptr = ptr->next;                                //算人數移動PTR.
        
        /*--- Checking ---*/
        tbk = ptr->next;                            //tbk = 第N個人 (ptr->next)
        if(tbk->sex == 'O'){                        //【若第N個人 (tbk) 是男性】
            circularList.deleteNode(tbk);                   //刪除節點(該人被允許登船)
            count++;                                        //已登船的人數+1
        }else return false;                         //【否則,這不是個特別數】
    }
    return true;
}

/*-------------------- Data input --------------------*/
// 建立新的環狀鏈結
void createCircular(string members){
    for(int i = 0; i < members.size(); i++)
        circularList.addNode(members[i]);
}
// 輸入
void input(string prompt, string *members){
    cout << prompt;
    cin >> *members;
}

/*-------------------- Main Function --------------------*/
int main(void) {
    string MemberList;              //名單的清單
    int maleCount, specialNum = 0;  //男性數量及特別數

    input("請輸入男女生名單(O為男X為女):", &MemberList);
    maleCount = count(MemberList.begin(), MemberList.end(), 'O');

    if(maleCount>0)
        do{
            specialNum++;                   //從1開始找特別數
            circularList.clearNode();       //清除環狀鏈結
            createCircular(MemberList);     //重建環狀鏈結
        }while(!isTrue(specialNum, maleCount));

    cout << "Number: " << specialNum << endl;
    system("pause");
    return 0; 
}
測試資料:

請輸入男女生名單(O為男X為女):OXOOXOOOOXOO
Number: 54