数三退一的问题解决(C语言和Java实现)

1 概述

数三退一的问题指的是一堆小朋友手牵手围成一个圈,从第一个小朋友到最后一个小朋友分别报数,报到数字“3”的小朋友要及时退出这个圈,剩下的人继续围成一个圈,然后从那个退出的小朋友的下一个开始重新从“1”开始报数,“1,2,3,1,2,3……”,直到圈中只剩下一人为止,求出剩下的这一人的编号。

2 问题决解

采用循环链表的方式进行解决,KidCircle基于循环链表实现把一个个kid连起来。首先从第一个Kid开始(即KidCircle的head成员)计数,Kid一直向后移动,数到3将调用删除方法将该Kid删除,并把计数器重置为0,直到KidCircle的size为1时,停止数数,打印出head的id即可。

3 代码实现

3.1 C语言

采用头文件公开一些公用方法和数据类型,具体实现的源代码文件和main函数文件分离

头文件kidcircle.h

/* kidcircle.h */

#ifndef KIDCIRCLE_H_
#define KIDCIRCLE_H_

/* DataType */
struct Kid_ {
	int id;
	struct Kid_ *left;
	struct Kid_ *right;
};
typedef struct Kid_ *Kid;

struct KidCircle_ {
	int size;
	Kid head, tail;
};
typedef struct KidCircle_ *KidCircle;

/* public interface */

/*
 * 功能:创建一个KidCircle类型 
 * 参数:无
 * 返回值:KidCircle 
 */
extern KidCircle new_kidcircle();

/*
 * 功能:在kc中增加指定数目num的孩子 
 * 参数:kc是已经初始化的 KidCircle类型的指针,num需要增加的孩子数目 
 * 返回值:无 
 */ 
extern void add_kid(KidCircle kc, int num);

/* 
 * 功能:使孩子K退出kc
 * 参数:kc是已经初始化的KidCircle类型的指针, k出队的孩子
 * 返回值:无 
 */
extern void del(KidCircle kc, Kid k);

/*
 * 功能:销毁动态申请的内存 
 * 参数:kc是已经初始化的 KidCircle类型的指针
 * 返回值:无 
 */ 
extern void dispose(KidCircle kc);

#endif

接口实现文件kidcircle.c

/* kidcircle.c */

#include <stdlib.h>
#include <stdio.h>
#include "kidcircle.h"

static Kid new_kid()
{
	static int cnt = 0;

	Kid k = (struct Kid_*)malloc(sizeof(struct Kid_));
	k->id = cnt++;
	k->left = NULL;
	k->right = NULL;

	return k;
}

static void dispose_kid(Kid k)
{
	free(k);
}

extern KidCircle new_kidcircle()
{
	KidCircle kc = (KidCircle)malloc(sizeof(struct KidCircle_));

	kc->size = 0;
	kc->head = NULL;
	kc->tail = NULL;
}

static void dispose_kidcircle(KidCircle kc)
{
	free(kc);
}

static void add(KidCircle kc)
{
	Kid k = new_kid();
	if (kc->size == 0) {
		kc->head = k;
		kc->tail = k;
		k->left = k;
		k->right = k;
	} else {
		k->right = kc->head;
		kc->head->left = k;
		kc->tail->right = k;
		k->left = kc->tail;
		kc->tail = k;
	}
	kc->size++;
}

extern void del(KidCircle kc, Kid k)
{
	if (kc->size == 0) {
		printf("the kidcircle has no kid");
		return;
	}
	if (kc->size == 1) {
		kc->head = kc->tail = NULL;
	} else {
		k->left->right = k->right;
		k->right->left = k->left;

		if (k == kc->head) {
			kc->head = k->right;
		} else if (k == kc->tail) {
			kc->tail = k->left;
		}
	}
	dispose_kid(k);
	kc->size--;
}

extern void add_kid(KidCircle kc, int num)
{
	int i;

	for (i = 0; i < num; i++) {
		add(kc);
	}
}

extern void dispose(KidCircle kc)
{
	Kid k = kc->head;

	while (kc->size > 0) {
		del(kc, k);
	}
	dispose_kidcircle(kc);
}

main函数文件main.c

#include <stdio.h>
#include <stdlib.h>
#include "kidcircle.h"

int main(int argc, char *argv[])
{
	KidCircle kc = new_kidcircle();
	add_kid(kc, 500);
	Kid k = kc->head;
	int cnt = 0;

	while (kc->size > 1) {
		cnt++;
		if (cnt == 3) {
			cnt = 0;
			del(kc, k);
		}
		k = k->right;
	}

	printf("%d", kc->head->id);
	
	dispose(kc);

	return 0;
}

3.2 Java语言

/* CountThree.java */
public class CountThree {
	public static void main(String[] args) {
		KidCircle kc = new KidCircle(500);
		int cnt = 0;
		//mark
		Kid k = kc.getHead();
		while (kc.getSize() > 1) {
			cnt++;
			if (cnt == 3) {
				kc.delete(k);
				cnt = 0;
			}
			k = k.getRight();
		}
		System.out.println(kc.getHead().getId());
	}
}

class Kid {
	private int id;
	private Kid left;
	private Kid right;

	public Kid(int id) {
		this.id = id;
	}

	public void setLeft(Kid k) {
		left = k;
	}

	public void setRight(Kid k) {
		right = k;
	}

	public int getId() {
		return id;
	}

	public Kid getLeft() {
		return left;
	} 

	public Kid getRight() {
		return right;
	}
}

class KidCircle {
	private int size = 0;
	private static int cnt = 0;
	private Kid head, tail;

	public KidCircle(int num) {
		for (int i = 0; i < num; i++) {
			add();
		}
	}

	public void add() {
		Kid k = new Kid(cnt);
		if (size == 0) {
			head = tail = k;
			k.setLeft(k);
			k.setRight(k);
		} else {
			/*tail.setRight(k);
			k.setRight(head);
			k.setLeft(tail);
			head.setLeft(k);
			tail = k;*/
			k.setRight(head);
			tail.setRight(k);
			head.setLeft(k);
			k.setLeft(tail);
			tail = k;
		}
		size++;
		cnt++;
	}

	public void delete(Kid k) {
/*		System.out.println(k.getId());
		System.out.println(size);*/
		if (size <= 0) {
			System.out.println("The KidCircle has no Kid!!!");
			return;
		}
		if (size == 1) {
			head = tail = null;
		} else {
			k.getLeft().setRight(k.getRight());
			k.getRight().setLeft(k.getLeft());

			//important
			if (k == head) {
				head = k.getRight();
			} else if (k == tail) {
				tail = k.getLeft();
			}
		}
		size--;
	}

	public int getSize() {
		return size;
	}

	public Kid getHead() {
		return head;
	}

	public Kid getTail() {
		return tail;
	}
}




  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值