维护可修改的有序时间片列表(仍应订购列表)

时间:2015-07-15 20:54:18

标签: java collections

所以,我有一个问题,如下面的 ArrayList 中存在特定类型的各种对象,

...
//Class definition
class Params
{
  long startTimeMillis;
  long endTimeMillis;
  String currentState;

 .. correponding getters and setters are present here ..
}
....

ArrayList<Params> activities=new ArrayList<>();

Params h1= new Params();        
h1.setStartTimeMillis(1435939200000L);//"16:00"
h1.setEndTimeMillis(1435941000000L);//"16:30"
h1.setCurrentState("C");

Params h2= new Params();        
h2.setStartTimeMillis(1435941000000L);//"16:30"
h2.setEndTimeMillis(1435941900000L);//"16:45"
h2.setCurrentState("B");

Params h3= new Params();        
h3.setStartTimeMillis(1435941900000L);//"16:45"
h3.setEndTimeMillis(1435942500000L);//"16:55"
h3.setCurrentState("A");

Params h4= new Params();        
h4.setStartTimeMillis(1435942500000L);//"16:55"
h4.setEndTimeMillis(1435942800000L);//"17:00"
h4.setCurrentState("B");

Params h5= new Params();        
h5.setStartTimeMillis(1435942800000L);//"17:00"
h5.setEndTimeMillis(1435943400000L);//"17:10"
h5.setCurrentState("C");

activities.add(h1);
activities.add(h2);
activities.add(h3);
activities.add(h4);
activities.add(h5);

现在,我可以增加或减少各种情况:

  • 特定对象的开始时间
  • 特定对象的结束时间
  • 两个或多个活动之间是否存在对象。

e.g。

示例1:

以防我修改对象h2,使h2 16:30 )的开始时间减少10分钟,然后结束时间h1应该减少相同的h1结束时间 16:20

示例2:

以防我修改对象h2,使h2 16:45 )的结束时间增加10分钟,即 16:55 然后,对象h3应该从列表中移除,因为h2完全占用了对象。{/ p>

I / P: 我总是在两个diff变量中为每个对象修改了开始和结束时间,但问题是在运行时修改上述情况中提到的对象并相应地更新arraylist。

2 个答案:

答案 0 :(得分:2)

正确的方法是使用TreeSet并定义Param的排序。为此,您必须Param实施Comparable,然后同时提供hashCodeequals的实施。

然后,您可以修改项目,然后导航该集合以查找前一项和后一项。我的解决方案假设没有任何重叠时间,它也会处理你的第二个案例(删除无效的时间片)。

首先,我们需要Param实施Comparable<Param>

public class Param implements Comparable<Param> {

    //Public just for demo purposes and brevity
    public int start;
    public int end;

    public Param(int start, int end) {
        this.start = start;
        this.end = end;
    }

    @Override
    public int compareTo(Param o) {
        //Needs to be consistent with equals!!
        int result = this.start - o.start;
        if(result == 0) {
            result = (this.end - this.start) - (o.end - o.start);
        }

        return result;
    }

    @Override
    public int hashCode() {
        int result = 17;
        result = 31 * result + start;
        result = 31 * result + end;  
        return result;
    }

    @Override
    public boolean equals(Object o) {
        ... // null check, reference check etc.
        Param p = (Param) o;
        return this.start == p.start && this.end == p.end;
    }
}

现在所有的努力都已完成!您可以使用TreeSet中的方法查找正确的项目,然后进行修改。这是一些示例代码。

  NavigableSet<Param> pset = new TreeSet<Param>();

  Param p1 = new Param(10, 20);
  Param p2 = new Param(20, 30);
  Param p3 = new Param(30, 50);
  Param p4 = new Param(50, 60);

  pset.add(p1);
  pset.add(p2);
  pset.add(p3);
  pset.add(p4);

  System.out.println(pset);      

  int sdiff = -2;
  int ediff = 2;      

  //Find the item we want, as well as the preceding and succeeding items
  Param p = pset.floor(new Param(20, 30));      
  Param lower = pset.lower(p);
  Param higher = pset.higher(p);      

  //Remove the item from the set and modify it
  pset.remove(p);
  p.start += sdiff;
  p.end += ediff;      

  //Add only if it is valid
  if(p.start < p.end) {
      pset.add(p);    
  }      

  //If we have a preceding item
  if(lower != null) {
      //Remove, modify, and add back to set
      pset.remove(lower);
      lower.end += sdiff;
      if(lower.start < lower.end) {
          pset.add(lower);
      }    
  }

  //Same case as lower
  if(higher != null) {
      pset.remove(higher);
      higher.start += ediff;          
      if(higher.start < higher.end) {
          pset.add(higher);
      }    
  }

  System.out.println(pset);

运行此代码会给我们:

[[10, 20], [20, 30], [30, 50], [50, 60]]
[[10, 22], [22, 28], [28, 50], [50, 60]]

此代码适用于无效的时间片,以下示例将演示:

int sdiff = -20;
int ediff = 20; 

输出:

[[10, 20], [20, 30], [30, 50], [50, 60]]
[[0, 50], [50, 60]]

如果您以时间片无效的方式修改了元素本身,它也会起作用:

int sdiff = 5;
int ediff = -5;      

Param p = pset.floor(new Param(10, 20));

给我们:

[[10, 20], [20, 30], [30, 50], [50, 60]]
[[15, 30], [30, 50], [50, 60]]

int sdiff = 5;
int ediff = -10;      

Param p = pset.floor(new Param(10, 20));

给我们:

[[10, 20], [20, 30], [30, 50], [50, 60]]
[[10, 30], [30, 50], [50, 60]]

如果您修改元素以跨越多个切片,则此特定解决方案无法工作。但稍作修改,你也可以让它来处理这些情况。这是使用排序结构真正有用的地方,因为使用列表执行此操作将是一种噩梦。修改涉及使用while循环而不是if并且只要存在需要修改的元素就会遍历循环。循环还检查我们是否最终进入&#34;中间&#34;切片,如果是这样,它会适当地调整开始/结束时间:

//As long as we have elements to modify
while(lower != null) {
    Param nextLower = null;

    //Remove, modify, and add back to set if valid
    pset.remove(lower);
    lower.end += sdiff;

    if(lower.start < lower.end) {
        //The modified slice is valid, so add it back
        pset.add(lower);                   
    } else if(lower.start > lower.end) {
        //The modified slice is not valid and so we're not
        //going to add it. But it looks like we might have
        //encroached on the space of the slice that precedes
        //"lower" (at least; we may have extended past even
        //more, possibly all the way up to and past the
        //beginning)
        nextLower = pset.lower(p);
        if(nextLower != null && p.start == nextLower.start) {
            //It looks like we took up the space of the preceding
            //slice exactly (i.e., we are flush against it) and
            //so we don't need to do anything.
            nextLower = null;
        } else if(nextLower != null) {
            //It looks like we took up the space of the preceding
            //slice and then some. Let's adjust sdiff to reflect
            //that.
            sdiff = p.start - nextLower.end;                  
        }                            
    }

    lower = nextLower;
}

  //Similar to lower
  while(higher != null) {
      Param nextHigher = null;

      pset.remove(higher);
      higher.start += ediff;

      //Need to check for the additional case where the modified element's
      //end time could supersede a "higher" element's end time.
      if(higher.start < higher.end && higher.end > p.end) {
          pset.add(higher);              
      } else if(higher.start > higher.end || higher.end <= p.end) {
          nextHigher = pset.higher(p);
          if(nextHigher != null && p.end == nextHigher.start) {
              nextHigher = null;
          } else if(nextHigher != null) {
              ediff = p.end - nextHigher.start;                  
          }
      }

      higher = nextHigher;
  }

例如,如果您将[30, 40]更改为[0, 5][5, 15],则此算法无法运行。在这种情况下,您最终会得到[30, 40]曾经存在的空间,并且没有明确定义该空间应该如何填充。 [20, 30]应该更改为[20, 40],还是[40, 50]更改为[30, 50]?或者像[20, 35][35, 50]这样的内容呢?只要修改后的范围包含全部或部分原始范围,该算法就可以工作。

答案 1 :(得分:0)

这将修改您的开始时间

public void modifyStart(Params toModify,int increment,ArrayList<Params> list){
    int index = list.indexOf(toModify);
    int timeStart=toModify.getStartTimeMillis()+increment;
    toModify.setStartTimeMillis(timeStart);
    for(int i=index-1;i>=0;i--){ //removing all previous
        if(timeStart<list.get(i).getStartTimeMillis()){
            list.remove(i);
            index--;
        }else{
             break;
        }
    }
    if(index==0){
        return;
    }
    Params previous = list.get(index-1);
    previous.setEndTimeMillis(previous.getEndTimeMillis()+increment);
    if(toModify.getStartTimeMillis()>toModify.getEndTimeMillis()){ //removes yourself
        list.remove(toModify);
    }
}

结束时间非常相似

注意:没有经过测试,只是显示了一个想法