算法学习日记 字典法排序

算法学习日记  字典法排序

 

问题:给出给定序列的全排列

 

例如:序列为 1 2 3

  输出为 123 132 213 231 312 321

 

问题分析:

(1)如何对一组数找到他的全排列

解答:采用字典序排列算法。用字典序法得到全排列的思路大概是这样的:我们需要有一个初始的排列状态,对于这个排列,用字典序法转换就得到下一个排列。我们把初始状态设置为字符从小到大地排,不断地用字典序法得到它的下一个排列,直到最后一个排列为止,而最后一个排列就是字符从大到小地排喽。比如说5个数字的所有的排列中最前面的是12345,最后面的是54321

具体算法如下

 

P1n的一个全排列:p=p1p2......pn=p1p2......pj-1pjpj+1......pk-1pkpk+1......pn
(1)从排列的右端开始,找出第一个比右边数字小的数字的序号jj从左端开始计算),即 j=max{i|pi<pi+1}
 (2)在pj的右边的数字中,找出所有比pj大的数中最小的数字pk,即 k=max{i|pi>pj}(右边的数从右至左是递增的,因此k是所有大于pj的数字中序号最大者)
 (3)对换pipk,再将pj+1......pk-1pkpk+1pn倒转得到排列p’’=p1p2.....pj-1pjpn.....pk+1pkpk-1.....pj+1,这就是排列p的下一个下一个排列。


 例如839647521是数字19的一个排列。从它生成下一个排列的步骤如下:
 自右至左找出排列中第一个比右边数字小的数字4 839647521
 在该数字后的数字中找出比4大的数中最小的一个5 839647521
 将54交换 839657421
 将7421倒转 839651247

 所以839647521的下一个排列是839651247


源码如下

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define array_max 5

void invert_array(int *begin,int *end)
{
    int temp;
    while(begin<end)
    {
        temp=*begin;
        *begin=*end;
        *end=temp;
        ++begin;
        --end;
    }
}


void print(int *a)
{
    int i;
    for(i=0;i<array_max;i++)
    {
        printf("%d ",a[i]);
    }
    printf("\n");
}

int main(void)
{

    int list[5]={2,3,1,4,5};
    int min=0,point=0;
    int temp=0;
    int *begin=NULL;
    int *end=list+array_max-1;
    int i=0,j=0;
    print(list);
    while(1)
    {
        i=array_max-2;
        while(i>=0&&list[i]>list[i+1])
            i--;
         if(i<0) break;
        point=i;
        begin=&list[i+1];
        min=1000;
        for(j=i;j<array_max;j++)
        {
            if((list[j]>list[i])&&(list[j]<min))
            {
                min=list[j];
                point=j;
            }
        }
        temp=list[i];
        list[i]=list[point];
        list[point]=temp;
        invert_array(begin,end);
        print(list);

    }
    return 0;

}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值