求合并重叠时间段的算法

zhlei616 2011-02-28 08:54:37
同一天中的一连串不连续时间段,合并其中重叠时间,如:
StartTime EndTime
06:10:58 08:15:28
07:38:56 10:34:45
10:55:00 11:34:00
13:09:34 17:45:23
14:23:12 15:24:14
16:14:25 17:52:15
...
合并后为:
StartTime EndTime
06:10:58 10:34:45
10:55:00 11:34:00
13:09:34 17:52:15
...
用SQL或C#代码都可以,SQL的话因为数据库是SQL Compact,不支持存储过程,编程能力差,所以用C#相对简单一点,数据放在DataTable或List中都可以,其实任意语言均可,我只是想要一个好点的算法,
我现在想出的算法是先按开始时间排序,排序后遍历所有元素,使每个时间段跟它下一个时间段比较,合并重叠时间段,然后递归再次比较,直到每个时间段都与它下一个时间段没有重叠为止,这个算法一是效率太低,而且我觉得好像也有点问题。
这个算法应该在HR系统的考勤记录中应用比较多,不知那位兄台有比较好的算法?
...全文
970 11 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
yalan 2011-03-02
  • 打赏
  • 举报
回复
我的算法:
构造一个二维数组,然后将数组从小到大排序,然后从小到大遍历数组合并
artwl_cn 2011-03-02
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 qldsrx 的回复:]

引用 4 楼 durongjian 的回复:
大哥,在博客园已经给你回复了:
http://home.cnblogs.com/q/22617/
http://www.cnblogs.com/durongjian/archive/2011/03/01/1968044.html

虽然功能实现得还是不错的,不过个人感觉欠考虑,不是效率问题,而是准确度问题。比方说,后面一行记录的结束时间如果……
[/Quote]
非常感谢你的意见,程序现已更改:
http://www.cnblogs.com/durongjian/archive/2011/03/01/1968044.html
qldsrx 2011-03-02
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 durongjian 的回复:]
大哥,在博客园已经给你回复了:
http://home.cnblogs.com/q/22617/
http://www.cnblogs.com/durongjian/archive/2011/03/01/1968044.html
[/Quote]
虽然功能实现得还是不错的,不过个人感觉欠考虑,不是效率问题,而是准确度问题。比方说,后面一行记录的结束时间如果也小于前面一行记录,那么结束时间就不应该继续拿后面一行记录了。如果List内的数据未经过排序,那么这样做肯定得不到想要的结果。鉴于数据一般优先加载到DataTable中,在DataTable中使用筛选更加好。
artwl_cn 2011-03-02
  • 打赏
  • 举报
回复
zhlei616 2011-03-02
  • 打赏
  • 举报
回复
感谢大家的回复,尤其是天行健兄,原来大家都是CSDN和博客园两边逛啊,哈哈~~~
天行健和superhoy的代码我已运行过,都成功的解决了此问题,也感谢青龙白虎和jingjiting26和建议哈
由于昨天需求变得更复杂了点,所以结贴前我也把我现在用的算法公布一下吧
需求后来又加入了另一组时间段集合,从第一组时间段集合中排除掉第二组时间段集合,如下图
所以我现在的算法是new了个bool[86400]的数组(一天86400秒),默认所有值为false
将第一组所有时间段相应的秒设为true,在把第二组所有时间段相应的秒设为false
最后剩下来的为true的秒数就是所要的结果,但此算法仅限于算一天内的时间段
86400个boolean占用内存86K(如果我记得没错的话,一个bool一字节),经过测试跑一天的执行下来也就0.0几秒
但如果周期是一月或一年就不能用此方法了
键盘tops舞者 2011-03-02
  • 打赏
  • 举报
回复
贴图贴不上,copy上来结果
2011-03-02 6:10:58 2011-03-02 10:34:45
2011-03-02 10:55:00 2011-03-02 11:34:00
2011-03-02 13:09:34 2011-03-02 17:52:15
键盘tops舞者 2011-03-02
  • 打赏
  • 举报
回复
这个问题看起来不复杂啊
首先把数据读入DataTable dt里,然后

static void CombineData()
{
DataTable dt = new DataTable();
dt.Columns.Add(new DataColumn("StartTime", Type.GetType("System.DateTime")));
dt.Columns.Add(new DataColumn("EndTime", Type.GetType("System.DateTime")));

DataRow row = dt.NewRow();
row[0] = DateTime.Parse("06:10:58");
row[1] = DateTime.Parse("08:15:28");
dt.Rows.Add(row);

row = dt.NewRow();
row[0] = DateTime.Parse("07:38:56");
row[1] = DateTime.Parse("10:34:45");
dt.Rows.Add(row);

row = dt.NewRow();
row[0] = DateTime.Parse("10:55:00");
row[1] = DateTime.Parse("11:34:00");
dt.Rows.Add(row);

row = dt.NewRow();
row[0] = DateTime.Parse("13:09:34");
row[1] = DateTime.Parse("17:45:23");
dt.Rows.Add(row);

row = dt.NewRow();
row[0] = DateTime.Parse("14:23:12");
row[1] = DateTime.Parse("15:24:14");
dt.Rows.Add(row);

row = dt.NewRow();
row[0] = DateTime.Parse("16:14:25");
row[1] = DateTime.Parse("17:52:15");
dt.Rows.Add(row);

for (int i = dt.Rows.Count - 1; i >= 1; i--)
{
//从后往前判断
if (Convert.ToDateTime(dt.Rows[i - 1]["EndTime"].ToString()) > Convert.ToDateTime(dt.Rows[i]["StartTime"].ToString()) && Convert.ToDateTime(dt.Rows[i - 1]["EndTime"].ToString()) < Convert.ToDateTime(dt.Rows[i]["EndTime"].ToString()))
{
dt.Rows[i - 1]["EndTime"] = dt.Rows[i]["EndTime"];
dt.Rows.RemoveAt(i);
}
else if (Convert.ToDateTime(dt.Rows[i - 1]["EndTime"].ToString()) > Convert.ToDateTime(dt.Rows[i]["StartTime"].ToString()) && Convert.ToDateTime(dt.Rows[i - 1]["EndTime"].ToString()) > Convert.ToDateTime(dt.Rows[i]["EndTime"].ToString()))
{
dt.Rows.RemoveAt(i);
i++;
}
}

foreach (DataRow r in dt.Rows)
{
Console.WriteLine(r[0].ToString()+" "+r[1].ToString());
}
Console.ReadLine();
}


中午没睡觉,呵呵,好在整出来个结果

嗳嘉 2011-02-28
  • 打赏
  • 举报
回复
嗯。。。我想到的基本上也是给开始和结束时间的列分别排序,然后写循环用第一行的结束时间跟第二行的开始时间做比较,如果第二行的开始时间小于第一行的结束事件那么就用第二行的结束时间替换第一行的结束时间然后删除第二行,再将循环的行数减一继续比较。这么说能懂吧,我就偷懒不写代码了
zhlei616 2011-02-28
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 wuyq11 的回复:]
DateTime.Compare来比较
List<DataRow> lstRows = new List<DataRow>();

var result = lstRows.Where(row =>
DateTime.Now >= Convert.ToDateTime(row["StartTime"]) &&
DateTime.Now <= Convert.ToD……
[/Quote]
感谢回复,但是我想要的算法不是如何判断两个时间段交叉,而是合并一个时间段集合中的重叠时间段,所以重点可能在在如何遍历元素两两比较的问题上
wuyq11 2011-02-28
  • 打赏
  • 举报
回复
DateTime.Compare来比较
List<DataRow> lstRows = new List<DataRow>();

var result = lstRows.Where(row =>
DateTime.Now >= Convert.ToDateTime(row["StartTime"]) &&
DateTime.Now <= Convert.ToDateTime(row["EndTime"]));

if (result.Count() > 0) // 交叉

111,097

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧