Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

BokkyPooBah's Red-Black Binary Search Tree Library

License

NotificationsYou must be signed in to change notification settings

bokkypoobah/BokkyPooBahsRedBlackTreeLibrary

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation



BokkyPooBahs Red-Black Binary Search Tree Library

Status:Currently being tested and bug bounty open. Don't use in production without an audit, yet.

A gas-efficient Solidity library using the iterative (rather than recursive) Red-Black binary search tree algorithm to help you maintain a sorteduint key index for your data. Insertions, deletions and searches are inO(log n) time (and ~gas). Note that the key of 0 is prohibited. Use the sorted keys as indices to your mapping tables of data to access your data in sorted order.

Inserting a key into an empty tree costs 68,459 gas. Inserting a key into a tree with 9,999 keys costs 127,210 gas on average. Removing an element from a tree with a single key costs 44,835 gas. Removing a key from a tree with 10,000 keys cost 81,486 gas on average.

An important use-case for this library is to maintain a sorted on-chain order book in decentralised exchange smart contracts, providing a provably fair order matching algorithm.

Check out the onlineRed-black tree visualization tool- type in some 4 digit numbers and press Insert or Delete to see the insertions and rebalances animated.

See alsoHitchen's Order Statistics Tree, an extension built from this library.



Table Of Contents



Overview

Binary Search Tree

TheRed-Black Tree binary search tree is a self-rebalancingbinary search tree. Following is a diagram of a fairly well-balanced binary search tree.

The following unbalanced binary search tree was generated by inserting the numbers 1 to 32 in sequential order[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32]:

Inserting the keys into the binary search tree in sequential order will result in this unbalanced tree resembling a linked-list.


Red-Black Binary Search Tree

The red-black algorithm maintains a red or black colouring for each node in the tree, and uses this information to maintain a reasonably balanced tree. FromWikipedia:

In addition to the requirements imposed on a binary search tree the following must be satisfied by a red–black tree:

  • Each node is either red or black.
  • The root is black. This rule is sometimes omitted. Since the root can always be changed from red to black, but not necessarily vice versa, this rule has little effect on analysis.
  • All leaves (NIL) are black.
  • If a node is red, then both its children are black.
  • Every path from a given node to any of its descendant NIL nodes contains the same number of black nodes.

When an element is inserted into or removed from a red-black tree, the binary search tree is rebalanced to satisfy the red-black rules.

From Wikipedia'sRed-Black Tree page, the following Red-Black tree was created by inserting the items[13,8,17,11,15,22,25,27,1,6]:


Red-Black Tree With Random Insertion

The following fairly well-balanced red-black tree was generated by inserting the numbers 1 to 32 in random order[15,14,20,3,7,10,11,16,18,2,4,5,8,19,1,9,12,6,17,13]:

The root node of the tree is 18,k represents the key numbers,p the parent,l the left node,r the right node. Nodes withl0 r0 are the leaves of the tree.


Red-Black Tree With Sequential Insertion

The following red-black tree was generated by inserting the numbers 1 to 32 in sequential order[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32]:

A property of the red-black tree is that the path from the root to the farthest leaf is no more than twice as long as the path from the root to the nearest leaf. The shortest path has all black nodes and the longest path alternate between red and black nodes.

The shortest path is 4 levels deep: (8 black), (4 black), (2 black), (1 black).

The longest path is 8 levels deep: (8 black), (16 red), (20 black), (24 red), (28 black), (30 red), (31 black), (32 red). This is no more than twice as long as the shortest path.



Gas Cost

Following is a chart with the minimum, average and maximum gas cost for insertions and deletions from a Red-Black Tree. The result have been generated by insering random data in the first case, and sequential data in the second case.

Data and chart -docs/GasStatistics.xlsx. These statistics have been generated using thetest/02_test2.sh script with the results logged intest/test2results.txt - the parametersNUMBEROFITEMS,BATCHSIZE were varied for the results with different number of items, and theinsertItems = shuffle(insertItems); andremoveItems = shuffle(removeItems); commented out for sequential insertions.


Random Insertion Gas Cost

The following table shows the minimum, average and maximum gas cost for the insertion of items in arandom order and removal of items from a red-black tree:

ItemsIns MinIns AvgIns MaxRem MinRem AvgRem Max
168,91368,91368,91344,65444,65444,654
568,91399,588140,40429,82740,89156,405
1068,913108,635141,51827,37544,88090,688
5068,913121,753182,64527,37564,977179,109
10068,913122,549186,76627,37565,447143,832
50068,913124,790191,55927,37566,629215,994
1,00068,977128,550195,71927,37567,331195,574
5,00068,977127,029200,23327,37566,966258,858
10,00068,977127,516200,90727,37566,781240,152

Note that the statistics above will change with each execution, as the data inserted is randomised.


Sequential Insertion Gas Cost

The following table shows the minimum, average and maximum gas cost for the insertion of items in asequential order and removal of items from a red-black tree:

ItemsIns MinIns AvgIns MaxRem MinRem AvgRem Max
168,91368,91368,91344,65444,65444,654
568,913107,761141,12929,82744,88380,922
1068,913116,896149,93829,82753,457104,650
5068,913138,234158,84429,82761,485151,002
10068,913143,145163,29729,82763,540174,178
50068,913149,417191,13429,85966,239219,978
1,00068,913150,878208,36029,85966,774243,154
5,00068,913153,219242,81329,85967,276304,485
10,00068,913154,017260,04029,85967,352327,661


History

VersionDateNotes
v0.90-pre-releaseFeb 17 2019Bug bounty added
v1.0 pre-release-aMar 8 2019Incorporatedsuggestions fromRob Hitchens


Bug Bounty Scope And Donations

Details of the bug bounty program for this project can be found atBokkyPooBah's Hall Of Fame And Bug Bounties. Please considerdonating to support the bug bounty, and the development and maintenance of decentralised applications.

The scope of the bug bounty for this project follows:


Bounties awarded for this project:



Deployment

This library has been designed to be automatically compiled into your Ethereum Solidity contract or library, instead of having to deploy this library and then linking your contract or library to this library.



Questions And Answers

What would I use this library for?

Any smart contract where you need to maintain a sorted list of unsigned integers. One major use case is for this RBT library to maintain a decentralised exchange orderbook, sorted by price.


Why does this library only store unsigned integers and not any additional data?

This library was designed to be a simple component to be used within your smart contract project.

Store any additional data, e.g., key/value pairs, by adding the functionality into your smart contract. Sample code fromcontracts/TestBokkyPooBahsRedBlackTree.sol follows:

contractTestBokkyPooBahsRedBlackTree{usingBokkyPooBahsRedBlackTreeLibraryforBokkyPooBahsRedBlackTreeLibrary.Tree;BokkyPooBahsRedBlackTreeLibrary.Treetree;mapping(uint=>uint)values;eventLog(stringwhere,uintkey,uintvalue);    ...functiongetNode(uint_key)publicviewreturns(uintkey,uintparent,uintleft,uintright,boolred,uintvalue){if(tree.exists(_key)){BokkyPooBahsRedBlackTreeLibrary.Nodememorynode=tree.getNode(_key);(key,parent,left,right,red)=(_key,node.parent,node.left,node.right,node.red);value=values[_key];}}functioninsert(uint_key,uint_value)public{tree.insert(_key);values[_key]=_value;emitLog("insert",_key,_value);}functionremove(uint_key)public{tree.remove(_key);emitLog("remove",_key,values[_key]);deletevalues[_key];}}

Why can't I use 0 as a key?

This library has been configured with theEMPTY marker set to '0'. This can be set to non-0, but you will have to add some additional functionality - you can get an idea of the functionality you will need to add back from anolder untested version of the library. Search forinit(...) and the last line ofgetNode(...). Please test carefully!


Can duplicate keys be inserted?

No



Functions

Seecontracts/TestBokkyPooBahsRedBlackTree.sol (or theflattened version) for an example contract that uses this library.

Notes:

  • The function parameterTree storage self has been omitted in the documentation below, as Solidity automatically injects the library data structure in place of this first parameter
  • There is a constantEMPTY that is set to 0 in the library source code by default
  • Theinsert(...) andremove(...) functions haveinternal visibility so it is easy to deploy your contract, as these function calls will be inlined. There may be cases where you may want to specify apublic visibility so the is not inlined and duplicated in the deployment EVM code.

root

functionroot()internalviewreturns(uint_key);

Returns the root of the tree, orEMPTY is the tree is empty.


first

functionfirst()internalviewreturns(uint_key);

Returns the smallest key in the tree.

Return ValueCondition
{first key}Tree has at least one key
EMPTYTree empty

last

functionlast()internalviewreturns(uint_key);

Returns the largest key in the tree.

Return ValueCondition
{last key}Tree has at least one key
EMPTYTree empty

next

functionnext(uintx)internalviewreturns(uinty);

Returns the next key in the tree with a value larger thanx.

Return ValueCondition
{next key}There exists a key with a value larger than thex key
EMPTYTree empty
EMPTYx is not an existing key in the tree
EMPTYx is the only key in the tree
EMPTYx is the last key in the tree

prev

functionprev(uintx)internalviewreturns(uinty);

Returns the previous key in the tree with a value smaller thanx.

Return ValueCondition
{prev key}There exists a key with a value smaller than thex key
EMPTYTree empty
EMPTYx is not an existing key in the tree
EMPTYx is the only element in the tree
EMPTYx is the last element in the tree

exists

functionexists(uintkey)internalviewreturns(bool_exists);

Returnstrue if the key exists in the tree,false otherwise.

Return ValueCondition
truekey is an existing key in the tree
falseTree empty
falsekey is not an existing key in the tree

isEmpty

functionisEmpty(uintkey)internalpurereturns(bool);

Returnstrue if the key exists in the tree,false otherwise.

Return ValueCondition
truekey is an existing key in the tree
falseTree empty
falsekey is not an existing key in the tree

getEmpty

functiongetEmpty()internalpurereturns(uint);

Returns the value of the EMPTY variable


getNode

functiongetNode(uintkey)internalviewreturns(uint_returnKey,uint_parent,uint_left,uint_right,bool_red);

Returns the node information ifkey exists in the tree. Alluint values will be set toEMPTY ifkey does not exist in the tree.


insert

functioninsert(uintkey)internal;

Insert the keykey into the tree.

TransactionCondition
successkey has been successfully inserted into the tree
failurekey already exists in the tree

remove

functionremove(uintkey)internal;

Remove the keykey from the tree.

TransactionCondition
successkey has been successfully removed from the tree
failurekey does not exist in the tree


Algorithm

The main Red-Black binary search tree algorithm is listed inAlgorithms for Red Black Tree Operations(from CLRS text).

Note that this algorithm is designed to work with memory pointers to the node data. The rebalancing process after the removal of an item from the tree may result in a swapping of data values between nodes.

As the nodes are stored as elements in a Soliditymapping data structure,Iterative Algorithm for Red-Black Tree provides an alternative algorithm to perform this swapping. In particular, the functionRB-Delete in the main Red-Black algorithm will need the linethen key[z] := key[y] replaced with the alternative swapping algorithm.



Testing

  • Test random insertions and deletions of 1, 10, 100, 1000 and 10000 keys
  • Test the insert function, including inserting a duplicate key
  • Test theremove function, including removing a non-existent key
  • Test theview functions, including what happens when a non-existent key is passed
  • Test sequential insertions
  • Test repeated random insertions and deletions


References



Thanks toJames Zaki andSolidified for the 3 minor issues they picked up at the Web3 Summit.

And thanks toRob Hitchens for thesuggestions.

Enjoy!

(c) BokkyPooBah / Bok Consulting Pty Ltd - Jan 18 2020. The MIT Licence.

About

BokkyPooBah's Red-Black Binary Search Tree Library

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors2

  •  
  •  

[8]ページ先頭

©2009-2025 Movatter.jp