字典序简介
英文名叫lexicographical order,数字可以作为特别的字符串,这种情况下,如果我们用字典序进行比较,就有可能会出现下面这种情况:
”100”<”1000”(加引号的目的是为了区别数字与数字串),事实上,在计算机里,我们会这么看?
和之前一样,我们会首先比较第一个字符,这里”1”=’1’(已经可以看到区别了、在数中,数字因为位置的不同会有不同的意义,而这里,这种分别变的不一样了)。一步比较,还没有办法分辨出它们的大小,只好再比较之后的数。
这种情况回直到最后一次尝试,第一个字符串已经空掉之前。如果硬要比较的话,空格的ascii码值是32.(Ascii码还是用两位十六进制表示比较合适)‘0’的ASCII码值是48 所以‘100’<’1000’
例子:依次比字母, 如boat < boot < cap < card < cat < to < too< two < up.
求下一个字典序的方法
- 求 i = max{j | p[j – 1] < p[j]} (找最后一个正序);
- 求 j = max{k| p[i – 1] < p[k]} (找最后大于 p[i – 1] 的);
- 交换 p[i – 1] 与 p[j]得到 p[1] … p[i-2] p[j] p[i] p[i+1] … p[j-1] p[i-1]
p[j+1] … p[n]; - 反转 p[j] 后面的数得到 p[1] … p[i-2] p[j] p[n] … p[j+1] p[i-1] p[j-1] …
p[i]。
例如:设有排列(p)=2763541,按照字典式排序,它的下一个排列是什么?
- 2763541 (找最后一个正序35);
- 2763541 (找3后面比3大的最后一个数4);
- 2764531 (交换3,4的位置);
- 2764135 (把4后面的5,3,1反转)。
C++代码
void nextPermutation(vector<int>& nums) {
int size = nums.size();
if(size==0 || size==1)
return;
vector<int>::iterator p = nums.end()-1,q=nums.end()-1;
while( p!=nums.begin() && *p<=*(p-1) )
p--;
if(p==nums.begin())
reverse(nums.begin(),nums.end());
else if(p==nums.end()-1)
swap(*p,*(p-1));
else{
p--;
while(*q<=*p)
q--;
swap(*p,*q);
reverse(p+1,nums.end());
}
}
STL中排列算法
- is_permutation(beg1,end1,beg2)
is_permutation(beg1,end1,beg2,binaryPred)
如果第二个序列的某个排序和第一个序列具有相同数目的元素,且元素都相等,则返回true。第一个版本用==比较元素,第二个版本使用给定的binaryPred。 - next_permutation(beg,end)
next_permutation(beg,end,comp)
如果序列已经是最后一个排列,则next_permutation将序列重排为最小的排序,并返回false。否则,它将输入序列转换为字典序中的下一个排列,并返回true。第一个版本使用元素的<运算比较元素,第二个版本使用给定的比较操作。 - prev_permutation(beg,end)
prev_permutation(beg,end,comp)
类似next_permutation,但将序列转换为前一个排序。如果序列已经是最小的排列,则将其重排为最大的排列,并返回false。
注意:
1. 这些算法假定序列中的元素都是唯一的。即没有两个元素的值是一样的。
2. 为了生成排序,必须即向前又向后处理排序,因此算法要求双向迭代器。
总结
因为本人能力有限,暂时还不能深入STL源码来解析这些泛型算法,等我能够看到STL源码的时候,再来对这些算法进行详细解读。字典序排序是计算机中一个非常重要的知识,对于求解排列问题有着很好的借鉴作用,稍后我会写一些利用字典序求解问题的文章。