打印一个字符串(长度不确定)的全字符组合情况,原始字符串中没有重复字符

import java.util.Arrays;
/**
 * 题目要求:
 * 打印一个字符串(长度不确定)的全字符组合情况,原始字符串中没有重复字符
       例如:原始字符串是"def", 打印得到下列所有组合情况:
   "d" "e" "f" "de" "df" "ed" "ef" "fd" "fe" "def" "dfe" "edf" "efd" "fde" "fed"
 * @author Hs
 *
 */
public class T1 {
	public static void main(String[] args) {
		// 定义一个字符串
		String s = "abcd";
		// 把字符串中每一个字符拿出来,放进字符串数组
		char[] dataChar = s.toCharArray();// 先变成char数组
		String[] datas = new String[dataChar.length];
		// char转化为String
		for (int i = 0; i < datas.length; i++) {
			datas[i] = String.valueOf(dataChar[i]);
		}
		
		// new 一个根节点,根节点并没有数据,目的是为了能遍历到树中的所有数据,需要单根结构树.
		// 因为cell类的构造器本身是一个递归函数,所以new root完成时,已经把所有数据作为节点,创建了一个树出来.
		// 所有的情形已经储存在树中
		// 剩下的只是遍历所有的情况
		Cell root = new Cell(datas);// datas中没有数据是递归结束的信号

		for(int i =1;i<=s.length();i++) {
			Cell.view(root, i);
		}
	}
}

/**
 * 1 节点类Cell. 
 * 2 树结构中的节点 拥有指针指向父节点father,子节点son,和下一个兄弟节点brother 还有一个floor.
 * 3 用来储存该节点处在树结构的第几层.
 * 
 * @author Hs
 *
 */
class Cell {
	public int floor;// 在树中的层数
	public String data;// 存放具体数据
	public Cell father;// 指向父节点
	public Cell brother;// 指向下一个(相邻的)兄弟节点
	public Cell son;// 指向子节点
	public String[] sonRest;// sonRest数组,用来存放这一分支中,到此节点为止,所剩数据(已经删掉this对象中的data)
	public String[] broRest;// broRest数组,类似于上面,用来存放这一行所剩数据

	/**
	 * 这个构造器只调用一次,用来new root节点 
	 * 所以他只有son有指向,father和brother都是null floor为0 data为null
	 * 因为data为空,所以sonRest和broRest不需要删除数据,等于s
	 * 
	 * @param s 用户给出的字符串拆分成的数组,最原始的数据
	 */
	public Cell(String[] s) {
		floor = 0;
		data = null;
		father = null;
		brother = null;
		//因为data为空,所以sonRest和broRest不需要删除数据,等于s
		sonRest = Arrays.copyOf(s, s.length);
		broRest = Arrays.copyOf(s, s.length);
		//找到sonRest数组中第一个不为空数据,作为son的data
		for (int i = 0; i < sonRest.length; i++) {
			if (sonRest[i] != null) {
				//son的floor要比this+1,father是this本身,data略,sonRest和broRest传递给son,此时的数据数组中并没有删除son已经用掉的数据
				son = new Cell(floor + 1, this, sonRest[i], broRest,true);
				break;
			}
		}
	}

	/**
	 * 另一个构造器,递归直到数据数组中不再有数据,至结束 所有cell对象一起组成一个逻辑树结构
	 * 
	 * 7个成员变量中有4个需要传递过来的参数赋值,其中floor,father,broRest只能由兄弟节点或者父节点穿来,否则this无从得知信息
	 * sonRest 可以通过father调出来
	 * data 也只能在父节点或者兄弟节点中确定 传给this,因为this本身并不知道谁(父/bro)new的自己,所以不知道从哪个数据组中提取数据,而且(父/bro)必须知道有没有数据用来new新的cell,来判断是否让son或father指向空
	 *
	 * 
	 */
	public Cell(int floor, Cell father, String data, String[] broRest,boolean isSon) {
		this.floor = floor;
		this.father = father;
		this.data = data;
		// 删除sonRest中 被this用过的data
		String[] newSonRest = Arrays.copyOf(father.sonRest, father.sonRest.length);
		for (int i = 0; i < newSonRest.length; i++) {
			if(newSonRest[i]!=null) {
				if (newSonRest[i].equals(data)) {
					newSonRest[i] = null;
					break;
				}
			}
		}
		// 删除broRest中 被this用过的data
		String[] newBroRest = Arrays.copyOf(broRest, broRest.length);
		for (int i = 0; i < newBroRest.length; i++) {
			if(newBroRest[i]!=null) {
				if (newBroRest[i].equals(data)) {
					newBroRest[i] = null;
					break;
				}
			}
		}
		//使用删除数据后的数据组作为this的剩余数据组
		this.sonRest = newSonRest;
		this.broRest = newBroRest;
		if(isSon) {
			this.broRest = Arrays.copyOf(newSonRest, newSonRest.length);
		}
		// 判断sonRest中是否还有数据,如果有就让son指向一个新的cell,如果没有就指向空
		boolean flag1 = true; // 如果for正常结束 依然为true 证明 sonRest数组中已经没有数据
		for (int i = 0; i < newSonRest.length; i++) {
			if (newSonRest[i] != null) {
				this.son = new Cell(floor + 1, this, newSonRest[i], this.broRest,true);// 因为是son 所以floor+1,father是this
				flag1 = false;
				break;
			}
		}
		if (flag1) {
			this.son = null;// 如果数组中没数据,son指向null
		}
		// 判断broRest中是否还有数据,如果有就让brother指向一个新的cell,如果没有就指向空
		boolean flag2 = true; // 如果for正常结束 依然为true 证明 broRest数组中已经没有数据
		for (int i = 0; i < this.broRest.length; i++) {
			if (this.broRest[i] != null) {
				this.brother = new Cell(floor, this.father, this.broRest[i], this.broRest,false);// 因为是brother 所以floor不变,father是this.father
				flag2 = false;
				break;
			}
		}
		if (flag2) {
			this.brother = null;// 如果数组中没数据,指针指向null
		}
	}

	@Override
	public String toString() {
		if(data!=null) {
			return data;
		}else {
			return "";
		}
	}
	
	/**
	 * 递归遍历函数
	 * @param root 根节点
	 * @param size 遍历的层数,这是递归结束的唯一信号
	 */
	static void view(Cell root,int size) {
		if(root!=null) {
			if(root.floor==size) {
				System.out.println(getInfo(root));
			}else {
				view(root.son, size);
			}
			
			if(root.brother!=null) {
				view(root.brother, size);
			}
		}
	}
	
	static String getInfo(Cell c) {
		if(c.father!=null) {
			return getInfo(c.father)+c;
		}else {
			return c.toString();
		}
	}

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值