数据结构与算法---复习:尤瑟夫问题 线性表解决

数据结构与算法—复习:尤瑟夫问题 线性表解决

在这里就不概述什么是尤瑟夫问题了,一般的数据结构教材里都有这道题。下面给出关于本问题的线性表解法。

解题方式

模拟报数:这种方式更适合于单循环链表,用一个计数器记下当前报数的大小,再用一个指针指向规定的报数起点。循环删除链表直到链表为空。因为是循环链表所有操作方便。这种方式的复杂度经过计算是O(n * m);
推演数列:通过写出一个简单数列的报数结果,并且给出对应的数组下标,可以容易的推理出下标与报数最大值还有当前桌子上人的总数的关系。即:
(当前下标+报数目标-1)%当前总人数 = 下一个报数出列的人的下标
需要深刻的理解取余运算的作用。我个人理解,他和循环转圈有一定的关系。

下面给出程序片段代码:

/**
 * Josephus  尤瑟夫问题
 * 设n个人,坐在一个圆桌,现在从第s个人开始报数,要求报数从1开始,一直到m,报数报到m
 * 的人出列,要求得到n个人员的数列
 * 算法思想:
 * 观察出队下标,可以总结出规律:(当前下标+报数目标-1)%当前总人数 = 下一个报数出列的人
 * 例如,给定一桌人:
 * 1 2 3 4 5 他们的下标:
 * 0 1 2 3 4 如果指定3号人物,开始报数,报到2就出列,则下一个出列的人是4,以此类推,最终报数出列的人顺序是:
 * 4 1 3 2 5 他们的对应下标是:
 * 3 0 2 1 4 则可以推导出:(当前下标+报数目标-1)%当前总人数 = 下一个报数出列的人
 * 取余操作大概跟转圈之类的操作有关
 */
#include 
#include 

/**
 * 线性表结构定义
 */
struct SeqList{
    int MAXNUM; //表明线性表最大长度
    int n;  //表明线性表当前存储元素个数
    int* vals;  // DataType* X;
};
typedef struct SeqList * PSeqList; //定义一个指向SeqList的指针类型

/**
 * 1.创建一个空的线性表
 * @param m 线性表长度
 * @return
 */
PSeqList createNullList_Seq(int m){
    PSeqList palist = (PSeqList)malloc(sizeof(struct SeqList));
    if(palist != NULL){
        palist->vals = (int*)malloc(sizeof(int) * m);
        if(palist->vals){
            palist->n = 0;
            palist->MAXNUM = m;
            return palist;
        } else{
            free(palist);
        }
    }
    printf("创建线性表时分配空间失败\n");
    return NULL;
}

/**
 * 2.判断线性表是否为空
 * @param palist
 * @return
 */
int isNullList_Seq(PSeqList palist){
    if(palist->n == 0)
        return -1;
    else
        return 0;
}

/**
 * 3.输入数据,找出该数据位于线性表的下标
 * @param palist
 * @param x
 * @return
 */
int locate_seq(PSeqList palist,int x){
    if(isNullList_Seq(palist))
        return -1;
    for(int i=0;i<palist->n;i++)
    {
        if(palist->vals[i] == x)
            return i;
    }
    return -1;
}

/**
 * 4.对指定的下标数据前,插入数据
 * @param palist
 * @param position
 * @param x
 * @return
 */
int insertPre_seq(PSeqList palist, int position,int x){
    if(isNullList_Seq(palist))
        return -1;
    if(palist->MAXNUM <= position){
        printf("插入时,下标超过最大值\n");
        return -1;
    }
    if(position<0 || position>palist->n){
        printf("不存在下表为%d的元素\n",position);
    }
    for(int i = palist->n; i>=position; i--)
    {
        palist->vals[i] = palist->vals[i-1];
    }
    palist->vals[position] = x;
    palist->n += 1;
    printf("插入成功\n");
    return 1;
}

/**
 * 5.删除指定下标的元素
 * @param palist
 * @param position
 * @return
 */
int deleteP_seq(PSeqList palist,int position){
    if(isNullList_Seq(palist)){
        printf("线性表为空,无法删除\n");
        return -1;
    }
    if(position > palist->n || position < 0){
        printf("当前线性表不存在下标为%d的数据,无法删除\n",position);
        return -1;
    }
    for(int i = position; i<palist->n;i++){
        palist->vals[i] = palist->vals[i+1];
    }
    palist->n -= 1;
    printf("删除成功\n");
    return 1;
}

/**
 * 6.查找元素的删除方法
 * @param palist
 * @param x
 * @return
 */
int deleteV_seq(PSeqList palist,int x){
    if(isNullList_Seq(palist)){
        printf("线性表为空,无法删除\n");
        return -1;
    }
    if(locate_seq(palist,x) == -1){
        printf("元素不存在,无法删除\n");
        return -1;
    }
    deleteP_seq(palist,locate_seq(palist,x));
    printf("删除成功\n");
    return 1;
}

/**
 * 7.初始化数据的方法
 * @param palist
 * @param data
 */
void initData(PSeqList palist,int data[]){
    for(int i=0;i<11;i++)
    {
        palist->vals[i] = data[i];
        (palist->n)++;
    }
}

/**
 * 8.线性表打印方法
 * @param palist
 */
void printSeqList(PSeqList palist){
    if(isNullList_Seq(palist)){
        printf("线性表为空,无法打印\n");
        return;
    }
    for(int i=0;i<palist->n;i++){
        printf("%d,",palist->vals[i]);
    }
    printf("\n");
}


void Josephus(PSeqList palist,int s,int m){
    int s1,i,w;
    s1 = s - 1;
    for(i=palist->n;i>0;i--){
        s1 = (s1 + m - 1) % i;
        w = palist->vals[s1];
        printf("第%d号出列;",w);
        deleteP_seq(palist,s1);
    }
}

int main(){
    int man[] = {1,2,3,4,5,6,7,8,9,10,11};
    PSeqList palist = createNullList_Seq(100);
    initData(palist,man);
    Josephus(palist,4,4);
}

欢迎批评指正

你可能感兴趣的:(大学生)