- 顺序表
- 循环链表(不带头节点)
值得注意的是,其实两种方法都是利用了循环的结构,想象成一个时钟的表盘
1.顺序表
较为简单,以下代码:
/*
约瑟夫问题的顺序表实现
author: Qian Jipeng(C)
date: 2019-3-21
*/
#include <stdio.h>
#include <stdlib.h>
#define maxsize 100
typedef struct node
{
int data[maxsize];
int length;
}SeqList, *PSeqList;
/* 初始化 */
PSeqList Init(){
PSeqList L;
L = (PSeqList)malloc(sizeof(SeqList));
if (L){
L->length = 0;
}
return L; /* 返回顺序表指针 */
}
/* 插入 */
int InSeqList(PSeqList L, int i, int e){
if(i < 1 || i > L->length+1 || L->length >= maxsize){
printf("插入失败!\n");
return 0;
}
else{
int j;
L->data[i-1] = e;
for (j=L->length; j>=i; j--){
L->data[j] = L->data[j-1]; /* 依次往后移动 */
}
L->length ++;
}
return 1;
}
/* 删除 */
int DelSeqList(PSeqList L, int i, int *x){
if ( i < 1 || i > L->length){
printf("删除位置不合法\n");
return 0;
}
int j;
int tmp; // 保存将被删除的元素
tmp = L->data[i-1];
for (j = i ; j <= L->length; j++ ){ // 从第I 个开始往前移动一位
L->data[j-1] = L->data[j];
}
L->length --;
//printf("删除第 %d 个位置元素 %d 成功!\n", i, tmp);
return 1;
}
// 功能函数 s 开始, 数到 m
int yusefu_SeqList(PSeqList L, int s, int m){
int x;
int i;
int s1;
int w; // 保存删除的元素
if( L-> length == 0){
printf("表空!\n");
return 0;
}
s1 = s -1;
// 依次出去
for (i = L->length; i > 0; i--){
/* 关键步骤 */
s1 = (s1+m-1) % i;
w = L -> data[s1]; // 下标 s1, 是第s1+1 个元素!!!
DelSeqList(L, s1+1, &x);
printf("出列: %d\n", w);
}
return 1;
}
int main(){
int len; // 序列长度
int num[maxsize]; // 用来存输入的数
PSeqList L = (PSeqList)malloc(sizeof(SeqList));
printf("输入序列元素个数: ");
scanf("%d", &len);
printf("输入约瑟夫序列(空格分开): ");
// 依次插入
for (int l = 0; l < len; l++ ){
scanf("%d", &num[l]);
InSeqList(L, l+1, num[l]);
//printf(" %d ", num[l]);
}
yusefu_SeqList(L, 2, 5);
return 0;
}
2.循环链表
这里的循环链表是没有头结点的,为了操作方便,否则每每循环到头结点还要跳过这个头结点,我的做法是:
1. 先把第一个元素放入第一个节点(即首元节点),只有数据域,指针域置空
2. 接着用个循环,创建剩下的单个节点,同样只有数据域
3. 再把这些节点连接起来
代码如下:
/* 约瑟夫问题的循环链表实现
* author: Qian Jipeng(C)
* date: 2019-3-24
* version: 2.0(1.0 aborted for too complexed)
*/
#include <stdio.h>
#include <stdlib.h>
/* node definition */
typedef struct node{
int data;
struct node * next;
}linklist;
/*
\brief: crate the linklist and do insert, return the first node's ptr
\param: n ->> the size of the serises
\return: the first node's ptr
*/
/* creat the node in range(1, n)*/
linklist * initLink(int n){
linklist * head = (linklist*)malloc(sizeof(linklist));
/* the first node initionalized (not head node)*/
head->data = 1;
head->next = NULL;
/* a ptr to move through the list */
linklist * tmp = head;
/* we satrt with the second node for a loop */
for (int i = 2; i <= n; i ++) {
linklist * body = (linklist*)malloc(sizeof(linklist));
/* creat and init single node */
body -> data = i;
body -> next = NULL;
/* connect the single nodes together */
tmp -> next = body;
tmp = tmp -> next;
}
//printf("%d\n", tmp->data);
/* now tmp is just the last node */
tmp -> next = head; /*connect the head and the rear */
return head;
/* by this method, we created a loop linklist */
}
void yusefu(linklist * head,int k,int m){
linklist * tail = head;
//找到链表第一个结点的上一个结点,为删除操作做准备
while (tail -> next != head) {
tail = tail -> next;
}
linklist * p = head;
//找到编号为k的人(或者是第几个开始,可以改)
while (p -> data != k) {
tail = p;
p = p->next;
}
//从编号为k的人开始,只有符合p->next==p时,说明链表中除了p结点,所有编号都出列了,
while (p -> next != p) {
//找到从p报数1开始,报m的人,并且还要知道数m-1de人的位置tail,方便做删除操作。
for (int i = 1; i < m; i ++) {
tail = p;
p = p -> next;
}
tail->next=p->next;//从链表上将p结点去除
printf("%d \t",p -> data);
free(p);
p = tail -> next;//继续使用p指针指向出列编号的下一个编号
}
/* the last one */
printf("%d \n",p -> data);
free(p);
}
int main() {
linklist * head=initLink(10);
yusefu(head, 2, 5);
return 0;
}