算法笔记 //05_有重复元素的排列问题(针对字母排序)

来源:互联网 发布:搜索引擎优化教程 编辑:程序博客网 时间:2024/06/08 05:16

★问题描述:

设 R = { r1, r2, ……, rn } 是要进行排列的 n 个元素。其中元素 r1 ,r2 ,……,rn 可能相同。试设计一个算法,列出 R 的所有不同排列。给定 n 以及待排列的 n 个元素。计算出这 n 个元素的所有不同排列。

★举例

简单举例:aabb则排列为:aabb ,abab, abba, baab, baba, bbaa(共6种)

**

★算法思想

① 当读取完用户输入的所有字母,考虑用将字母转换成数值的方法间接来进行排列;
② 将这些字母存储进一个数组 read[],将每个字母 -96 转换成数字,这时候考虑到用户可能会输入重复字母(某个或某些),因此考虑用一个数组 f[] 来作为计数器,记录所有字母的重复次数;
③ 记录完所有字母重复的次数之后,来进行排序,这里排序的思想是:对于重复的字母(即 f[]>0 时),不是考虑一次将其加入排序,而是一个一个地取,先取出第一个,f[] - 1,然后进入下一层遍历排序,继续取其他的字母,若其他字母也有重复(也是 f[] > 0),继续进入下一层遍历排序(重复此步骤),直到这一层遍历结束,返回上一层遍历排序,f[] + 1;
④遍历排序完一层,就输出此次排序的结果,情况总数记录数组 quantity[] +1,而且输出结果是一个一个字母输出,并非一次输出所有字母,因此也是循环输出,输入几个字母就循环几次。

**

★C++ 代码如下(Visual Studio 2017 调试运行,这里只写了字母排序):

// 输入字符的时候,个数要输入正确再按回车,字符之间不要有空格或回车#include "stdafx.h"#include <iostream>#include <stdio.h>#include <stdlib.h>using namespace std;int f[100], a[1000], n; //数组 a[1000] 为记录排列组合情况数组,f[100]作为一个计数器,整数 n 是来询问一共要输入几个字母 int quantity = 0;    //定义一个变量 quantity 来记录方案总数char read[100];     //定义字符串数组 read[] 记录用户输入字符void dfs(int depth) //定义函数 dfs(深度优先算法)(输出排列组合情况函数),定义深度depth{    if (depth == n + 1 && n != 0) //当层次深度达到了最底层时,比如说用户输入了 4 个字母,程序运行完第 5 层时,说明此次遍历排序完成,输出排序结果,然后情况数 + 1    {        quantity ++;      //将情况数 + 1         for (int r = 1;r <= n;r ++)   //不断循环遍历,一个一个字母地输出,不加空格,所以结果四个字母紧挨着,但是并非一次输出四个字母的            printf("%c", a[r] + 96);    //将数字转换为字符并输出所有排列组合情况(标准 ascII 码,a 对应 97,A 对应 65)        cout << endl;        return;    }    for (int r = 1;r <= 26;r ++)    //依次读取 f[] 每个位置的数值(即每个字母重复的次数,见主函数中 f[read[i]-96] 注释);26:26个字母组多也就是 26 个位置        if (f[r] > 0)     //如果这个位置数值大于零   在这里是第二个位置        {            a[depth] = r;     //a[]开始记录字母,先用数字来记录              f[r] --;     //相应的 f[] 数组 第二个位置的数值大小 -1            dfs(depth + 1);   //递归使用            f[r] ++;     //上面 dfs 结束此层的遍历之后,f[] + 1,回到上一层,取出下一个位置的字母        }}int main(){    cout << "Please input the number of letters you're gonna range:" << endl;    cin >> n;    cout << "\nPlease input the letters(no space and no entering until the letters' quantity is enough):" << endl;    cin >> read;    for (int i = 0;i < n;i ++) //输入几个字母就循环几遍,每个字母都要被遍历到        f[read[i] - 96] ++;    //记录每一个字母在字符串中出现了几次  ,read[i]为读取每个位置上的字母,然后将字母 -96 转化为数字,这个数字最大是26(因为一共26个字母),这样的话有重复的字母出现后,f[]数组相对应位置的数值大小就会重复加 1,可以记录到所有字母重复的次数    cout << "\nResults:" << endl;       //输出排列组合情况    dfs(1);     //在这里预定义深度为 1,上一条语句用 f[] 记录了各个字母重复的次数    cout << "\nTotal number:" << endl;    //输出总情况数    cout << quantity << endl;    cout << "__________________________________________________________" << endl;    system("pause");    return 0;}

这里写图片描述

原创粉丝点击