约瑟夫环问题,多种方式处理

约瑟夫环问题,这是一个很经典算法

问题描述:N个人围成一圈,从第一个人开始报数,报到m的人出圈,剩下的人继续从1开始报数,报到m的人出圈;如此往复,直到所有人出圈。(模拟此过程,输出出圈的人的序号)


当初还没有学过数据结构,链表这些东西都没有听过,所以回去直接用c语言数组硬上做出来了.

有一个数组存贮着每个人的编号, 当数到3的时候把下标置为-1,表示已经移出了数组,然后到数组结束的位置在从头计数

#include 

void fun(int n)
{

    int a[n];
    int i = 0 ;
    for(i=0;i0){
            		printf("向后找到的下一个元素  %d\n",a[k]);
            		break;
            	}
            }
            
// 如果向后寻找失败,那就得从头开始继续找
        if(k==n){
	for(i=0;i0){
            		k=i;
            		printf("向前循环找到的下一个元素  %d\n",a[k]);
            		break;
           		}
            }
            
        }
        
        
        //判断能否结束循环
        j=0;
        for(i=0;i0){
                j++;
                
            }
        }
        printf("当前数组中有效的元素个数是 %d\n",j);
        //j==1,说明可以结束了,k中的就是那个唯一剩下的元素了
        if(j==1){
            printf("最终留下的数字是 %d\n",a[k]);
            break;
        }
    }
    
    
    
}


int main(void) {
    fun(10);
    return 0;
}

下面是log信息: 

1
2
3
4
5
6
7
8
9
10
当前的m=1   对应的元素  1
向后找到的下一个元素  2
当前数组中有效的元素个数是 10
当前的m=2   对应的元素  2
向后找到的下一个元素  3
当前数组中有效的元素个数是 10
当前的m=3   对应的元素  3
向后找到的下一个元素  4
当前数组中有效的元素个数是 9
当前的m=1   对应的元素  4
向后找到的下一个元素  5
当前数组中有效的元素个数是 9
当前的m=2   对应的元素  5
向后找到的下一个元素  6
当前数组中有效的元素个数是 9
当前的m=3   对应的元素  6
向后找到的下一个元素  7
当前数组中有效的元素个数是 8
当前的m=1   对应的元素  7
向后找到的下一个元素  8
当前数组中有效的元素个数是 8
当前的m=2   对应的元素  8
向后找到的下一个元素  9
当前数组中有效的元素个数是 8
当前的m=3   对应的元素  9
向后找到的下一个元素  10
当前数组中有效的元素个数是 7
当前的m=1   对应的元素  10
向前循环找到的下一个元素  1
当前数组中有效的元素个数是 7
当前的m=2   对应的元素  1
向后找到的下一个元素  2
当前数组中有效的元素个数是 7
当前的m=3   对应的元素  2
向后找到的下一个元素  4
当前数组中有效的元素个数是 6
当前的m=1   对应的元素  4
向后找到的下一个元素  5
当前数组中有效的元素个数是 6
当前的m=2   对应的元素  5
向后找到的下一个元素  7
当前数组中有效的元素个数是 6
当前的m=3   对应的元素  7
向后找到的下一个元素  8
当前数组中有效的元素个数是 5
当前的m=1   对应的元素  8
向后找到的下一个元素  10
当前数组中有效的元素个数是 5
当前的m=2   对应的元素  10
向前循环找到的下一个元素  1
当前数组中有效的元素个数是 5
当前的m=3   对应的元素  1
向后找到的下一个元素  4
当前数组中有效的元素个数是 4
当前的m=1   对应的元素  4
向后找到的下一个元素  5
当前数组中有效的元素个数是 4
当前的m=2   对应的元素  5
向后找到的下一个元素  8
当前数组中有效的元素个数是 4
当前的m=3   对应的元素  8
向后找到的下一个元素  10
当前数组中有效的元素个数是 3
当前的m=1   对应的元素  10
向前循环找到的下一个元素  4
当前数组中有效的元素个数是 3
当前的m=2   对应的元素  4
向后找到的下一个元素  5
当前数组中有效的元素个数是 3
当前的m=3   对应的元素  5
向后找到的下一个元素  10
当前数组中有效的元素个数是 2
当前的m=1   对应的元素  10
向前循环找到的下一个元素  4
当前数组中有效的元素个数是 2
当前的m=2   对应的元素  4
向后找到的下一个元素  10
当前数组中有效的元素个数是 2
当前的m=3   对应的元素  10
向前循环找到的下一个元素  4
当前数组中有效的元素个数是 1
最终留下的数字是 4

上面是纯C语言搞出来的,但是oc中有可变数组,用可变数组就方便多了, 移出的操作方便了很多,计数的时候也是考虑到结尾处需要置为起始位置.


#import "ViewController.h"

@interface ViewController ()

// 用数组操作比c语言方便多了
@property (nonatomic, strong) NSMutableArray *array;

@end

@implementation ViewController



- (void)viewDidLoad {
    [super viewDidLoad];
    
    /// 假设此处的步长为4
    NSInteger m = 4;
    
    NSInteger index = 0;
    while (self.array.count>1) {
        
        index +=m-1;
        if (index >= self.array.count) {
            index = index%self.array.count;
        }
 
        NSLog(@"即将移除 %@",self.array[index]);
        [self.array removeObjectAtIndex:index];
        
        
    }
    NSLog(@"最后一个元素 : %@",self.array.firstObject);
    
}


- (NSMutableArray *)array {
    if (_array == nil) {
        _array = [NSMutableArray array];
        
        for (int i = 1; i<=10; i++) {
            [_array addObject:@(i)];
        }
        
    }
    return _array;
}

@end

约瑟夫环问题,多种方式处理_第1张图片


还可以使用队列, 一开始建一个队列存贮所有的下标, 然后前m-1个出队加入到队尾,第m个出队后丢弃,不断循环,直到队列中一个元素都没有


#import "ViewController.h"

@interface ViewController ()

//模拟队列
@property (nonatomic, strong) NSMutableArray *array;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    
      /// 假设此处的步长为4
    NSInteger m = 4;
    
    NSInteger index = 0;// 统计步长
    while (self.array.count > 0) {
        
        
        index ++ ;
        // 如果是第m个,丢弃
        if (index == m) {
            NSLog(@"即将移除 %@",self.array.firstObject);
            [self.array removeObjectAtIndex:0];
            index = 0;
            continue;
        }
        // 0到m-1个,模拟队列操作,从队头移除,加入到队尾
        NSObject * obj = self.array.firstObject;
        [self.array addObject:obj];
        [self.array removeObjectAtIndex:0];
        
    }
    
      
}

- (NSMutableArray *)array {
    if (_array == nil) {
        _array = [NSMutableArray array];
        
        for (int i = 1; i<=10; i++) {
            [_array addObject:@(i)];
        }
        
    }
    return _array;
}


@end

约瑟夫环问题,多种方式处理_第2张图片


最后放上最正统的循环链表, 把最后一个的next指向首节点,根据步长循环,直到只剩下一个元素


#import 

typedef struct Node{
    int data;
    struct Node * next;
} Node;

int main(int argc, char * argv[]) {
    
    Node * first = malloc(sizeof(Node));
    first->data = 1;
    
    Node * preNode = first;
    // 生成其他节点
    for (int i= 2; i<=10; i++) {
        Node * next = malloc(sizeof(Node));

        next->data = i;
        preNode->next = next;
        preNode = next;
        
    }
    
    /// 把最后一个元素的next指向第一个,形成循环链表
    preNode->next = first;
    
    // 假定步长为4
    NSInteger m = 4;
    Node * temp = first;
    // 链表中还剩下10个元素
    NSInteger leftNum = 10;
    while (leftNum>0) {
        
        // 向前走m-1步,退出循环的时候,temp就是被移除节点的前一个节点,
        for (int i = 1; inext;
        }
        Node * removeNode = temp->next;
        NSLog(@"即将移除 %d",removeNode->data);
        temp->next = removeNode->next;
        free(removeNode);
        leftNum--;
        temp = temp->next;

    }
    
}

约瑟夫环问题,多种方式处理_第3张图片

c语言写算法,真心有点累,还是oc好点

@interface Node : NSObject

+ (Node *)nodeWithArray:(NSArray *)array;

@property (nonatomic, assign) int data;
@property (nonatomic, strong) Node *next;

@end

----------------

#import "Node.h"

@implementation Node

+ (Node *)nodeWithArray:(NSArray *)array {
    
    if (array.count==0) {
        return nil;
    }
    
    Node * first = [[Node alloc] init];
    first.data = [array.firstObject intValue];
    Node * preNode = first;
    for (int i = 1; i0) {
        
        for (int i = 1; i

约瑟夫环问题,多种方式处理_第4张图片

个人最喜欢第二种和队列的方式, 代码好理解很多, 循环链表这个会产生循环引用, 要小心

你可能感兴趣的:(数据结构和算法)