<?xml version="1.0" encoding="UTF-8"?>
<!-- generator="FeedCreator 1.8" -->
<?xml-stylesheet href="https://baszerr.eu/lib/exe/css.php?s=feed" type="text/css"?>
<rss version="2.0">
    <channel xmlns:g="http://base.google.com/ns/1.0">
        <title>BaSzErr - blog:2014:12:16</title>
        <description></description>
        <link>https://baszerr.eu/</link>
        <lastBuildDate>Fri, 01 May 2026 06:48:40 +0000</lastBuildDate>
        <generator>FeedCreator 1.8</generator>
        <image>
            <url>https://baszerr.eu/lib/exe/fetch.php?media=wiki:dokuwiki.svg</url>
            <title>BaSzErr</title>
            <link>https://baszerr.eu/</link>
        </image>
        <item>
            <title>unordered_array</title>
            <link>https://baszerr.eu/doku.php?id=blog:2014:12:16:unordered_array</link>
            <description>
&lt;h1 class=&quot;sectionedit1&quot; id=&quot;unordered_array&quot;&gt;2014-12-16 - unordered array&lt;/h1&gt;
&lt;div class=&quot;level1&quot;&gt;

&lt;p&gt;
recently i was in a need of fast and compact container to keep data, that changes very often. amount of insertions, removals and searches were pretty equal and very frequent. fortunately size was expected to be small - tens to hundreds of elements. of course the most cache-friendly data structure is linear array (read: &lt;em&gt;vector&lt;/em&gt;). can we do even better?
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;2014-12-16 - unordered array&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;unordered_array&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:0,&amp;quot;secid&amp;quot;:1,&amp;quot;range&amp;quot;:&amp;quot;1-403&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit2&quot; id=&quot;assumptions&quot;&gt;assumptions&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;
generally &lt;em&gt;vector&lt;/em&gt; is fast, but removal of elements from the middle is a bit more painful. to deal with it i&amp;#039;ve decided to create an array that by design does not guarantee any particular order, after insertion and removal. when the size does not change, elements can be reorder, in terms of swapping/assigning. it&amp;#039;s just size-changing operations that destroy any order. also all size-modifying operations invalidate all iterators. when container shrinks, unlike the &lt;em&gt;vector&lt;/em&gt;, it can shrink as well. i&amp;#039;ve called the container &lt;a href=&quot;https://github.com/el-bart/but/blob/master/But/UnorderedArray.hpp&quot; class=&quot;urlextern&quot; title=&quot;https://github.com/el-bart/but/blob/master/But/UnorderedArray.hpp&quot; rel=&quot;ugc nofollow&quot;&gt;unordered array&lt;/a&gt; (available as a part of &lt;a href=&quot;https://github.com/el-bart/but&quot; class=&quot;urlextern&quot; title=&quot;https://github.com/el-bart/but&quot; rel=&quot;ugc nofollow&quot;&gt;but&lt;/a&gt; library).
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;assumptions&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;assumptions&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:0,&amp;quot;secid&amp;quot;:2,&amp;quot;range&amp;quot;:&amp;quot;404-1119&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit3&quot; id=&quot;operations&quot;&gt;operations&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;
since no particular order is assumed, addition is simple. it means appending one more element at the end.
&lt;/p&gt;

&lt;p&gt;
removal is also done in situ as well. instead of moving all elements from the given position until the end, one place backwards (as in &lt;em&gt;vector&lt;/em&gt;), last element is being moved to the position of the element to be removed and the stub of last element is being removed.
&lt;/p&gt;

&lt;p&gt;
searching for an element is done in a linear fashion, as usual.
&lt;/p&gt;
&lt;div class=&quot;table sectionedit4&quot;&gt;&lt;table class=&quot;inline&quot;&gt;
	&lt;thead&gt;
	&lt;tr class=&quot;row0&quot;&gt;
		&lt;th class=&quot;col0&quot;&gt; operation &lt;/th&gt;&lt;th class=&quot;col1&quot;&gt; UnorderedArray &lt;/th&gt;&lt;th class=&quot;col2&quot;&gt; vector &lt;/th&gt;
	&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tr class=&quot;row1&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; add &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; O(1) &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; O(N) &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row2&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; remove &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; O(1) &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; O(N) &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row3&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt; find &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; O(N) &lt;/td&gt;&lt;td class=&quot;col2&quot;&gt; O(N) &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;table&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;table&amp;quot;,&amp;quot;secid&amp;quot;:4,&amp;quot;range&amp;quot;:&amp;quot;1585-1694&amp;quot;} --&gt;
&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;operations&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;operations&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:0,&amp;quot;secid&amp;quot;:3,&amp;quot;range&amp;quot;:&amp;quot;1120-1696&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit5&quot; id=&quot;test_scenario&quot;&gt;test scenario&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;
to see how it behaves i&amp;#039;ve done some measurements. they are all done using algorithm, that reassembles my actual use case. it goes like this:
&lt;/p&gt;
&lt;pre class=&quot;code c&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;const&lt;/span&gt; vector&lt;span class=&quot;sy0&quot;&gt;&amp;lt;&lt;/span&gt;int&lt;span class=&quot;sy0&quot;&gt;&amp;gt;&lt;/span&gt; valuesToAdd &lt;span class=&quot;sy0&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;coMULTI&quot;&gt;/*...*/&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;;&lt;/span&gt;
Container c&lt;span class=&quot;sy0&quot;&gt;;&lt;/span&gt;
c.&lt;span class=&quot;me1&quot;&gt;reserve&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt; valuesToAdd.&lt;span class=&quot;me1&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;// fill&lt;/span&gt;
&lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;auto&lt;/span&gt; v&lt;span class=&quot;sy0&quot;&gt;:&lt;/span&gt; valuesToAdd&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
  c.&lt;span class=&quot;me1&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;v&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;// search and remove&lt;/span&gt;
&lt;span class=&quot;kw4&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;auto&lt;/span&gt; queries &lt;span class=&quot;sy0&quot;&gt;=&lt;/span&gt; randomizeOrder&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;valuesToAdd&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;auto&lt;/span&gt; q&lt;span class=&quot;sy0&quot;&gt;:&lt;/span&gt; queries&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
  &lt;span class=&quot;kw4&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;auto&lt;/span&gt; it &lt;span class=&quot;sy0&quot;&gt;=&lt;/span&gt; std&lt;span class=&quot;sy0&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;me2&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt; c.&lt;span class=&quot;me1&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; c.&lt;span class=&quot;me1&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; q &lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;;&lt;/span&gt;
  c.&lt;span class=&quot;me1&quot;&gt;erase&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;it&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;
check out an &lt;a href=&quot;https://github.com/el-bart/but/blob/master/But/UnorderedArray_speed.manual.cpp&quot; class=&quot;urlextern&quot; title=&quot;https://github.com/el-bart/but/blob/master/But/UnorderedArray_speed.manual.cpp&quot; rel=&quot;ugc nofollow&quot;&gt;actual implementation of test case&lt;/a&gt; for details.
&lt;/p&gt;

&lt;p&gt;
for measurements i&amp;#039;ve selected several containers to compare with &lt;em&gt;UnorderedArray&lt;/em&gt;:
&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;em&gt;vector&lt;/em&gt; – to see if it is much slower.&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;em&gt;deque&lt;/em&gt; – to check if it is significantly slower.&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;em&gt;set&lt;/em&gt; – to compare with balanced search tree.&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;em&gt;unordered_set&lt;/em&gt; – to compare with hash table and amortized O(1) access.&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;em&gt;list&lt;/em&gt; – just for the record… ;)&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;test scenario&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;test_scenario&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:0,&amp;quot;secid&amp;quot;:5,&amp;quot;range&amp;quot;:&amp;quot;1697-2694&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit6&quot; id=&quot;measurements&quot;&gt;measurements&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;
&lt;a href=&quot;https://baszerr.eu/lib/exe/detail.php?id=blog%3A2014%3A12%3A16%3Aunordered_array&amp;amp;media=blog:2014:12:16:data_points.png&quot; class=&quot;media&quot; title=&quot;blog:2014:12:16:data_points.png&quot;&gt;&lt;img src=&quot;https://baszerr.eu/lib/exe/fetch.php?w=500&amp;amp;tok=f5177d&amp;amp;media=blog:2014:12:16:data_points.png&quot; class=&quot;media&quot; loading=&quot;lazy&quot; title=&quot;all data points&quot; alt=&quot;all data points&quot; width=&quot;500&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;https://baszerr.eu/lib/exe/detail.php?id=blog%3A2014%3A12%3A16%3Aunordered_array&amp;amp;media=blog:2014:12:16:data_points-no-list.png&quot; class=&quot;media&quot; title=&quot;blog:2014:12:16:data_points-no-list.png&quot;&gt;&lt;img src=&quot;https://baszerr.eu/lib/exe/fetch.php?w=500&amp;amp;tok=c43c08&amp;amp;media=blog:2014:12:16:data_points-no-list.png&quot; class=&quot;media&quot; loading=&quot;lazy&quot; title=&quot;all data points, without the list&quot; alt=&quot;all data points, without the list&quot; width=&quot;500&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;https://baszerr.eu/lib/exe/detail.php?id=blog%3A2014%3A12%3A16%3Aunordered_array&amp;amp;media=blog:2014:12:16:data_points_0_to_2000.png&quot; class=&quot;media&quot; title=&quot;blog:2014:12:16:data_points_0_to_2000.png&quot;&gt;&lt;img src=&quot;https://baszerr.eu/lib/exe/fetch.php?w=500&amp;amp;tok=4576c2&amp;amp;media=blog:2014:12:16:data_points_0_to_2000.png&quot; class=&quot;media&quot; loading=&quot;lazy&quot; title=&quot;0-2k range&quot; alt=&quot;0-2k range&quot; width=&quot;500&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;https://baszerr.eu/lib/exe/detail.php?id=blog%3A2014%3A12%3A16%3Aunordered_array&amp;amp;media=blog:2014:12:16:data_points_0_to_2000-no-list-no-deque.png&quot; class=&quot;media&quot; title=&quot;blog:2014:12:16:data_points_0_to_2000-no-list-no-deque.png&quot;&gt;&lt;img src=&quot;https://baszerr.eu/lib/exe/fetch.php?w=500&amp;amp;tok=dc9fc2&amp;amp;media=blog:2014:12:16:data_points_0_to_2000-no-list-no-deque.png&quot; class=&quot;media&quot; loading=&quot;lazy&quot; title=&quot;0-2k range w/o list and deque&quot; alt=&quot;0-2k range w/o list and deque&quot; width=&quot;500&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
all measurements, containing &lt;em&gt;list&lt;/em&gt; clearly show that… &lt;em&gt;list&lt;/em&gt; just gets in the way. ;) there is just one interesting point there, that shows sudden speedup of the &lt;em&gt;list&lt;/em&gt; around 7k elements – looks like the &lt;em&gt;list&lt;/em&gt; is not only slow but also haunted. ;) just stay away from it.
&lt;/p&gt;

&lt;p&gt;
&lt;em&gt;unordered_set&lt;/em&gt; was the fastest container for more than ~1.2k elements. up to that point, &lt;a href=&quot;https://github.com/el-bart/but/blob/master/But/UnorderedArray.hpp&quot; class=&quot;urlextern&quot; title=&quot;https://github.com/el-bart/but/blob/master/But/UnorderedArray.hpp&quot; rel=&quot;ugc nofollow&quot;&gt;UnorderedArray&lt;/a&gt; was the fastest container there is. in terms of speed, next non-associative container is &lt;em&gt;vector&lt;/em&gt;. here is a comparison of these two:
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;https://baszerr.eu/lib/exe/detail.php?id=blog%3A2014%3A12%3A16%3Aunordered_array&amp;amp;media=blog:2014:12:16:data_points_small_vec_vs_ua.png&quot; class=&quot;media&quot; title=&quot;blog:2014:12:16:data_points_small_vec_vs_ua.png&quot;&gt;&lt;img src=&quot;https://baszerr.eu/lib/exe/fetch.php?w=500&amp;amp;tok=cab417&amp;amp;media=blog:2014:12:16:data_points_small_vec_vs_ua.png&quot; class=&quot;media&quot; loading=&quot;lazy&quot; title=&quot;UnorderedArray vs. std::vector for small number of elements&quot; alt=&quot;UnorderedArray vs. std::vector for small number of elements&quot; width=&quot;500&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;measurements&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;measurements&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:1,&amp;quot;secid&amp;quot;:6,&amp;quot;range&amp;quot;:&amp;quot;2695-3741&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit7&quot; id=&quot;final_remarks&quot;&gt;final remarks&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;
for my use case UnorderedArray was a clear winner. however please keep in mind that this comparison is far from being comprehensive. it shows a particular test case only, that i happened to need. it also does not include neither different compilers nor hardware platforms. consider it an inspiration more than an oracle… ;)
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;final remarks&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;final_remarks&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:1,&amp;quot;secid&amp;quot;:7,&amp;quot;range&amp;quot;:&amp;quot;3742-&amp;quot;} --&gt;</description>
            <author>anonymous@undisclosed.example.com (Anonymous)</author>
            <pubDate>Tue, 15 Jun 2021 20:08:56 +0000</pubDate>
        </item>
    </channel>
</rss>
