递归实现排列

先给大家讲一个故事:

这是一个风云变幻的时代,几个字母争先恐后的抢着做老大,但是姜还是老的辣,经过一番折腾,最后的最后,几个字母还是回到最初的样子,坐回他们原来的位置,一起干回他们原来的事情——(构成一个完整的"单词"),老大还是那个老大...

(啊...真是一个有趣的故事...手动滑稽)

 

为了让大家更好的理解,我将4个字母构成的单词(不一定是真正的单词,只要由四个字母构成,我们在这里就把它叫做单词)前面部分进行详细讲解,后面的以此类推:

例子:abcd

这是一个逆向过程

知道d(一个字母无法进行交换,不打印)→ 推到cd(执行打印操作,随后进行前移操作),

[暂且看起来执行的像是交换操作,其实到后面就可以看出来是前移操作了]

前移过程:将c后面的字母d往前移,把字母c放在最后面,构成dc

执行完前移rotate方法后,仍在循环体内,所以仍在dc中(前面已经完成了前移操作),执行打印操作,然后再进行前移操作,

前移过程:将d后面的字母c往前移,把字母d放在最后面,构成cd

此时你会发现又变回了abcd,两次前移操作相当于没有进行前移操作。

跳出循环:推到bcd→因为长度不为2故不执行打印工作(长度不为2时,相当于还保留着上一轮的"单词",前面说过进行两次前移操作相当于没有操作,如果我们这时候打印,就回造成重复)→ 进行前移操作

前移过程:将b后面的字母c跟d往前移,把字母b放在最后面,构成cdb

此时仍在循环体内:重复上一轮操作,具体如下:

 

cdb → db → b [return]

知道b(一个字母无法进行交换,不打印)→ 推到db(执行打印操作,进行前移操作),

[暂且看起来执行的像是交换操作,其实到后面就可以看出来是前移操作了]

前移过程:将d后面的字母b往前移,把字母d放在最后面,构成bd

执行完前移rotate方法后,仍在循环体内,所以仍在bd中(前面已经完成了前移操作),执行打印操作,然后再进行前移操作,

前移过程:将b后面的字母d往前移,把字母b放在最后面,构成db

此时你会发现又变回了acdb,两次前移操作相当于没有进行前移操作。

跳出循环:推到cdb→因为长度不为2故不执行打印工作(长度不为2时,相当于还保留着上一轮的"单词",前面说过进行两次前移操作相当于没有操作,如果我们这时候打印,就回造成重复)→ 进行前移操作

前移过程:将c后面的字母d跟b往前移,然后把字母c放在最后面,构成dbc

 

随后又进行一次上述的循环,最后回到bcd原来的模样,为什么呢?

(其实就是我们的前移操作,不断将第一个字母的后面往前移动,然后将第一个字母放到最后一个位置上面)

初始模样:bcd

上述在3个字母的时候进行了3次操作,把b移动到d的位置,让c做了头头即cdb

然后:

b又移动到了初始模样c的位置,让d做了头头,即dbc

然后:

b又移动到了初始模样b的位置,再次做上了头头,即bcd

 

经历完上述操作,相信可以看懂以下流程:

doAnagram(1) → doAnagram(2) → doAnagram(3) → doAnagram(4)

到了doAnagram(4)这里,我们又执行类似上述的工作,将a后面的字母往前移,把字母a放到最后的位置,每个字母抢着做老大,显然背后是你敲代码动了手脚让他们这样干的,这样一轮轮的前移,仍然会回到原来的模样abcd(真是有够折腾的)

 

下面是附注释代码:

import java.io.*;

public class Anagram {
	static int size;//"单词"长度
	static int count;//变换个数
	static char[] arrChar = new char[100];//存放"单词"字母的数组
	
	public static void main(String args[]) throws IOException{
		System.out.println("Enter a word: ");//提示
		String input = getString();	//输入一个"单词"
		size  =input.length();//获取"单词"长度
		count = 0;			//初始化变换个数count为0
		for(int j=0;j<size;j++)
			arrChar[j] = input.charAt(j);//将"单词"字母存放于数组中
		doAnagram(size);				//进行变换
	}
	
	public static void doAnagram(int newSize) {
		if(newSize==1) //递归的出口:当一直缩减的"单词"长度为1时,返回。(无需做变换)
			return;
		for(int j=0;j<newSize;j++) {//进行递归操作
			doAnagram(newSize-1);
			if(newSize==2)		//当只有两个字母的时候打印,只有两个字母需执行前移操作,需要打印
				displayWord();
			rotate(newSize);//进行前移工作
		}
	}
	
	public static void rotate(int newSize) {
		int j;
		int position = size - newSize;//得到此时"单词"的第一个位置
		char temp = arrChar[position];			
		for(j=position+1;j<size;j++)//前移
			arrChar[j-1] = arrChar[j];
		arrChar[j-1] = temp;//将原先的第一个字母放到最后的位置
	}
	
	
	//打印单词
	public static void displayWord() {
		if(count<99)			//有这些空壳只是为了让打印出来的表格看起来漂亮一点
			System.out.print(" ");//如果你不在意的话完全可以不用这样做
		if(count<9)
			System.out.print(" ");
		System.out.print(++count+":");
		for(int j=0;j<size;j++)
			System.out.print(arrChar[j]);
		if(count%6==0)
			System.out.println();
	}
	
	//输入单词,输入的方法,Java基础--I/O流部分
	public static String getString() throws IOException{
		InputStreamReader isr = new InputStreamReader(System.in);
		BufferedReader br = new BufferedReader(isr);
		String s = br.readLine();
		return s;
	} 
}	

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值