Java 数据结构的层次结构为“年”>“月”>“日”>“字符串”?

问题描述 投票:0回答:6

我需要表示以下数据(用Java):

  • 2012年(年)
    • 01(月)
      • 01(日)
        • 你好我是一根绳子
      • 02
      • ...
    • 02
    • 03
    • 04

我正在考虑使用 TreeMap,但不知道如何使用。有什么想法吗?

java data-structures dictionary tree
6个回答
2
投票

注意事项,假设您对管理日历条目感兴趣

  • 有无限可能的日期——不要在未使用的日子上浪费内存
  • 给定一个日期,您希望快速访问当天的日期 -- 使用 数组或基于哈希的查找
  • 每一天都有一个唯一的日期 -- 地图日期 => 天

模型

// best to use ENUM for fixed set of constants
enum Month {
    JANUARY, FEBRUARY, ... , NOVEMBER, DECEMBER
}

enum Weekday {
    SUNDAY, MONDAY, ... , FRIDAY, SATURDAY
}

/**
 * The day "data node". Fill in constructors/accessors.
 */
class Day {
    int year;
    Month month;
    Weekday weekday;
    String date; // hashkey
    String entry; // the entry
}

/**
 * The calendar, simply mapping a unique date to it's day.
 * Create a date like: year + "-" + MONTH + "-" + DAY
 */
HashMap<String, Day> calendar;

在 Java 8 及更高版本中,您可以使用预定义的枚举:

Month
DayOfWeek

景色
由于我们的数据结构并不稀疏,因此独立视图必须模拟完整的日历。根据日历的规则显示所有日期/生成所有日期,但如果保存新条目,则仅在

HashMap
中添加一天。

注释

  • 在空间和时间上都非常高效。
  • 上面过于简化:将
    HashMap
    包装在一个类中以仲裁 days 上的
    CRUD
    操作。
  • 假设您不需要操纵月/年,而只需操纵天。如果这是错误的,并且您想要例如将所有日期放在
    month
    中,或删除
    year
    ,考虑在上面放置一个像
    year => month => day
    这样的三级地图。

0
投票

Swing 中的 JTree 也可以用作数据结构。

但是您应该问自己的第一个问题是“我想如何访问数据”。


0
投票

您需要某种树结构。 这可能是您的起点:

public class Node {
    private String label;
    private List<Node> children;
    //add Constructors, getters, setters, and member methods, etc
}


Node root = new Node();
root.setLabel("2012");
//children of root are "01", "02", etc.

0
投票

将模型数据与视图数据明确分开。

这是一个与佩斯利答案中提出的模型不同的模型。

Map<Calendar, String> thisIsAllYouNeedForTheModel = new HashMap<Calendar, String>();
Calendar thisIsTheKey = Calendar.getInstance();

thisIsTheKey.clear();
thisIsTheKey.set(Calendar.YEAR, theYear);
thisIsTheKey.set(Calendar.MONTH, theMonth);
thisIsTheKey.set(Calendar.DAY_OF_MONTH, theMonth);
thisIsTheKey.set(Calendar.HOUR, theHour);
thisIsTheKey.set(Calendar.MINUTE, theMinute);
thisIsTheKey.set(Calendar.SECOND, theSecond);
thisIsAllYouNeedForTheModel.put(thisIsTheKey, data);

编辑:我傻了。

Map<Calendar, String>
是我的建议。


0
投票

tl;博士

SequencedMap < LocalDate , String > map = new TreeMap<>() ;
map.put( LocalDate.of( 2012 , Month.JANUARY , 1 ) , "Hello I am a string" ) ;

java.time

在 Java 8+ 中,使用现代的 java.time 类取代了存在严重缺陷的遗留日期时间类。

对于没有时间、没有时区或偏移量的仅日期值,请使用

LocalDate
。一个月,使用
Month
枚举。

将每个日期映射到其文本片段。通过 Oracle 免费提供的本教程了解有关 Java 集合框架中的映射的信息。

SequencedMap

您可能希望按时间顺序保留地图条目。根据定义,

Map

 没有遭遇顺序。所以在现代 Java 中,使用 
SequencedMap
 接口。在旧版 Java 中使用 
NavigableMap
。在古老的 Java 中,使用 
SortedMap

与 Java 实现

SequencedMap

 捆绑在一起的三个类:
ConcurrentSkipListMap
LinkedHashMap
TreeMap
。根据您的需求,如果不是多线程,请使用 
TreeMap
 作为选择的实现。

SequencedMap < LocalDate , String > map = new TreeMap<>() ;
要了解 Java 21+ 中的顺序集合,请参阅 

Nicolai Parlog 的视频、官方文档 JEP 431:顺序集合Stuart Marks 的演讲

添加您的条目。

LocalDate ld = LocalDate.of( 2012 , Month.JANUARY , 1 ) ; // 2012-01-01. map.put( ld , "Hello I am a string" ) ;
检索:

String s = map.get( ld ) ; // Retrieve the string value for this `LocalDate` key.
层次结构

如果需要,您可以将这个简单的两级地图作为四级层次结构进行访问。

此方法循环遍历

SequencedMap

 以查看键,在本例中为所有 
LocalDate
 值。我们得到了一个不同的年份排序列表,使用 
Year
 类表示。然后,对于这些年份中的任何一年,我们都可以获得一个不同的排序月份列表,由 
Month
 枚举表示。最后,对于任何月份(和年份),我们都可以通过 
auto-boxing 获得表示为
Integer
对象的不同排序的月份数字列表。

这种方法很简单,但

效率不高。由于代码简单(基本上都是单行代码!),我确实会选择这种方法用于数据量较小的生产用途。对于大量数据,您将需要不同的方法。

这是我们用于表示年-月-日-字符串层次结构的类。

package work.basil.example.hierarchy; import java.time.LocalDate; import java.time.Month; import java.time.Year; import java.time.YearMonth; import java.util.SequencedCollection; import java.util.SequencedMap; import java.util.TreeMap; public class YearMonthDayStringHierarchy { private final SequencedMap < LocalDate, String > map = new TreeMap <>( ); public String put ( final LocalDate localDate , final String string ) { return map.put( localDate , string ); } public String get ( final LocalDate localDate ) { return map.get( localDate ); } public String get ( final Year year , final Month month , final Integer day ) { return map.get( LocalDate.of( year.getValue( ) , month , day ) ); } // Convenience method. public SequencedCollection < Year > years ( ) { return this .map .sequencedKeySet( ) .stream( ) .map( Year :: from ) .distinct( ) .sorted( ) .toList( ); } SequencedCollection < Month > monthsForYear ( final Year year ) { return this .map .sequencedKeySet( ) .stream( ) .filter( localDate -> Year.from( localDate ).equals( year ) ) .map( Month :: from ) .distinct( ) .sorted( ) .toList( ) ; } SequencedCollection < Integer > daysForYearMonth ( final Year year , final Month month ) { final YearMonth yearMonth = YearMonth.of( year.getValue( ) , month ); // Odd that `YearMonth` has no `of` factory method taking `Year` object. So extract primitive year number. return this .map .sequencedKeySet( ) .stream( ) .filter( localDate -> YearMonth.from( localDate ).equals( yearMonth ) ) .map( LocalDate :: getDayOfMonth )// Auto-boxed to Integer. .distinct( ) .sorted( ) .toList( ) ; } }
这是一个用于练习该代码的示例应用程序。

package work.basil.example.hierarchy; import java.time.LocalDate; import java.time.Month; import java.time.Year; import java.time.ZoneId; public class YearMonthDayStringHierarchyApp { public static void main ( String[] args ) { YearMonthDayStringHierarchyApp app = new YearMonthDayStringHierarchyApp( ); app.demo( ); } private void demo ( ) { YearMonthDayStringHierarchy map = new YearMonthDayStringHierarchy( ); LocalDate v2012_01_01 = LocalDate.of( 2012 , Month.JANUARY , 1 ); // 2012-01-01. map.put( v2012_01_01 , "Hello I am a string" ); LocalDate today = LocalDate.now( ZoneId.of( "America/Edmonton" ) ); map.put( today , "Today is " + today + "." ); LocalDate yesterday = today.minusDays( 1 ); map.put( yesterday , "Yesterday is " + yesterday + "." ); for ( Year year : map.years( ) ) { System.out.println( year ); for ( Month month : map.monthsForYear( year ) ) { System.out.println( " ".repeat( 4 ) + month ); for ( Integer day : map.daysForYearMonth( year , month ) ) { System.out.println( " ".repeat( 8 ) + day ); System.out.println( " ".repeat( 12 ) + map.get( year , month , day ) ); } } } } }
运行时:

2012 JANUARY 1 Hello I am a string 2024 AUGUST 28 Yesterday is 2024-08-28. 29 Today is 2024-08-29.


由于我们使用了

SequencedMap

,对 
.sorted
 的调用可能是不必要的。我考虑得不够仔细,也没有测试过他们的遗漏。


顺便说一句,您可以折叠嵌套的

for

 循环,如下所示。但我认为这更难读。

map.years( ).forEach( year -> { System.out.println( year ); map.monthsForYear( year ).forEach( month -> { System.out.println( " ".repeat( 4 ) + month ); map.daysForYearMonth( year , month ).forEach( day -> { System.out.println( " ".repeat( 8 ) + day ); System.out.println( " ".repeat( 12 ) + map.get( year , month , day ) ); } ); } ); } );
    

-1
投票
我建议使用 TreeMap,但如果你想进行实验,就使用 LinkedList 吧。如果您迭代许多列表,则访问数据会非常复杂。但实验很有趣。

编辑:这是一个教程,其中包括一个包,允许您使用 TreeMap 或类似于树的东西:

http://code.google.com/p/qed-java/wiki/HowToUseTree

© www.soinside.com 2019 - 2024. All rights reserved.