1. 程式人生 > >通過例子進階學習C++(七)CMake專案通過模板庫實現約瑟夫環

通過例子進階學習C++(七)CMake專案通過模板庫實現約瑟夫環

本文是通過例子學習C++的第七篇,通過這個例子可以快速入門c++相關的語法。

1.問題描述

回顧一下約瑟夫環問題:n 個人圍坐在一個圓桌周圍,現在從第 s 個人開始報數,數到第 m 個人,讓他出局;然後從出局的下一個人重新開始報數,數到第 m 個人,再讓他出局......,如此反覆直到所有人全部出局為止。

上一篇我們通過陣列、靜態連結串列實現了約瑟夫環,具體參考:

通過例子進階學習C++(六)你真的能寫出約瑟夫環麼

本文,我們進一步深入分析約瑟夫環問題,並通過c++模板庫實現該問題求解,最後我們說明用模板庫的優劣之處。

2.模板庫專案搭建

本文我們用c++的模板庫通過單向迴圈連結串列實現約瑟夫環問題,用c++模板庫實現約瑟夫環。

首先我們在Visual Studio中“檔案”--“新建”--”CMake專案“:

點選“下一步”:

點選“建立”,即可生成一個CMake的C++專案。

在解決方案上面,點選“右鍵”,“新增”--“新建資料夾”:

在資料夾中新建檔案“circList.h”、“CMakeLists.txt”和“main.cpp”。

然後在整個專案的“CMakeLists.txt"中增加如下內容:

3.C++模板庫通過迴圈連結串列實現約瑟夫環

用C++模板庫實現約瑟夫環,主要包括這3個檔案:“circList.h”、“CMakeLists.txt”和“main.cpp”。整個程式碼以《資料結構 用面向物件方法與c++語言描述》(第2版)上面的實現為基礎。

用書本上面的例子,是無法直接執行的,耗費了一定的時間才修改好。

circList.h相關程式碼:

template<class T>
struct CircLinkNode {
    T data;
    CircLinkNode<T>* link;
    CircLinkNode(CircLinkNode<T> *next = NULL):link(next){}
    CircLinkNode(T d, CircLinkNode<T> *next = NULL):data(d),link(next){}
};

template<class T>
class CircList {
public:
    CircList() {
        first = last = NULL;
    }
    CircList(const T& x) {
        first = new CircLinkNode<T>(x);
    }
    CircList(CircList<T>& L) {
        T value;
        CircLinkNode<T>* srcptr = L.getHead();
        CircLinkNode<T>* destptr = first = new CircLinkNode<T>;
        while (srcptr->link != NULL) {
            value = srcptr->link->data;
            destptr->link = new CircLinkNode<T>(value);
            destptr = destptr->link;
            srcptr = srcptr->link;
        }
        destptr->link = NULL;
    }
    ~CircList() {
        //makeEmpty();
    }
    void makeEmpty() {
        CircLinkNode<T>* q;
        while (first!=NULL && first->link != first) {
            q = first->link;
            first->link = q->link;
            delete q;
        }
    }
    int length() const {
        CircLinkNode<T>* p = first->link;
        int count = 0;
        while (p != NULL) {
            count++;
            p = p->link;
        }
        return count;
    }
    CircLinkNode<T>* getHead()const {
        return first;
    }
    void setHead(CircLinkNode<T>* p) {
        first = p;
    }
    CircLinkNode<T>* Search(T x) {
        CircLinkNode<T>* current = first->link;
        while (current != first) {
            if (current->data == x) break;
            else current = current->link;
        }
        return current;
    }
    CircLinkNode<T>* Locate(int i) {
        if (i < 0) return NULL;
        CircLinkNode<T>* current = first;
        int k = 0;
        while (current->link != first && k < i) {
            current = current->link;
            k++;
        }
        return current;
    }
    T* getData(int i) {
        if (i < 0) return NULL;
        CircLinkNode<T>* current = Locate(i);
        if (current == NULL) return NULL;
        else return &current->data;
    }

    void setData(int i, T& x) {
        if (i < 0) return;
        CircLinkNode<T>* current = Locate(i);
        if (current == NULL) return;
        else current->data = x;
    }

    bool Insert(int i, T& x) {
        CircLinkNode<T>* newNode = new CircLinkNode<T>(x);
        if (newNode == NULL) {
            cerr << "儲存分配失敗!" << endl;
            exit(1);
        }
        
        if (i == 1) {
            first = last = newNode;
            first->link = newNode;
        }
        else {
            last->link = newNode;
            last = newNode;
        }
        
        newNode->link = first;  
        return true;
    }
    bool Remove(int i, CircLinkNode<T> * p, CircLinkNode<T>* pre) {
        if (first == p) {
            first = p->link;
        }
        if (last == p) {
            last = pre;
        }
        delete p;
        return true;
    }
    void output() {
        CircLinkNode<T>* current = first->link; 
        cout << first->data << "  ";

        while (current != last->link) {
            cout << current->data <<"  ";
            current = current->link;
        }
        cout << endl;
    }
private:
    CircLinkNode<T>* first, * last;
};

CMakeLists.txt相關程式碼如下:

# CMakeList.txt: DataStructure 的 CMake 專案,在此處包括原始碼並定義
# 專案特定的邏輯。
#
cmake_minimum_required (VERSION 3.8)

# 將原始碼新增到此專案的可執行檔案。
add_executable (circList "main.cpp" "circList.h" )

# TODO: 如有需要,請新增測試並安裝目標。

main.cpp相關程式碼如下:

#include<iostream>
#include "circList.h"

using namespace std;

template<class T>
void Josephus(CircList<T> &Js,int n,int m) {
    CircLinkNode<T>* p = Js.getHead();
    CircLinkNode<T>* pre = NULL;

    int i, j;
    for (i = 0; i < n - 1; i++) {
        for (j = 0; j < m-1; j++) {
            pre = p;
            p = p->link;
        }
        
        cout << "出列的是:" << p->data << endl;
        pre->link = p->link;

        Js.Remove(p->data,p,pre);
        
        p = pre->link;

        cout << "出列後的佇列為:" << endl;
        Js.output();
        cout << "當前元素為:" << p->data << endl;
    }
}

int main() {
    CircList<int> clist;
    int i, n, m;
    cout << "輸入遊戲者人數和報數間隔:"<<endl;
    cin >> n >> m;
    for (i = 1; i <= n; i++) {
        clist.Insert(i,i);
    }

    Josephus(clist, n, m);
}

程式執行後效果如下:

4.總結

本著Talk is cheap. Show me the code原則,程式碼實現不做過多解釋。

通過該例子,可以學習:

  • 在Visual Studio中搭建CMake專案;
  • 在CMake專案中增加“可執行檔案”;
  • 掌握struct定義;class定義;template class 、function定義;建構函式;解構函式;
  • 通過模板庫實現約瑟夫環問題

本文從構思到完成,可謂是耗費了大量的心血。

如果您閱讀本文後哪怕有一丟丟收穫,請不要吝嗇你手中關注和點讚的權力,謝謝!

另外,如果需要相關程式碼,請留言,可以提供完整原始碼