DHU28 循环链表ADT模板简单应用算法设计:约瑟夫环

问题描述 :

目的:使用C++模板设计循环链表的抽象数据类型(ADT)。并在此基础上,使用循环链表ADT的基本操作,设计并实现单链表的简单算法设计。

内容:(1)请使用模板设计循环链表的抽象数据类型。(由于该环境目前仅支持单文件的编译,故将所有内容都集中在一个源文件内。在实际的设计中,推荐将抽象类及对应的派生类分别放在单独的头文件中。参考网盘中的单链表ADT原型文件,自行设计循环链表的ADT。)

(2)ADT的简单应用:使用该ADT设计并实现循环链表应用场合的一些简单算法设计。

应用2:编号为1,2,...,n的n个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。现在给定一个随机数m>0,从编号为1的人开始,按顺时针方向1开始顺序报数,报到m时停止。报m的人出圈,同时留下他的密码作为新的m值,从他在顺时针方向上的下一个人开始,重新从1开始报数,如此下去,直至所有的人全部出列为止。请在使用循环链表ADT的基础上,设计一个算法求出圈的顺序(以编号表示)。限定人数至少为1.

参考函数原型:

template

void Joseph(CirLinkList &A, int m);

//约瑟夫环专用结点类型

struct node{

int number;

int code;

};

输入说明 :

第一行:人数n

第二行:第一个人所持的密码

第三行:第二个人所持的密码

...

第n+1行:第n个人所持的密码

第n+2行:给定的随机数m

输出说明 :

第一行至第n行:建立的循环链表的遍历结果(一个结点占据1行)

第n+1行:空行

第n+2行:出圈的顺序(编号与编号之间以“->”分隔)

输入范例 :

7
3
8
1
22
4
9
15
5
输出范例 :

1 3
2 8
3 1
4 22
5 4
6 9
7 15

5->2->6->7->4->3->1

#include 
using namespace std;

template
struct LinkNode
{
    ElemType data;
    int number;
    LinkNode* next;
    LinkNode(LinkNode* ptr = NULL) { next = ptr; } //构造函数1,用于构造头结点
    LinkNode(const ElemType& item, LinkNode* ptr = NULL) //构造函数2,用于构造其他结点  
    //函数参数表中的形参允许有默认值,但是带默认值的参数需要放后面
    {
        next = ptr;
        data = item;
    }
    ElemType getData() { return data; }   //取得结点的数据域的值
    void SetLink(LinkNode* link) { next = link; }  //修改结点的next域
    void SetLink(ElemType value) { data = value; }   //修改结点的next域
};

//带头结点的循环单链表
template
class CirLinkList
{
private:
    LinkNode* head;   // 头结点
    LinkNode* tail;   // 尾结点
public:
    //无参数的构造函数
    CirLinkList() { head = new LinkNode; tail = head; head->next = head; }
    //带参数的构造函数
    CirLinkList(const ElemType& item) { head = new LinkNode(item); tail = head; head->next = head; }
    //拷贝构造函数
    CirLinkList(CirLinkList& List);
    //析构函数
    ~CirLinkList() { ListDestroy(); }
    //销毁链表
    void ListDestroy();
    //清空链表
    void ListClear();
    //返回链表的长度
    int ListLength() const;
    //判断链表是否为空表
    bool ListEmpty() const;
    //获取循环链表头结点
    LinkNode* GetHead() { return head; }
    //获取循环链表尾结点
    LinkNode* GetTail() { return tail; }
    //设置链表头结点
    void SetHead(LinkNode* p) { head = p; }
    //设置链表尾结点
    void SetTail(LinkNode* p) { tail = p; }
    //在链表的第pos个位置之后插入e元素
    bool ListInsert_next(int pos, ElemType e);
    //表头插入法动态生成链表
    void CreateList_Head(int n, ElemType* A);
    //表尾插入法动态生成链表
    void CreateList_Tail(int n, ElemType* A);
    //遍历链表
    bool ListTraverse() const;
};

template
void Joseph(CirLinkList& A, int m)
{
    int i, count, len=A.ListLength();
    LinkNode* p, *q;
    p = A.GetHead();
    q = p->next;
    for (i = 0;i < len;i++)
    {
        for (count = 1;count < m;p = q, q = q->next, count++)
        {
            if (q == A.GetHead())
            {
                p = q;
                q = q->next;
            }
        }
        if (q == A.GetHead())
        {
            p = q;
            q = q->next;
        }
        if (i != 0)cout << "->";
        cout << q->number;
        m = q->data;
        p->next = q->next;
        delete q;
        q = p->next;
    }
    cout << endl;
    A.GetHead()->next = A.GetHead();
    A.SetTail(A.GetHead());
}

int main()
{
    CirLinkLista, b;
    int n;
    int s[1000];
    cin >> n;
    for (int i = 0;i < n;i++)
        cin >> s[i];
    a.CreateList_Tail(n, s);
    a.ListTraverse();
    cout << endl;
    int m;
    cin >> m;
    Joseph(a, m);
}

//拷贝构造函数
template
CirLinkList::CirLinkList(CirLinkList& List)
{
    head = new LinkNode;
    LinkNode* p, * q, * r;
    r = head;
    for (p = List.head->next;p != List.head;p = p->next)
    {
        q = new LinkNode;
        q->data = p->data;
        r->next = q;
        r = q;
    }
    tail = r;
    tail->next = head;
}

//销毁链表
template
void CirLinkList::ListDestroy()
{
    //销毁以head为头指针的单链表,释放链表中所有结点空间
    LinkNode* p;
    while (head!=tail)
    {
        p = head;
        head = head->next;
        delete p;
    }
    delete tail;
    head = NULL;
    tail = NULL;
}

//清空链表
template
void CirLinkList::ListClear()
{
    //清空以head为头指针的单链表,释放原链表中结点空间,保留头结点
    LinkNode* p = head->next;
    while (p!=head)
    {
        head->next = p->next;
        delete p;
        p = head->next;
    }
    tail = head;
}

//返回链表长度
template
int CirLinkList::ListLength() const
{
    //返回链表的长度
    int length = 0;
    LinkNode* p;
    p = head->next;
    while (p!=head)
    {
        ++length;
        p = p->next;
    }
    return length;
}

//判断链表是否为空表
template
bool CirLinkList::ListEmpty() const
{
    //判断链表是否为空
    if (head->next == head) return true;
    return false;
}

//在链表的第pos个位置之前插入e元素
template
bool CirLinkList::ListInsert_next(int pos, ElemType e)
{
    if (pos > ListLength() || pos <= 0)return false;
    LinkNode* p, * q, * r;
    p = head->next;
    q = head;
    int i = 0;
    while (p!=head && pos != i)
    {
        i++;
        q = p;
        p = p->next;
    }
    r = new LinkNode;
    r->data = e;
    r->next = p;
    q->next = r;
    return true;
}

//表头插入动态生成链表
template
void CirLinkList::CreateList_Head(int n, ElemType* A)
{
    LinkNode* p;  //p为指向待插入结点的指针
    for (int i = 0; i < n; i++)
    {
        LinkNode p = new LinkNode;
        p->data = A[i];
        p->next = head->next;
        head->next = p;
        if (i == 0)
            tail = p;
        tail->next = head;
    }
}

//表尾插入动态生成链表
template
void CirLinkList::CreateList_Tail(int n, ElemType* A)
{
    LinkNode* r;  //r为指向尾结点的指针
    r = head;
    LinkNode* p;  //p为指向待插入结点的指针
    for (int i = 0; i < n; i++)
    {
        p = new LinkNode;
        p->data = A[i];
        p->number = i + 1;
        r->next = p;
        r = p;
    }
    r->next = head;
    tail = r;
}

//遍历链表
template
bool CirLinkList::ListTraverse() const
{
    LinkNode* p;
    p = head->next;
    for (;p != head;p = p->next)
        cout << p->number << " " << p->data << endl;
    return true;
}

你可能感兴趣的:(DHU28 循环链表ADT模板简单应用算法设计:约瑟夫环)