CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 23
  1. #1
    Join Date
    Jan 2004
    Location
    Netherlands
    Posts
    24

    Need advice with datastructure

    Hi everybody,

    I'm pretty new to C++ so I don't know if I'm on the right track with the following subject.

    I'm making a little application to modify and view some logging information. Every log message has a group, subgroup and level (all integers) associated with it. Because I want to enable the user to select what group, subgroup and level he wants to see, I want to inspect the logfile and see what groups, subgroups and levels are available and store this information in a datastructure. The global structure should be something like a list or set of groups where every group has a set of subgroups and every subgroup a set of levels. Something structured like this:

    group
    - subgroup
    -- level
    -- level
    - subgroup
    -- level
    group
    - subgroup
    -- level

    I tried to implement this the following way:

    typedef std::set<int> levels;
    typedef std::map<int,levels> subgroup;
    typedef std::set<subgroup> subgroups;
    typedef std::map<int,subgroups> group;
    typedef std::set<group> groups;

    But I can't seem to acces my elements. Maybe I'm doing it the wrong way or maybe this is just not a recommendable datastructure. Anybody any advice?

  2. #2
    Join Date
    Feb 2002
    Posts
    5,757
    There are several solutions. One solution is a map within a map. Another solution is to wrap the innermost data in a structure and design a map to house the structure.

    Kuphryn

  3. #3
    Join Date
    Apr 2003
    Location
    Los Angeles area
    Posts
    776
    Code:
    class level
    { 
        int level;
        std::string message;
    }
    
    class subgroup
    {
       std::string subgroupname;
       std::vector<level> Levels;
    }
    
    class group
    {
        std::string groupname;
        std::vector<subgroup> Subgroups;
    }
    
    int main()
    {
        std::vector<group> logfile;
    }

  4. #4
    Join Date
    Jan 2004
    Location
    Netherlands
    Posts
    24
    Thnx for the help

    I tried several implementations including an adjustment to what I posted earlier, namely:

    typedef std::set<int> levels;
    typedef std::map<int,levels> subgroups;
    typedef std::map<int,subgroups> groups;

    But when implementing another part I discoverd that I needed more data then just an int so I tried something like the code of Joe Nellis and it works fine.

    But this raises another question. How to directly acces the vector's elements (with O(1), like in an array). I thought Vectors should be able to do that but I saw it only with an integer or string, not with a class. The integer value that every class has could act as a key.

  5. #5
    Join Date
    Aug 2002
    Location
    Cluj-Napoca,Romania
    Posts
    3,496
    You should overwrite the [] operator for that set:

    Code:
    class level
    {
    	//...
    };
    
    struct VectorLevels
    {
    private:
    	std::vector< level> vct;
    
    public:
    	inline level operator [] ( int n)
    	{	
    		int pos = 0;
    
    		//search for level = n and store it's value in pos ( or in an iterator)
    		//...
    
    		return vct.at( pos);
    	}
    };
    
    class subgroup
    {
       std::string subgroupname;
       VectorLeveles levels;
    }
    
    //...
    Har Har

  6. #6
    Join Date
    Jan 2004
    Location
    Netherlands
    Posts
    24
    Originally posted by PadexArt
    You should overwrite the [] operator for that set:

    Code:
    class level
    {
    	//...
    };
    
    struct VectorLevels
    {
    private:
    	std::vector< level> vct;
    
    public:
    	inline level operator [] ( int n)
    	{	
    		int pos = 0;
    
    		//search for level = n and store it's value in pos ( or in an iterator)
    		//...
    
    		return vct.at( pos);
    	}
    };
    
    class subgroup
    {
       std::string subgroupname;
       VectorLeveles levels;
    }
    
    //...
    But won't this searching for level = n cost me O(n) time? Or is this inevitable with the way I use vectors?

  7. #7
    Join Date
    Aug 2002
    Location
    Cluj-Napoca,Romania
    Posts
    3,496
    Yes, the cost will be indeed O(n).

    A fatser way ( that I can think of) would be to duplicate the information :

    Code:
    class VectorLevels
    {
    //same as above
    
    private:
    map::<int, level> searchMap; //same data as in the levels std::vector
    }
    So, in the [] operator you would actually use the search map.
    Har Har

  8. #8
    Join Date
    Jan 2004
    Location
    Netherlands
    Posts
    24
    So I guess it is not possible to keep using Vectors in this situation. Then a map indeed sounds like a better solution, although I don't like the idea of data duplication. Of course I could always remove the key from the level class and access that information via the key of the map. The stl documentation that I have also mentions a hash_map so I probably should use that one (I don't care about the order of the map, just the direct access is important). In any case, thanks for the help.

  9. #9
    Join Date
    Aug 2002
    Location
    Cluj-Napoca,Romania
    Posts
    3,496
    The data duplication was mentioned as I didn't know how fond you were of using vectors. If no requirements are for using the vector you can verry well use the map.
    Har Har

  10. #10
    Join Date
    Jan 2004
    Location
    Netherlands
    Posts
    24
    Well, I don't have a preference for any datastructure as long as it does the job. So I started with the adjustments for map, but now It won't compile anymore. The implementation using vectors was working fine and I think I try to acces the map elements the right way.

    Could it be that a map imposes additional constraints on its elements? Should I add some operators on the level class

  11. #11
    Join Date
    Aug 2002
    Location
    Cluj-Napoca,Romania
    Posts
    3,496
    Can you post your current code?
    Har Har

  12. #12
    Join Date
    Jan 2004
    Location
    Netherlands
    Posts
    24
    Code:
    class CLevel  
    {
    public:
    	bool visible;
    	CString text;
    	int level;
    
    	CLevel(int l_level);
    	virtual ~CLevel();
    };
    
    class CSubgroup  
    {
    public:
    	int subgroup;
    	CString text;
    	std::map<int,CLevel> levels;
    	
    	CSubgroup(int l_subgroup, int l_level);
    	virtual ~CSubgroup();
    };
    
    class CGroup  
    {
    public:
    	int group;
    	CString text;
    	std::map<int,CSubgroup> subgroups;
    
    	CGroup(int l_group, int l_subgroup, int l_level);
    	virtual ~CGroup();
    };
    
    class CGroups  
    {
    public:
    
    //I'm planning to add some access and alter function here
    
    	std::map<int,CGroup> m_groups;
    
    	CGroups();
    	virtual ~CGroups();
    };
    
    // This is where I use these classes, m_logData is an instance of CGroups
    
    void CSimpelDlg::addLine(int g, int s, int l)
    {
    	std::map<int,CGroup>::iterator g_pos = m_logData.m_groups.begin();
    	while (g_pos != m_logData.m_groups.end())
    	{
    		if (g_pos->first == g)
    		{
    			// insert s and l in g
    			std::map<int,CSubgroup>::iterator s_pos = g_pos->second.subgroups.begin();
    			while (s_pos != g_pos->second.subgroups.end())
    			{
    				if (s_pos->first == s)
    				{
    					//insert l in s and g
    
    					std::map<int,CLevel>::iterator l_pos = s_pos->second.levels.begin();
    					while (l_pos != s_pos->second.levels.end())
    					{
    						if (l_pos->first == l)
    						{
    							// l does already exist in g and s, do nothing
    							return;
    						}
    						l_pos++;
    					}
    					//l does not exists in g and s, make new l in s with value l
    					s_pos->second.levels[l] = CLevel(l);
    					return;
    				}
    				s_pos++;
    			}
    			//s does not exist in g, make new s in g with values s and l
    			g_pos->second.subgroups[s] = CSubgroup(s,l);
    			return;
    		}
    		g_pos++;
    	}
    	// g does not exist yet, make new g in m_classgroups with values g,s and l
    	m_logData.m_groups[g] = CGroup (g,s,l);
    	return;
    
    }//addLine
    I really appreciate you helping me out, cause without such help I would never get so far

  13. #13
    Join Date
    Jan 2004
    Location
    Netherlands
    Posts
    24
    Nevermind, I already discovered the origin of the compile errors. A map needs a standard constructor and I made a constructor with arguments (although all arguments had default values). Now I just added a default constructor and both the compiler and I are happy.

  14. #14
    Join Date
    Aug 2002
    Location
    Cluj-Napoca,Romania
    Posts
    3,496
    This makes me happy too.
    Har Har

  15. #15
    Join Date
    Aug 2000
    Location
    West Virginia
    Posts
    7,725
    I think the reason for the compile error is as follows:

    Code:
    // g does not exist yet, make new g in m_classgroups with values g,s and l
    m_logData.m_groups[g] = CGroup (g,s,l);
    you are using operator [] to add to the m_groups map. This
    is OK - except you need to know how it usually works
    internally (following is basically from Scott Meyer's "Effective STL",
    Item 24 : Choose carefully between map::operator [] and
    map::insert when efficiency is important).

    when doing the following :

    Code:
    m_logData.m_groups[g] = CGroup (g,s,l);
    The first thing that is done, is a check to see if the key "g"
    is already in the map. If it is, it updates the value. If not,
    it creates an object using the VALUE types DEFAULT
    constructor, then updates it (CGroup(g,s,l)). Your class
    CGroup does not have a default constructor, so it can
    not create an object to add. You can get around this in one
    of two ways :

    1) change CGroup's constructor :

    Code:
    CGroup(int l_group = 1, int l_subgroup = 1, int l_level = 1);
    2) or use insert instead of operator [] ...

    Code:
    m_logData.m_groups.insert( make_pair(g,CGroup (g,s,l)) );
    Note: the same is true for your other classes

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured