我想编写一个函数insertAndSort(),它将整数“num”和整数列表“list”作为参数。我们假设List欲望已经排序了。
该算法应该以这种方式工作:
警告:我们不知道列表是按ASC还是DESC排序。这正是我的问题!
示例:
到目前为止,我已经制作了这段代码:
public static void main(String[] args) {
int num = 4;
List<Integer> myList = Arrays.asList(1, 3, 5, 7);
List<Integer> newList = new ArrayList<Integer>();
newList = insertAndSort(myList, num);
System.out.println(newList);
}
public static List<Integer> insertAndSort(List<Integer> list, int num) {
List<Integer> listSecond = new ArrayList<Integer>(list.size()+1);
for(int i = 0; i <= list.size() ; i++) {
if(num < list.get(i)) {
if(!listSecond.contains(num)){
listSecond.add(num);
} else {
listSecond.add(list.get(i-1));
listSecond.add(list.get(i));
break;
}
} else {
listSecond.add(list.get(i));
}
}
return listSecond;
}
问题在于,这似乎与单一类型的List一起使用:升序列表。 当我采用排序的降序列表时,它不再起作用。
您是否有任何想法可以使用这两种类型的List?
谢谢和问候。
答案 0 :(得分:4)
首先,您需要检测现有列表中的排序顺序。
一旦你检测到排序顺序,我建议使用一个很大的if-else语句来分别处理这两个案例。
您已经拥有升序案例的代码。除了它并不总是有效。如果我尝试将4插入{1,3,5},我会得ArrayIndexOutOfBoundsException
。如果我尝试使用{1,3,5,7,9},则会丢失9。你可能应该找到一个解决方法。
您应该能够处理降序情况,与升序情况类似。仅使用num > list.get(i)
代替num < list.get(i)
。
答案 1 :(得分:1)
首先,您需要检查列表是否在ASC或DESC中排序。这很简单:比较前两个元素。
if(list.size() >= 2 && list.get(0) < list.get(1))
//ASC
else
//DESC
现在,对于按升序排序的列表,请将list
转换为ArrayList
。然后,将num
添加到ArrayList并将其转换为TreeSet
,因为TreeSet会按升序对其元素进行排序。最后,重新分配ArrayList以保存TreeSet的内容并将其返回。
对于按降序排序的列表,首先,将TreeSet转换为ArrayList,然后以相反的顺序迭代此ArrayList并将元素添加到新的ArrayList。返回第二个ArrayList。
public List<Integer> insertAndSort(List<Integer> list, int num){
ArrayList<Integer> a = new ArrayList<Integer>(list);
a.add(new Integer(num));
TreeSet t = new TreeSet(a);
a = new ArrayList<Integer>(t);
if(list.size() >= 2 && list.get(0) < list.get(1))
return a;
else{
ArrayList<Integer> a2 = new ArrayList<Integer>();
for(int i = a.size() - 1; i >= 0; i--)
a2.add(a.get(i));
return a2;
}
}
答案 2 :(得分:0)
我会继续使用下面的代码。一些评论:
int oo = list.get(p2) - list.get(p1);
计算
最后一个元素和第一个元素之间的差异(负= DESC,
positive = ASC)ox
为正时
添加的元素位于变量p3
指向的元素之后
无论订单如何。p3
和p1
之间选择p2
并确定该元素是在p3之前还是之后,通过二元搜索算法找到位置。这与您提供的示例无法完全测试:
// static List<Integer> list = new ArrayList<>(Arrays.asList(7, 5, 3, 1));
static List<Integer> list = new ArrayList<>(Arrays.asList(1, 3, 5, 7));
static void add(int x)
{
// fixed code below (see Ole V.V. comment)
}
static public void main(String [ ] args)
{
add(4);
for(int x: list)
System.out.println(x);
}
编辑:完成(见Ole V.V.评论)
算法的复杂性对我来说是一个重要的问题,并且是我帖子的主要目标。 add
函数的代码变为:
static void add(int x)
{
int p1 = 0;
int p2 = list.size() - 1;
if(list.size() == 0 || list.get(p1) == list.get(p2))
throw new IllegalStateException("Unable to decide sort order");
int oo = list.get(p2) - list.get(p1);
if(oo * (x - list.get(p1)) <= 0) // new element is before first
list.add(0, x);
else if(oo * (x - list.get(p2)) >= 0) // new element is after last
list.add(x);
else
{
while (p1 + 1 < p2)
{
int p3 = (p1 + p2) / 2;
int ox = (x - list.get(p3)) * oo;
if(ox >= 0) // new element is after p3
p1 = p3;
if(ox <= 0) // new element is before p3
p2 = p3;
}
list.add(p2, x);
}
}
注意:可能还有一些未处理的副作用。如果提问者感兴趣,我准备提供进一步的帮助 - 请问。
答案 3 :(得分:0)
您的代码和您所说的是两回事。 根据您编写的代码,我发现List不能包含多个相同值的实例。 在这种情况下,main方法应如下所示:
public static void main(String[] args){
int num = 4;
List<Integer> myList = Arrays.asList(1, 3, 4, 5, 7);
List<Integer> newList;
if (!myList.contains(num)) {
newList = insertAndSort(myList, num);
} else {
newList = copyList(myList);
}
System.out.println(newList);
}
如果不是这种情况:
public static void main(String[] args){
int num = 4;
List<Integer> myList = Arrays.asList(1, 3, 4, 5, 7);
List<Integer> newList;
newList = insertAndSort(myList, num);
System.out.println(newList);
}
主要方法使用的方法:
假设我们只能知道列表是如何按列表中的值排序的,那么当只有1个值或所有值都相同时,我们必须决定默认的排序方法。我选择ASC作为默认值。如果元素可以具有相同的值,并且我们确定列表已按其最佳排序,则将列表中的最小值与最高值进行比较。使用这种方法,我们只需比较两个元素一次。
所以查看列表是否已排序的方法DESC看起来像这样:
private static boolean isDesc(List<Integer> list) {
return list.get(0) > list.get(list.size() - 1);
}
如果方法返回true,则其已排序的DESC。返回false时,其ASC。如果要更改默认值,则当值不告诉我们默认值如何排序并且我们希望将其设为DESC时,可以将'>'符号替换为'> ='
private static boolean isDesc(List<Integer> list) {
return list.get(0) >= list.get(list.size() - 1);
}
代码insertAndSort:
public static List<Integer> insertAndSort(List<Integer> list, int num) {
List<Integer> listSecond = new ArrayList<Integer>(list.size() + 1);
boolean isDescSortOrder = isDesc(list);
if (isDescSortOrder) {
int i = 0;
while ((i < list.size()) && (list.get(i) > num)) {
listSecond.add(list.get(i));
i++;
}
listSecond.add(num);
while (i < list.size()) {
listSecond.add(list.get(i));
i++;
}
} else { // is asc sort order
int i = 0;
while ((i < list.size()) && (list.get(i) < num)) {
listSecond.add(list.get(i));
i++;
}
listSecond.add(num);
while (i < list.size()) {
listSecond.add(list.get(i));
i++;
}
}
return listSecond;
}
取决于将其排序的代码分为2个块的方式。正如我们所不知道的,在每次迭代中插入num值的位置都是正确的,最好在while循环中使用。使用for循环并每次检查list中是否已存在num值都会适得其反。最重要的是,我不知道您的应用程序是否应允许列表中使用相同的值。如果我认为应该这样做,则不能添加num值(如果它已存在于for循环的列表中,并使用包含每次迭代检查)。
仅当list已包含元素并且我们不想添加已经包含的元素时复制表:
public static List<Integer> copyList(List<Integer> list) {
List<Integer> listSecond = new ArrayList<Integer>(list.size());
for (int i = 0; i < list.size(); i++) {
listSecond.add(list.get(i));
}
return listSecond;
}
基于良好的编程习惯,我建议根据方法的用途来命名方法。
调用方法insertAndSort正在引起麻烦。如果我看到了,我会说它会改变我们在参数中给出的列表。然后对其进行排序。 因此,将未排序的列表放在其中会给我们带来不必要的结果。 而且我仍然会问自己,当我们向现有列表中插入一个项目时为什么它返回一个列表?我更愿意命名:
public static List<Integer> copySortedWithNewValue(List<Integer> sortedList, int newValue)
答案 4 :(得分:0)
尝试使用PriorityQueue
。该集合包含可以重复的元素排序序列。