固定长度的字符串排序

时间:2019-06-14 18:09:49

标签: java bucket radix-sort

我想对整数进行排序。因此,我将它们解释为长度为32的二进制字符串。现在,我可以为每个组件应用bucketsort了。这是我在Java中的实现:

public static void sort(List<Integer> numbers)
{
    Queue<Integer> tmp =new LinkedList<Integer>();
    for (int i = 0; i < numbers.size(); i++) {
        tmp.offer(numbers.get(i));
    }

    List<Integer>[] bucket = new ArrayList[2];
    for (int i = 0; i < bucket.length; i++) {
        bucket[i] = new ArrayList<Integer>();
    }

    for (int k = 32; k > 0; k--) {
        // Clear
        for (int i = 0; i < bucket.length; i++) {
            bucket[i].clear();
        }

        while (!tmp.isEmpty()) {
            Integer firstel =tmp.element();
            String el =String.valueOf(firstel);

            if (el.charAt(k - 1) == 0) {
                bucket[0].add(firstel);
            } else {
                bucket[1].add(firstel);
            }
            tmp.remove();
        }

        for (int i = 0; i < bucket.length; i++) {
            for (Integer j : bucket[i]) {
                tmp.add(j);
            }
        }
    }
}

我不确定我的代码是否正确处理了这些二进制字符串。我是否必须将列表编号中的整数转换为二进制字符串? 注意:仅用于练习。时间复杂度没有更深的认识。

2 个答案:

答案 0 :(得分:1)

首先让我们重写一下,因为不需要Queue或tmp arraylist等。第一步,一个存根类,使我们可以编写更少的代码:

private class Numlist extends ArrayList<Integer> {
  Numlist() { super(); }
}

完成,我们不再需要到处写ArrayList<Integer>

现在,java会执行“自动装箱”,因此您存储Integer的所有内容都可以int执行,反之亦然。这很方便,因为我们可以丢弃所有字符串内容。如果我们只关心位比较,就不需要它:

public void sort(Numlist numbers) {
  // No copying `numbers` to a `tmp` queue: just work with it directly.
  Numlist zeroes, ones;

  for (int k = 1; k < 32; k++) {
    // Build this step's masking value, which we can use to
    // find the value of individual bits by using bitwise AND.
    // Also note that we _know_ this is a safe integer operation.
    mask = (int) Math.pow(2,k);

    // just allocate new lists; it's about as fast as clearing.
    zeroes = new Numlist();
    ones = new Numlist();

    // "scatter": now we empty the numbers list one element at a
    //  time, and then we'll fill it back up after we emptied it.
    while (!numbers.isEmpty()) {
      int e = numbers.remove(0);

      if ((e & mask) == mask) {
        ones.add(e);
      } else {
        zeroes.add(e);
      }        
    }

    // "gather"
    for (int i: zeroes) { numbers.add(i); }
    for (int i: ones) { numbers.add(i); }      
  }
}

通过重写,一切正常。我们删除了很多冗长的细节,这使代码工作变得更容易推断,并且删除了整个“ int到字符串到子字符串,然后进行char比较”,这意味着出错的地方更少了。

在测试方面,将您的函数添加到以下类中:

import java.lang.Math;
import java.util.ArrayList;

public class Test {

  // private class goes here

  public static void main(String[] argv) { new Test(); }

  public Test() {
    Numlist list = new Numlist();
    list.add(10);
    list.add(77810);
    list.add(4);
    list.add(100);
    list.add(1);
    list.add(290387423);
    list.add(23423);
    sort(list);
    System.out.println(list);
  }

  // function goes here
}

并完成:javac将很高兴地对其进行编译,执行应产生[1, 4, 10, 100, 23423, 77810, 290387423]

您还将注意到我们没有使用for (int k = 31; k > 0; k--),但是我们正在使用for (int k=1; k<32; k++) ...为什么?有区别吗?

这有很大的不同

通过将掩码从b000 ... 001设置为b100 ... 000,我们保证尽管“取回值”,它们的相对“小于当前位”的顺序仍然保留。

如果以另一种方式从b1000 ... 000到b000 ... 001运行蒙版,则在每一步我们都将撤消刚刚设置的顺序,结果根本不是排序列表:[1, 4, 100, 77810, 10, 290387423, 23423]

**编辑**:屏蔽为何起作用?

整数类型bytecharintlong分别只是1、2、4和8个字节的位模式,因此所有这些已经是“二进制数”,我们只需要一种访问单个位的方法,我们可以使用bitwise masking来实现。

为了掩盖“除特定位之外的所有内容”,您可以采用某些位模式的按位与,以及仅设置一个位的模式,我们可以很容易地创建 ,因为这些仅仅是“ 2的幂”。

例如,要检查数字23中的位,我们可以使用以下检查:

     23  &   1     2    4      8     16    32  

b0    1  &  1=1   0=0   0=0   0=0   0=0   0=0
b1    1  &  0=0   1=1   0=0   0=0   0=0   0=0
b2    1  &  0=0   0=0   1=1   0=0   0=0   0=0
b3    0  &  0=0   0=0   0=0   1=0   0=0   0=0
b4    1  &  0=0   0=0   0=0   0=0   1=1   0=0
b5    0  &  0=0   0=0   0=0   0=0   0=0   1=0

在这里,我们可以看到数字23,二进制10111以及被2的幂乘以23:1所掩盖的结果为1,所以我们知道第一位已设置。我们看到23&2产生2,所以我们知道第二位被设置。对于4,相同,但23和8的结果为0。我们知道第四位未设置

因此,我们可以使用按位AND来检查任何长度的位模式:如果(number & mask) == mask我们知道该掩码的位已设置。如果结果改为0,则表明该位未设置。

此外,请注意,&&&不相同&是按位AND运算,对两个位之间的每个位执行AND操作员的左侧和右侧。 &&运算符为逻辑 AND,要求左侧和右侧为布尔值。逻辑“与”实际上是“单个与”,而按位“与”则是“与要测试的位一样多的与”运算。

答案 1 :(得分:-1)

Java已经提供了一个方便的api作为Collections框架的一部分。 Collections.sort(numbers); 这将按升序对整数进行排序。如果需要不同的订购,则可以使用另一个带有Comparator的API。