黑马程序员技术博客之字符串的组合与排列

----------- android培训java培训、java学习型技术博客、期待与您交流! ------------

这个其实也是我做的一道基础测试题,这道题给我感觉还是蛮难的,我也是看了网上关于全排列的递归算法之后才写出来的,我觉得把这个小程序搞懂了,递归基本也就弄明白了,写这个程序的时候还是费了点劲的。如果哪位仁兄有更好的方法还望@我

import java.util.Enumeration;
import java.util.Stack;

/**
 * 第6题:编程列出一个字符串的全字符组合情况,原始字符串中没有重复字符
 * 例如:原始字符串是"abc",打印得到下列所有组合情况
 * "a" "b" "c"
 * "ab" "bc" "ca" "ba" "cb" "ac"
 * "abc" "acb" "bac" "bca" "cab" "cba"
 * 
 * 程序说明:
 * 1、程序大致可以分为两个部分,组合、排列
 * 2、先求出字符串的全部组合
 * 3、而后,分别对这些组合进行全排列
 * 4、该程序无法应对重复字符的情况
 * 
 * @author shine
 *
 */
public class Test6 {
	//创建静态变量以便函数间交换数据
	static String[][] stringss;
	static String[] strings;
	static int index;
	//主函数,世界从这里展现
	public static void main(String[] args){
		String stringsmain = "abcd";
		char[] chars = stringsmain.toCharArray();
		stringss = new String[chars.length][];
		combiantion(chars);//调用combination方法,找到组合,并存储在string[][]中
		//遍历stringss[][]数组
		for(int indexout=0; indexout<stringss.length; indexout++){
			for(int indexin=0; indexin<stringss[indexout].length; indexin++){
				char[] arr = stringss[indexout][indexin].toCharArray();
				permutation(arr, 0, arr.length);//将组合传入permutation方法,并进行全排列
			}
			System.out.println();
		}
	}
	//该方法用于求解字符串的全部组合
	public static void combiantion(char[] chs){
   		if(chs.length == 0)
			return;
		Stack<Character> stack = new Stack<Character>();
		for(int i = 1; i <= chs.length; i++){
			int num = factorial(chs.length)/(factorial(i)*factorial(chs.length-i));
			//求出不同字符串,不同长度下的组合的数量num
			strings= new String[num];
			index = 0;
			//调用combine方法,求该字符串长度为i时的组合情况,并将数据保存到strings数组中
			combine(chs, 0, i, stack);
			stringss[i-1] = strings;
		}
	}
	//定义num的阶乘
	public static int factorial(int num){
		int result = 1;
		for(;num>=1;num--){
			result *=num;
		}
		return result;
	}
	//该方法用于求解字符串在长度为number时的组合情况,主要利用了递归思想
	public static void combine(char[] chars, int begin, int line, Stack<Character> stack){
		//定义跳出递归的条件
		if(line == 0){
			Enumeration<Character> enumer = stack.elements();
			strings[index] = "";
			while(enumer.hasMoreElements()){
					strings[index] += enumer.nextElement().toString();
			}
			index++;
			return;
		}
		if(begin == chars.length){
			return;
		}
		stack.push(chars[begin]);//利用堆栈缓存数据
		combine(chars, begin+1, line-1, stack);
		stack.pop();
		combine(chars, begin+1, line, stack);
	}
	/**
	 * combine方法实现过程分析:
	 * 为简化问题,假设需要排序的字符串是“abc”
	 * 单个字符,对应后面排列后显示的第一行:
	 * 	begin=0, line=1 , chars.length=3
	 ****** 首先,将a存入stack中,而后调用combine(chars,begin+1,line-1,stack)开始递归
	 * 			begin=1, line=0 , ....= 3  ==>  line==0,读取stack中的a-------, index++,return
	 * 		stack.pop() 情空缓存的a
	 * 			调用combine(chars,begin+1,line,stack)
	 * 			begin=1, line=1....
	 * 			chars[begin]=chars[2]=b  被存入stack
	 * 				begin=2, line=0.....输入b-------
	 * 			清空缓存b
	 * 			begin=2, line=1....
	 * 				缓存c
	 * 					begin=3, line=0....
	 * 						输出c----------
	 * 				清空c
	 * 					begin=3, line=1....begin==chars.length..==>   return
	 * 			return回到第二层是}。。。。继续回到第一层,依然是}==>程序结束,
	 * 完成第一行输出:a, b, c	继续combiantion中的for循环==>开始第二行
	 ****** 两个字符,对应第二行:
	 *  begin=0, line=2
	 *  	存储a。。。
	 *  		begin=1, line=1
	 *  		存储b。。。
	 *  			begin=2, line=0  ==>输出  ab  return------
	 *  		清空b
	 *  			begin=2, line=1
	 *  			存储c。。
	 *  				begin=3, line=0  ==>输出  ac	return-----
	 *  			清空c。。
	 *  				begin=3, line=1  ===> return
	 *  			}
	 *  		},再次后退,回到第一层
	 *  	清空a。。。
	 *  		begin=1,line=2
	 *  		缓存b。。。此时b放在了第一位
	 *  			begin=2,line=1
	 *  			读取c。。。
	 *  				begin=3,line=0  ==>输出bc  return------
	 *  			清空c。。。
	 *  				begin=3,lin=1 ==>return
	 *  			}
	 *  		清空b。。。
	 *  			begin=2,line=2
	 *  			读取c。。。此时c放在了第一位
	 *  				begin=3,line=1  ==>return
	 *  			清空c。。。
	 *  				begin=3,line=1  ==》retuen
	 *  			}
	 *  		}
	 *  	}程序结束,进入下一个for循环,开始三个字符的组合
	 *******  				
	 *三个元素的情况
	 *	begin=0, line=3
	 *	缓存a
	 *		begin=1,line=2
	 *		缓存b
	 *			begin=2,line=1
	 *  			缓存c
	 *  				begin=3,line=0  	输出abc	return
	 *  			清空c
	 *  				begin=3,line=1  return
	 *  			}
	 *  	清空b
	 *  		begin=2,line=2
	 *  		读取c
	 *  			begin=3,line=1  ==>return
	 *  		清空才
	 *  			begin=3,line=2  ==>return
	 *  		}
	 *  	}
	 *  清空a
	 *  	begin=1,line=3  ==>return
	 *  }
	 *  程序就此结束,完成全部组合的获取
	 *  		
	 * 全排列情况同理
	 * 
	 */

	//用于对字符数组进行全排列
	public static void permutation(char[] arr, int index, int size){
		//递归的出口,并用于输出当前排列
		if (index+1 == size){
			System.out.print("\"");
			for (int i = 0; i < arr.length; i++){
				System.out.print(arr[i] + "");
			}
			System.out.print("\"\t");
		}
		else {
			for (int i = index; i < size; i++) {
				//如果arr[i]和arr[index]相同则不进行操作,避免了存在相同元素时的重复排序,但由于组合的方法没有对相同字符加以辨别,所以最终效果并不好
				if(i != index && arr[i] == arr[index])
					continue;
				swap(arr, i, index);//如果不相同则交换两元素
				permutation(arr, index+1, size);//进入下一层,下一层会对后面的元素进行排序或者打印出当前的排列
				swap(arr, i, index);//再次换回交换前的状态,以便为下一个排列做准备
			}
		}
	}
	//用于交换数组元素的方法
	public static void swap(char[] arr, int idx1, int idx2) {
		char temp = arr[idx1];
		arr[idx1] = arr[idx2];
		arr[idx2] = temp;
	}
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值