【问题标题】:Insert an element to Array List sorted descending order将一个元素插入到 Array List 降序排序
【发布时间】:2017-12-14 10:49:33
【问题描述】:

我正在尝试在按降序排序的数组列表中的正确位置插入一个元素。 找到正确位置的复杂度必须是 O(LOGN)。 这就是为什么我尝试使用二进制搜索来找到正确的位置。 这就是我所做的:

我补充说:

中=(低+高)/2;

在while循环之后。

问题是它按升序插入元素。而不是降序

public void insert(E x) {

    if(q.size()==0){
        q.add(0, x);
    }
    else{
        int place = binarySearch(x);
        q.add(place, x);
    }
}

private int binarySearch (E x) {
    int size = q.size();
    int low = 0;
    int high = size - 1;
    int middle = 0;

    while(high > low) {
        middle = (low + high) / 2;
        if(q.get(middle).getPriority() == x.getPriority()) {
            return middle;
        }
        if(q.get(middle).getPriority() < x.getPriority()) {
            low = middle + 1;
        }
        if(q.get(middle).getPriority() > x.getPriority()) {
            high = middle - 1;
        }
    }

中=(低+高)/2;

    if(q.get(middle).getPriority() < x.getPriority()) {
        return middle + 1 ;
    }
    return middle;

}

【问题讨论】:

  • 我的意思是找到正确位置的复杂度必须是O(LOGN)。我编辑帖子。
  • 再次检查答案。我编辑了它。
  • 你能扩展一下它不能正常工作
  • @notyou 如果我添加这个:middle = (low + high) / 2;在while循环之后,它以升序插入元素。而不是降序
  • “它不工作”不是问题描述。调试您的代码并尝试定位错误。

标签: java sorting arraylist


【解决方案1】:

您的代码存在一些问题:

  • 你所有的比较都是错误的,因此你是按升序插入的
  • 你应该循环while (high &gt;= low),否则你不能插入小于所有现有元素的元素;此外,有了这个,您不再需要 insert 中的 if/else
  • 如果您希望处理关系,以便首先排序最旧的元素,请删除“与中间相同”检查并反转循环内的if/else;这样,在出现平局的情况下,low 绑定被提升,在旧元素之后插入新元素
  • 现在,在while 循环之后,您可以直接返回low

这似乎可行(注意:更改为 Integer 而不是 E 进行测试,用随机整数填充一个最初为空的列表。):

public void insert(E x) {
    q.add(binarySearch(x), x);
}

private int binarySearch (E x) {
    int low = 0;
    int high = q.size() - 1;
    while (high >= low) {
        int middle = (low + high) / 2;
        if (q.get(middle).getPriority() < x.getPriority()) {
            high = middle - 1;
        } else {
            low = middle + 1;
        }
    }
    return low;
}

测试和示例输出:

@Data @AllArgsConstructor
class E {
    int id, priority;
    public String toString() { return String.format("%d/%d", id, priority); }
}

Random random = new Random();
int id = 0;
for (int i = 0; i < 50; i++) {
    test.insert(new E(id++, random.nextInt(20)));
}
System.out.println(test.q);
// [2/19, 3/19, 24/19, 32/19, 46/19, 18/18, 23/18, 39/18, 31/17, 10/16, 28/16, 40/16, 45/16, 7/15, 19/14, 33/14, 37/14, 38/14, 36/13, 44/13, 5/11, 12/11, 15/11, 20/11, 30/11, 9/10, 41/10, 48/10, 16/9, 34/9, 13/8, 1/7, 8/7, 35/7, 0/6, 6/6, 22/6, 29/6, 21/5, 26/5, 42/5, 14/4, 27/4, 47/4, 25/3, 4/1, 11/1, 17/1, 43/1, 49/0]

【讨论】:

  • 我怎样才能改变它,首先插入的元素将首先在具有相同值的元素之间?
【解决方案2】:

使用Collections.binarySearch 可能会简单得多。如果找到索引,这些方法将返回索引,或者返回与应该在的位置匹配的负值:

搜索键的索引,如果它包含在列表中;否则,(-(插入点)- 1)。插入点定义为将键插入列表的点:第一个元素的索引大于键,如果列表中的所有元素都小于指定的键,则为 list.size()。请注意,这保证了当且仅当找到键时返回值将 >= 0。

这是SortedList的一个简单示例

class SortedList<E> extends ArrayList<E>{

    Comparator<E> comparator;

    public SortedList(Comparator<E> comparator) {
        this.comparator = comparator;
    }

    @Override
    public boolean add(E e) {
        int index = Collections.binarySearch(this, e, comparator);

        if(index < 0){
            index = -index - 1;
        }
        if(index >= this.size()){
            super.add(e);
        } else {
            super.add(index, e);
        } 
        return true;
    }
}

还有一个降序测试用例:

SortedList<Integer> list = new SortedList<>(
             (i1,  i2) -> i2 - i1
        );
list.add(10);
list.add(20);
list.add(15);
list.add(10);

System.out.println(list);

[20, 15, 10, 10]

构造函数中的comparator 允许您设置用于插入的顺序。并不是说这不安全,这并没有覆盖所有方法,但这是一个快速的答案;)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-06-24
    • 1970-01-01
    • 2012-11-26
    • 1970-01-01
    • 2013-02-09
    • 1970-01-01
    相关资源
    最近更新 更多