全排列算法【非递归活动数实现】
2017-10-10 20:15
375 查看
求解一个问题,有很多种算法/方法,一旦遇到比较有趣的思想/算法,就忍不住记录下来。
题:求n=4时的全排列(当n=4时,序列为:{1, 2, 3, 4})
算法的思想:
1. 给排列中的每个元素均赋予一个向左或向右的箭头。
2. 如果元素k的箭头指向的是与其相邻但小于k的元素,则称元素k是活动的。
3. 从排列 1 2 3 … n 开始,找其中的最大活动元素k,将该元素k与它所指向的相邻元素交换位置,并改变所有大于k的元素的方向。
运行结果:
题:求n=4时的全排列(当n=4时,序列为:{1, 2, 3, 4})
算法的思想:
1. 给排列中的每个元素均赋予一个向左或向右的箭头。
2. 如果元素k的箭头指向的是与其相邻但小于k的元素,则称元素k是活动的。
3. 从排列 1 2 3 … n 开始,找其中的最大活动元素k,将该元素k与它所指向的相邻元素交换位置,并改变所有大于k的元素的方向。
import java.util.ArrayList; import java.util.List; import java.util.Scanner; /** * 生成全排列 * * 算法的思想: * 1. 给排列中的每个元素均赋予一个向左或向右的箭头。 * 2. 如果元素k的箭头指向的是与其相邻但小于k的元素,则称元素k是活动的。 * 3. 从排列 1 2 3 … n 开始,找其中的最大活动元素k,将该元素k与它 * 所指向的相邻元素交换位置,并改变所有大于k的元素的方向。 */ public class Perm { enum Direction { LEFT, RIGHT //方向有左右 } /** * 把每个数看成一个元素,有数值有方向 */ static class Element { int data; //数值 Direction direction; //方向 public Element(int data, Direction direction) { this.data = data; this.direction = direction; } } /** * 生成全排列 * @param list 需要生成全排列的序列集合 */ private static void perm(List<Element> list) { int count = 1; //统计全排列的数目 if (list == null) return; //首先打印第一种情况 printAllElement(list, true); int index; //活动数的下标 while (true) { index = findMaxActiveNum(list); //找到最大活动数下标 if(index == -1) { System.out.println("全排列总数为:" + count); return; } //改变所有大于最大活动数的元素的方向 changeDirection(list, index); //交换最大活动数与它所指向的相邻元素 if (list.get(index).direction == Direction.LEFT) { swapElement(list, index-1, index); } else { swapElement(list, index, index+1); } count++; printAllElement(list, true); } } /** * 找到最大活动数 * @param list 需要生成全排列的序列集合 */ private static int findMaxActiveNum(List<Element> list) { if(list == null) return -1; int length = list.size(); int index = -1; //找出最大活动数的下标 for (int i = 0; i < length; i++) { int data = list.get(i).data; boolean isLeft = list.get(i).direction == Direction.LEFT; //当不是活动数时,跳出此次循环- if (i == 0 && isLeft || i == length-1 && !isLeft || //这个数的箭头所指的下一个元素为空 isLeft && data < list.get(i-1).data || !isLeft && data < list.get(i+1).data) { //这个数比箭头所指的下一个数小 continue; } else { if(index == -1) { index = i; } else { index = list.get(i).data > list.get(index).data ? i : index; //记录最大活动数的下标 } } } return index; } /** * 交换两个元素的值和箭头 * @param list 需要生成全排列的序列集合 * @param index1 下标1 * @param index2 下标2 */ private static void swapElement(List<Element> list, int index1, int index2) { if(list == null) return; //交换两个对象的引用,达到交换值的目的 Element temp = list.get(index1); list.set(index1, list.get(index2)); list.set(index2, temp); } /** * 改变所有大于list.get(index)的元素的方向 * @param list 需要生成全排列的序列集合 * @param index 下标 */ private static void changeDirection(List<Element> list, int index) { if (list == null) return; int data = list.get(index).data; for (int i = 0; i < list.size(); i++) { if (list.get(i).data > data) { list.get(i).direction = list.get(i).direction == Direction.LEFT ? Direction.RIGHT : Direction.LEFT; } } } /** * 打印全部元素 * @param list 需要生成全排列的序列集合 * @param arrowFlag 是否打印箭头 */ private static void printAllElement(List<Element> list, boolean arrowFlag) { if (list == null) return; if(arrowFlag) { for (Element element: list) { switch (element.direction) { case LEFT: System.out.print("← "); break; case RIGHT: Syste aa94 m.out.print("→ "); break; } } } System.out.println(""); for (Element element: list) { System.out.print(element.data + " "); } System.out.println(""); } /** * 创建一个序列 * @param n 序列最大的数 * @return n为最大值的集合 */ private static List<Element> createDataList(int n) { List<Element> list = new ArrayList<>(); for (int i = 1; i <= n; i++) { list.add(new Element(i, Direction.LEFT)); //初始化一个最大元素为n的序列,并且每个元素拥有一个向左的箭头 } return list; } public static void main(String[] args) { List<Element> elementList; Scanner scanner = new Scanner(System.in); int n; //读取n System.out.println("【功能】非递归求全排列(活动数实现)"); System.out.println("请输入n:"); n = scanner.nextInt(); elementList = createDataList(n); perm1(elementList, 0, elementList.size()); } }
运行结果:
相关文章推荐
- LeetCode:Permutations(全排列算法的递归与非递归实现)
- 全排列算法的递归与非递归实现
- 全排列算法递归实现 C++
- 递归实现的全排列算法
- 全排列算法(递归实现) 组合算法(递归,位运算实现)
- 【转】全排列算法非递归实现和递归实现
- 黑马程序员_论坛活动:递归实现猴子吃桃
- 全排列算法-递归与字典序的实现方法(Java)
- 全排列算法的非递归实现
- 全排列算法非递归实现和递归实现
- 全排列算法的非递归实现与递归实现的方法(C++)
- 全排列算法的递归与非递归实现
- 黑马程序员——论坛活动:递归实现猴子吃桃
- 全排列算法(字典序,递归实现)
- 全排列算法的递归实现
- 全排列算法的递归与非递归实现
- 全排列算法的递归思想及实现
- 递归实现全排列算法
- 全排列算法非递归实现和递归实现
- 二叉树的创建,遍历,查找,查找父节点,深度,大小等的递归实现