简体   繁体   English

将元素插入到数组列表的降序排列

[英]Insert an element to Array List sorted descending order

I'm trying to insert an element in the correct position in an array list that is sorted in descending order. 我正在尝试将元素按降序排列的数组列表中的正确位置插入。 The complexity to find the correct position must be O(LOGN). 查找正确位置的复杂度必须为O(LOGN)。 That's why I tried using binary search to find the correct position. 这就是为什么我尝试使用二进制搜索来找到正确的位置的原因。 This is what I did: 这是我所做的:

I added: 我补充说:

middle = (low + high) / 2; 中=(低+高)/ 2;

after the while loop. 在while循环之后。

The problem is that it's inserting the elements in ascending order. 问题在于它是按升序插入元素的。 instead of descending order 而不是降序

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;
        }
    }

middle = (low + high) / 2; 中=(低+高)/ 2;

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

}

There are a few problems with your code: 您的代码存在一些问题:

  • all your comparisons are the wrong way, thus you are inserting in ascending order 您所有的比较都是错误的方式,因此您以升序插入
  • you should loop while (high >= low) , or you can not insert an element that's smaller than all the existing elements; 您应while (high >= low)循环while (high >= low) ,否则不能插入小于所有现有元素的元素; also, with this you no longer need the if/else in insert 同样,您不再需要在insert使用if/else
  • if you want ties to be handled such that the oldest element is sorted first, remove the "same as middle" check and reverse the if/else within the loop; 如果您希望处理关系以使最早的元素排在最前面,则删除“与中间相同”检查,并在循环内反转if/else this way, in case of ties, the low bound is raised, inserting the new element after the older one 这样一来,在关系的情况下, low束缚提高,上了年纪后,一个插入新元素
  • now, after the while loop, you can just return low 现在,在while循环之后,您可以返回low

This seems to work (Note: Changed to Integer instead of E for testing, populating an initially empty list with random integers.): 这似乎可行(注意:为了进行测试,更改为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;
}

Tests and example output: 测试和示例输出:

@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]

This could be a lot simpler using Collections.binarySearch . 使用Collections.binarySearch可能会容易得多。 The methods will return the index if it is found or return a negative value matching where it should be : 如果找到索引,这些方法将返回索引,或者返回一个与之匹配的负值:

the index of the search key, if it is contained in the list; 搜索关键字的索引(如果包含在列表中); otherwise, (-(insertion point) - 1). 否则为(-(插入点)-1)。 The insertion point is defined as the point at which the key would be inserted into the list: the index of the first element greater than the key, or list.size() if all elements in the list are less than the specified key. 插入点定义为将键插入列表的点:第一个元素的索引大于键,如果列表中的所有元素都小于指定的键,则为list.size()。 Note that this guarantees that the return value will be >= 0 if and only if the key is found. 请注意,这保证了当且仅当找到键时,返回值才> = 0。

Here is a quick example of a SortedList 这是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;
    }
}

And a test case for a descending order: 还有一个降序测试用例:

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] [20、15、10、10]

The comparator in the constructor allow you to set the order to use for the insertion. 构造函数中的comparator允许您设置插入顺序。 Not that this is not safe, this is not overriding every methods but this is a quick answer ;) 并不是说这并不安全,不是覆盖所有方法,而是一个快速的答案;)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM