一种算法,用于在位掩码中设置下一个工作日

时间:2008-12-08 23:50:13

标签: c++ algorithm

我有一个小问题 - 给出工作日的位掩码(例如,Sunday = 0x01, Monday = 0x02, Tuesday = 0x04等等)和今天(以Sunday = 1, Monday = 2, Tuesday = 3等形式...) - 从今天开始第二天发现的最优雅方式是什么?这是在位掩码中设置的?优雅我的意思是,如果没有if / switch / etc,有没有办法做到这一点...,因为我知道非优雅的方式?

编辑我可能应该提到(为了更清楚),持有位掩码的变量可以设置几天,例如(粗略地):

uDay = Sunday | Monday;
today = Tuesday;

我需要“星期天”

4 个答案:

答案 0 :(得分:3)

int getNextDay(int days_mask, int today) {
   if (!days_mask) return -1; // no days set
   days_mask |= days_mask << 7; // duplicate days into next week
   mask = 1 << (today % 7); // keep track of the day
   while (!(mask & days_mask)) {
      mask <<= 1;
      ++today;
   }
   return today % 7;
}

因此,如果在开始和循环时只有一个。怎么样?

编辑我刚刚意识到有一种退化的情况,即如果今天使用&gt; = 14(或大于最高位集),则while循环变为无限。第4行的(今天%7)修复了这种情况。

如果我可能(轻松地)对获得复选标记的其他版本抱怨,我的版本只有2个模数调用,而检查的解决方案将至少有1个模数调用和最多6个模数调用。

另外,如果今天设置的话,关于函数返回“今天”的评论很有意思。如果今天该函数不应该返回,除非今天是该集合中的唯一一天,则需要在我的解决方案的第3行预先增加。

答案 1 :(得分:2)

您根本不需要任何额外的变量。最简单的想法 - 从“明天”开始,看看连续几天,直到你在面具中找到一天 - 也是最优雅的实施。做得好的诀窍是把日子想象为星期日= 0,星期一= 1等等(仅在这个函数内)。然后,“今天”实际上是t-1(其中t是函数的输入,因此从1到7),“明天”是(t-1+1)%7,即t%7等。

这很简单,并且已经针对litb的代码进行了详尽的测试,只是为了确保: - )

int getNextDay(int m, int t) {
  if((m&127)==0) return t;          //If no day is set, return today
  t=t%7;                            //Start with tomorrow
  while((m&(1<<t))==0) t = (t+1)%7; //Try successive days
  return t+1;                       //Change back to Sunday=1, etc.
}

修改:如果您希望“下一个”表示“今天或更晚”,则“t = t%7”行应更改为t=t-1--t

答案 2 :(得分:1)

我这样理解你的问题:

// returns t (today) if no weekday is set in the mask.
int getNextDay(int m, int t) {
    int i, idx;
    for(i = 0, idx=t%7; i<7 && !((1<<idx)&m); i++, idx=(idx+1)%7)
        /* body empty */ ;
    return (i == 7) ? t : (idx + 1);
}

// getNextDay(8|2, 2) == 4, getNextDay(64, 2) == 7
// getNextDay(128, 2) == 2

答案 3 :(得分:1)

  

我的意思是优雅,如果没有if / switch / etc,有没有办法做到这一点......

你打赌!这是否意味着任何通常意义上的“优雅”,嗯:

static unsigned next_day_set (unsigned today, unsigned set) {
  unsigned arev = bitreverse (highest_bit_set (bitreverse ((set << 7) | set)
                                               & (bitreverse (today) - 1)));
  return ((arev >> 7) | arev) & 0x7f;
}

假设你有'优雅'的功能来反转一个字中的位并找到最左边的位集 - 见Hacker's Delight。如果你以相反的顺序表示工作日位,它会更简单,实际上甚至更真实,假设我没有搞砸:

enum {
  Sunday  = 1 << 6
  Monday  = 1 << 5
  Tuesday = 1 << 4,
  /* etc */
  Saturday = 1 << 0
};

static unsigned next_day_set (unsigned today, unsigned set) {
  unsigned a = highest_bit_set (((set << 7) | set) & ((today << 7) - 1));
  return ((a >> 7) | a) & 0x7f;
}