Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

639 lines
18 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. btree.c
  5. Abstract:
  6. Implementation of red-black binary tree insertion, deletion, and search.
  7. This algorithm efficiently guarantees that the tree depth will never exceed
  8. 2*Lg(N), so a one million node tree would have a worst case depth of 40.
  9. This insertion implementation is non-recursive and very efficient (the
  10. average insertion speed is less than twice the average search speed).
  11. Author:
  12. Tom McGuire (tommcg) 1-Jan-1998
  13. Wesley Witt (wesw) 18-Dec-1998
  14. Revision History:
  15. Tom McGuire (tommcg) 13-Apr-2000 fixed hash collision search bug
  16. --*/
  17. #include "sfcp.h"
  18. #pragma hdrstop
  19. //
  20. // Rather than storing NULL links as NULL, we point NULL links to a special
  21. // "Empty" node which is always black and its children links point to itself.
  22. // We do this to simplify the color testing for children and grandchildren
  23. // such that any link can be dereferenced and even double-dereferenced without
  24. // explicitly checking for NULL. The empty node must be colored black.
  25. //
  26. const NAME_NODE NameRbEmptyNode = { RBNIL, RBNIL };
  27. const DWORD_NODE EmptyNode = { NODE_NIL, NODE_NIL };
  28. VOID
  29. BtreeInit(
  30. IN OUT PNAME_TREE Tree
  31. )
  32. {
  33. Tree->Root = RBNIL;
  34. }
  35. PNAME_NODE
  36. BtreeFind(
  37. IN PNAME_TREE Tree,
  38. IN LPCWSTR Name,
  39. IN DWORD NameLength
  40. )
  41. {
  42. PNAME_NODE Node;
  43. ULONG Hash;
  44. HASH_DYN_CONVERT_KEY( Name, (NameLength/sizeof(WCHAR)), &Hash );
  45. Node = Tree->Root;
  46. while ( Node != RBNIL ) {
  47. if ( Hash < Node->Hash ) {
  48. Node = Node->Left;
  49. }
  50. else if ( Hash > Node->Hash ) {
  51. Node = Node->Right;
  52. }
  53. else { // hashes equal, compare lengths
  54. if ( NameLength < Node->NameLength ) {
  55. Node = Node->Left;
  56. }
  57. else if ( NameLength > Node->NameLength ) {
  58. Node = Node->Right;
  59. }
  60. else { // hashes and lengths equal, compare strings
  61. int Compare = memcmp( Name, Node->Name, NameLength );
  62. if ( Compare == 0 ) {
  63. return Node;
  64. }
  65. else if ( Compare < 0 ) {
  66. Node = Node->Left;
  67. }
  68. else {
  69. Node = Node->Right;
  70. }
  71. }
  72. }
  73. }
  74. return NULL;
  75. }
  76. PNAME_NODE
  77. BtreeInsert(
  78. IN OUT PNAME_TREE Tree,
  79. IN LPCWSTR Name,
  80. IN DWORD NameLength
  81. )
  82. {
  83. PNAME_NODE * Stack[ MAX_DEPTH ];
  84. PNAME_NODE **StackPointer = Stack;
  85. PNAME_NODE * Link;
  86. PNAME_NODE Node;
  87. PNAME_NODE Sibling;
  88. PNAME_NODE Parent;
  89. PNAME_NODE Child;
  90. PNAME_NODE NewNode;
  91. ULONG Hash;
  92. HASH_DYN_CONVERT_KEY( Name, (NameLength/sizeof(WCHAR)), &Hash );
  93. *StackPointer++ = &Tree->Root;
  94. Node = Tree->Root;
  95. //
  96. // Walk down the tree to find either an existing node with the same key
  97. // (in which case we simply return) or the insertion point for the new
  98. // node. At each traversal we need to store the address of the link to
  99. // the next node so we can retrace the traversal path for balancing.
  100. // The speed of insertion is highly dependent on traversing the tree
  101. // quickly, so all balancing operations are deferred until after the
  102. // traversal is complete.
  103. //
  104. // Implementation Note: The compiler is smart enough to collapse each
  105. // of the three following "go left" and "go right" clauses into single
  106. // "go left" and "go right" instruction sequences, so the code remains
  107. // verbose for clarity.
  108. //
  109. while ( Node != RBNIL ) {
  110. if ( Hash < Node->Hash ) {
  111. *StackPointer++ = &Node->Left;
  112. Node = Node->Left;
  113. }
  114. else if ( Hash > Node->Hash ) {
  115. *StackPointer++ = &Node->Right;
  116. Node = Node->Right;
  117. }
  118. else { // hashes equal, compare lengths
  119. if ( NameLength < Node->NameLength ) {
  120. *StackPointer++ = &Node->Left;
  121. Node = Node->Left;
  122. }
  123. else if ( NameLength > Node->NameLength ) {
  124. *StackPointer++ = &Node->Right;
  125. Node = Node->Right;
  126. }
  127. else { // lengths equal, compare strings
  128. int Compare = memcmp( Name, Node->Name, NameLength );
  129. if ( Compare == 0 ) {
  130. return Node;
  131. }
  132. else if ( Compare < 0 ) {
  133. *StackPointer++ = &Node->Left;
  134. Node = Node->Left;
  135. }
  136. else {
  137. *StackPointer++ = &Node->Right;
  138. Node = Node->Right;
  139. }
  140. }
  141. }
  142. }
  143. //
  144. // Didn't find a matching entry, so allocate a new node and add it
  145. // to the tree. Note that we're not allocating space for a terminator
  146. // for the name data since we store the length of the name in the node.
  147. //
  148. NewNode = MemAlloc( sizeof(NAME_NODE)+NameLength );
  149. if ( NewNode == NULL ) {
  150. return NULL;
  151. }
  152. NewNode->Left = RBNIL;
  153. NewNode->Right = RBNIL;
  154. NewNode->Hash = Hash;
  155. NewNode->NameLengthAndColorBit = NameLength | 0x80000000; // MARK_RED
  156. memcpy( NewNode->Name, Name, NameLength );
  157. //
  158. // Insert new node under last link we traversed. The top of the stack
  159. // contains the address of the last link we traversed.
  160. //
  161. Link = *( --StackPointer );
  162. *Link = NewNode;
  163. //
  164. // Now walk back up the traversal chain to see if any balancing is
  165. // needed. This terminates in one of three ways: we walk all the way
  166. // up to the root (StackPointer == Stack), or find a black node that
  167. // we don't need to change (no balancing needs to be done above a
  168. // black node), or we perform a balancing rotation (only one necessary).
  169. //
  170. Node = NewNode;
  171. Child = RBNIL;
  172. while ( StackPointer > Stack ) {
  173. Link = *( --StackPointer );
  174. Parent = *Link;
  175. //
  176. // Node is always red here.
  177. //
  178. if ( IS_BLACK( Parent )) {
  179. Sibling = ( Parent->Left == Node ) ? Parent->Right : Parent->Left;
  180. if ( IS_RED( Sibling )) {
  181. //
  182. // Both Node and its Sibling are red, so change them both to
  183. // black and make the Parent red. This essentially moves the
  184. // red link up the tree so balancing can be performed at a
  185. // higher level.
  186. //
  187. // Pb Pr
  188. // / \ ----> / \
  189. // Cr Sr Cb Sb
  190. //
  191. MARK_BLACK( Sibling );
  192. MARK_BLACK( Node );
  193. MARK_RED( Parent );
  194. }
  195. else {
  196. //
  197. // This is a terminal case. The Parent is black, and it's
  198. // not going to be changed to red. If the Node's child is
  199. // red, we perform an appropriate rotation to balance the
  200. // tree. If the Node's child is black, we're done.
  201. //
  202. if ( IS_RED( Child )) {
  203. if ( Node->Left == Child ) {
  204. if ( Parent->Left == Node ) {
  205. //
  206. // Pb Nb
  207. // / \ / \
  208. // Nr Z to Cr Pr
  209. // / \ / \
  210. // Cr Y Y Z
  211. //
  212. MARK_RED( Parent );
  213. Parent->Left = Node->Right;
  214. Node->Right = Parent;
  215. MARK_BLACK( Node );
  216. *Link = Node;
  217. }
  218. else {
  219. //
  220. // Pb Cb
  221. // / \ / \
  222. // W Nr to Pr Nr
  223. // / \ / \ / \
  224. // Cr Z W X Y Z
  225. // / \
  226. // X Y
  227. //
  228. MARK_RED( Parent );
  229. Parent->Right = Child->Left;
  230. Child->Left = Parent;
  231. Node->Left = Child->Right;
  232. Child->Right = Node;
  233. MARK_BLACK( Child );
  234. *Link = Child;
  235. }
  236. }
  237. else {
  238. if ( Parent->Right == Node ) {
  239. MARK_RED( Parent );
  240. Parent->Right = Node->Left;
  241. Node->Left = Parent;
  242. MARK_BLACK( Node );
  243. *Link = Node;
  244. }
  245. else {
  246. MARK_RED( Parent );
  247. Parent->Left = Child->Right;
  248. Child->Right = Parent;
  249. Node->Right = Child->Left;
  250. Child->Left = Node;
  251. MARK_BLACK( Child );
  252. *Link = Child;
  253. }
  254. }
  255. }
  256. return NewNode;
  257. }
  258. }
  259. Child = Node;
  260. Node = Parent;
  261. }
  262. //
  263. // We bubbled red up to the root -- restore it to black.
  264. //
  265. MARK_BLACK( Tree->Root );
  266. return NewNode;
  267. }
  268. VOID
  269. TreeInit(
  270. OUT PDWORD_TREE Tree
  271. )
  272. {
  273. Tree->Root = NODE_NIL;
  274. }
  275. DWORD_CONTEXT
  276. TreeFind(
  277. IN PDWORD_TREE Tree,
  278. IN ULONG Key
  279. )
  280. {
  281. PDWORD_NODE Node;
  282. ASSERT(Tree != NULL);
  283. ASSERT(Key < (1 << 31));
  284. Node = Tree->Root;
  285. while ( Node != NODE_NIL ) {
  286. if ( Key < Node->Key ) {
  287. Node = Node->Left;
  288. }
  289. else if ( Key > Node->Key ) {
  290. Node = Node->Right;
  291. }
  292. else {
  293. return (DWORD_CONTEXT) Node->Context;
  294. }
  295. }
  296. return NULL;
  297. }
  298. DWORD_CONTEXT
  299. TreeInsert(
  300. IN OUT PDWORD_TREE Tree,
  301. IN ULONG Key,
  302. IN DWORD_CONTEXT Context,
  303. IN ULONG ContextSize
  304. )
  305. {
  306. PDWORD_NODE * Stack[ MAX_DEPTH ];
  307. PDWORD_NODE **StackPointer = Stack;
  308. PDWORD_NODE * Link;
  309. PDWORD_NODE Node;
  310. PDWORD_NODE Sibling;
  311. PDWORD_NODE Parent;
  312. PDWORD_NODE Child;
  313. PDWORD_NODE NewNode;
  314. ASSERT(Tree != NULL && Context != NULL && ContextSize != 0);
  315. ASSERT(Key < (1 << 31));
  316. *StackPointer++ = &Tree->Root;
  317. Node = Tree->Root;
  318. //
  319. // Walk down the tree to find either an existing node with the same key
  320. // (in which case we simply return) or the insertion point for the new
  321. // node. At each traversal we need to store the address of the link to
  322. // the next node so we can retrace the traversal path for balancing.
  323. // The speed of insertion is highly dependent on traversing the tree
  324. // quickly, so all balancing operations are deferred until after the
  325. // traversal is complete.
  326. //
  327. // Implementation Note: The compiler is smart enough to collapse each
  328. // of the three following "go left" and "go right" clauses into single
  329. // "go left" and "go right" instruction sequences, so the code remains
  330. // verbose for clarity.
  331. //
  332. while ( Node != NODE_NIL ) {
  333. if ( Key < Node->Key ) {
  334. *StackPointer++ = &Node->Left;
  335. Node = Node->Left;
  336. }
  337. else if ( Key > Node->Key ) {
  338. *StackPointer++ = &Node->Right;
  339. Node = Node->Right;
  340. }
  341. else {
  342. return (DWORD_CONTEXT) Node->Context;
  343. }
  344. }
  345. //
  346. // Didn't find a matching entry, so allocate a new node and add it
  347. // to the tree. Note that we're not allocating space for a terminator
  348. // for the name data since we store the length of the name in the node.
  349. //
  350. NewNode = MemAlloc( sizeof(DWORD_NODE) + ContextSize);
  351. if ( NewNode == NULL ) {
  352. return NULL;
  353. }
  354. NewNode->Left = NODE_NIL;
  355. NewNode->Right = NODE_NIL;
  356. NewNode->Key = Key;
  357. MARK_RED(NewNode);
  358. memcpy( NewNode->Context, Context, ContextSize );
  359. //
  360. // Insert new node under last link we traversed. The top of the stack
  361. // contains the address of the last link we traversed.
  362. //
  363. Link = *( --StackPointer );
  364. *Link = NewNode;
  365. //
  366. // Now walk back up the traversal chain to see if any balancing is
  367. // needed. This terminates in one of three ways: we walk all the way
  368. // up to the root (StackPointer == Stack), or find a black node that
  369. // we don't need to change (no balancing needs to be done above a
  370. // black node), or we perform a balancing rotation (only one necessary).
  371. //
  372. Node = NewNode;
  373. Child = NODE_NIL;
  374. while ( StackPointer > Stack ) {
  375. Link = *( --StackPointer );
  376. Parent = *Link;
  377. //
  378. // Node is always red here.
  379. //
  380. if ( IS_BLACK( Parent )) {
  381. Sibling = ( Parent->Left == Node ) ? Parent->Right : Parent->Left;
  382. if ( IS_RED( Sibling )) {
  383. //
  384. // Both Node and its Sibling are red, so change them both to
  385. // black and make the Parent red. This essentially moves the
  386. // red link up the tree so balancing can be performed at a
  387. // higher level.
  388. //
  389. // Pb Pr
  390. // / \ ----> / \
  391. // Cr Sr Cb Sb
  392. //
  393. MARK_BLACK( Sibling );
  394. MARK_BLACK( Node );
  395. MARK_RED( Parent );
  396. }
  397. else {
  398. //
  399. // This is a terminal case. The Parent is black, and it's
  400. // not going to be changed to red. If the Node's child is
  401. // red, we perform an appropriate rotation to balance the
  402. // tree. If the Node's child is black, we're done.
  403. //
  404. if ( IS_RED( Child )) {
  405. if ( Node->Left == Child ) {
  406. if ( Parent->Left == Node ) {
  407. //
  408. // Pb Nb
  409. // / \ / \
  410. // Nr Z to Cr Pr
  411. // / \ / \
  412. // Cr Y Y Z
  413. //
  414. MARK_RED( Parent );
  415. Parent->Left = Node->Right;
  416. Node->Right = Parent;
  417. MARK_BLACK( Node );
  418. *Link = Node;
  419. }
  420. else {
  421. //
  422. // Pb Cb
  423. // / \ / \
  424. // W Nr to Pr Nr
  425. // / \ / \ / \
  426. // Cr Z W X Y Z
  427. // / \
  428. // X Y
  429. //
  430. MARK_RED( Parent );
  431. Parent->Right = Child->Left;
  432. Child->Left = Parent;
  433. Node->Left = Child->Right;
  434. Child->Right = Node;
  435. MARK_BLACK( Child );
  436. *Link = Child;
  437. }
  438. }
  439. else {
  440. if ( Parent->Right == Node ) {
  441. MARK_RED( Parent );
  442. Parent->Right = Node->Left;
  443. Node->Left = Parent;
  444. MARK_BLACK( Node );
  445. *Link = Node;
  446. }
  447. else {
  448. MARK_RED( Parent );
  449. Parent->Left = Child->Right;
  450. Child->Right = Parent;
  451. Node->Right = Child->Left;
  452. Child->Left = Node;
  453. MARK_BLACK( Child );
  454. *Link = Child;
  455. }
  456. }
  457. }
  458. return (DWORD_CONTEXT) NewNode->Context;
  459. }
  460. }
  461. Child = Node;
  462. Node = Parent;
  463. }
  464. //
  465. // We bubbled red up to the root -- restore it to black.
  466. //
  467. MARK_BLACK( Tree->Root );
  468. return (DWORD_CONTEXT) NewNode->Context;
  469. }
  470. VOID
  471. TreeDestroy(
  472. IN OUT PDWORD_TREE Tree
  473. )
  474. //
  475. // We walk the tree left first, then right, until we find a leaf. We delete the leaf and continue
  476. // our walking to the right of the parent since we must've been to the parent's left before
  477. //
  478. {
  479. PDWORD_NODE * Stack[ MAX_DEPTH ];
  480. PDWORD_NODE **StackPointer;
  481. PDWORD_NODE Node;
  482. if(NODE_NIL == Tree->Root)
  483. return;
  484. StackPointer = Stack;
  485. *StackPointer = &Tree->Root;
  486. lTryLeft:
  487. Node = **StackPointer;
  488. if(Node->Left != NODE_NIL)
  489. {
  490. *++StackPointer = &Node->Left;
  491. goto lTryLeft;
  492. }
  493. lTryRight:
  494. if(Node->Right != NODE_NIL)
  495. {
  496. *++StackPointer = &Node->Right;
  497. goto lTryLeft;
  498. }
  499. MemFree(Node);
  500. **StackPointer = NODE_NIL;
  501. if(StackPointer > Stack) // this is true if the current node is not the root
  502. {
  503. Node = **--StackPointer;
  504. goto lTryRight;
  505. }
  506. }