Upgrade to Pro — share decks privately, control downloads, hide ads and more …

B-Tree & SortedSet in Swift Collections

B-Tree & SortedSet in Swift Collections

B-Tree & SortedSet in Swift Collections by Yu-Che Cheng @ COSCUP 2023

https://coscup.org/2023/en/session/PZSRQ8

iamhands0me

July 29, 2023
Tweet

More Decks by iamhands0me

Other Decks in Programming

Transcript

  1. Swift Collections 2 • Deque, OrderedSet • Heap, BitArray •

    SparseSet, SortedSet An open-source package of data structure implementations for the Swift 1.0.4 Latest 1.1 under development
  2. class Library { var books: SomeCollection<Int> /// let book =

    library.lendBook(10000) func lendBook(_ id: Int) -> Int? { } /// library.returnBook(10000) func returnBook(_ id: Int) { } /// let books = library.lendBooks(10001..<11000) func lendBooks(_ ids: Range<Int>) -> [Int] { } } Scenario 3 Design a Library class that can lend/return a book and lend a series of books
  3. class Library { var books: Set<Int> /// let book =

    library.lendBook(10000) func lendBook(_ id: Int) -> Int? { return books.remove(id) } /// library.returnBook(10000) func returnBook(_ id: Int) { books.insert(id) } /// let books = library.lendBooks(10000..<11000) func lendBooks(_ ids: Range<Int>) -> [Int] { var existedBooks: [Int] = [] for id in ids { if let book = books.remove(id) { existedBooks.append(book) } } return existedBooks } } 4 Set<Int> Set 10000 12300 10050 700 𝑂(1) 𝑂(1) 𝑂 𝐾 𝐾: Number of ids in the range for id in ids {
  4. 5 We need a collection that can 1. Store unique

    keys 2. Keep the keys being sorted
  5. 6 We need a collection that can 1. Store unique

    keys 2. Keep the keys being sorted => Binary Search Tree (Sorted Binary Tree/Sorted Set) Binary Search Tree 10000 12300 10050 700
  6. class Library { var books: SortedSet<Int> /// let book =

    library.lendBook(10000) func lendBook(_ id: Int) -> Int? { return books.remove(id) } /// library.returnBook(10000) func returnBook(_ id: Int) { books.insert(id) } /// let books = library.lendBooks(10000..<11000) func lendBooks(_ ids: Range<Int>) -> [Int] { var subSequence = books[ids.lowerBound ..< ids.upperBound] let existedBooks = Array(subSequence) for id in existedBooks { books.remove(id) } return existedBooks } } Binary Search Tree 7 SortedSet<Int> 𝑂(log 𝑛) 𝑂(log 𝑛) 𝑂 log 𝑛 + 𝑘 𝑘: Number of ids in the subSequence 10000 12300 10050 700 var subSequence = books[ids.lowerBound ..< ids.upperBound] for id in existedBooks {
  7. Red-black Tree AVL Tree Self-balancing binary search tree 8 B-Tree

    Source: https://en.wikipedia.org/wiki/Red-black_tree Source: https://en.wikipedia.org/wiki/AVL_tree Source: https://en.wikipedia.org/wiki/B-tree
  8. class Library { var books: [Int] /// let book =

    library.lendBook(10000) func lendBook(_ id: Int) -> Int? { guard let index = books.firstIndex(of: id) else { return nil } return books.remove(at: index) } /// library.returnBook(10000) func returnBook(_ id: Int) { let index = books.firstIndex { $0 > id } ?? books.endIndex if !books.contains(id) { books.insert(id, at: index) } } /// let books = library.lendBooks(10000..<11000) func lendBooks(_ ids: Range<Int>) -> [Int] { let startIndex = books.firstIndex { $0 >= ids.lowerBound } ?? books.endIndex let endIndex = books.firstIndex { $0 >= ids.upperBound } ?? books.endIndex defer { books.removeSubrange(startIndex ..< endIndex) } return Array(books[startIndex ..< endIndex]) } } Array 11 [Int] 𝑂(𝑛) 𝑂(𝑛) 𝑂 𝑛 0 700 1 10000 2 10050 3 12300 books.removeSubrange(startIndex ..< endIndex)
  9. 13 Source: https://github.com/attaswift/BTree Array vs. red-black tree 10000 12300 10050

    700 Array 0 700 1 10000 2 10050 3 12300 0x42B7 0x1C3E 0x54D9 0x877A 0x0800 0x0802 0x0804 0x0806 Tree
  10. 18 SortedSet<Element: Comparable> _root: BTree<Element> Node<Key: Comparable> count BTree<Key: Comparable>

    root: Node<Key> public func contains(_ member: Element) -> Bool public func insert(_ newMember: Element) public func remove(_ member: Element) -> Element? capacity depth children: [Node<Key>] keys: [Key]
  11. 1. Search for the key X. Start at the root

    2. Find the slot of first key which equal or greater than X 3. If it’s equal, return True 4. Else, go to the child node at the slot 5. Repeat the steps from 2 till no more traversal 6. Return False 19 public func contains(_ member: Element) -> Bool 80 35 63 60 40 71 . . . . . . 84 63 contains( ) slot 1 slot 2
  12. slot 3 1. Insert for the key X 2. Find

    the slot of first key which greater than X till no more traversal 3. If not full, then insert 20 public func insert(_ newMember: Element) 80 35 63 60 40 71 . . . . . . 84 insert( ) slot 1 67
  13. slot 3 1. Insert for the key X 2. Find

    the slot of first key which greater than X till no more traversal 3. If not full, then insert 21 public func insert(_ newMember: Element) 80 35 60 40 71 . . . . . . 84 67 slot 1 63
  14. 1. Insert for the key X 2. Find the slot

    of first key which greater than X till no more traversal 3. If not full, then insert 4. Else, split! 22 public func insert(_ newMember: Element) 80 35 60 40 71 . . . . . . 84 67 63 55 insert( ) slot 1 slot 1
  15. Splinter key rightChild 1. Insert for the key X 2.

    Find the slot of first key which greater than X till no more traversal 3. If not full, then insert 4. Else, split! 23 public func insert(_ newMember: Element) 80 35 60 40 . . . . . . 84 55 insert( ) slot 1 slot 1 71 67 63
  16. Splinter key rightChild 1. Insert for the key X 2.

    Find the slot of first key which greater than X till no more traversal 3. If not full, then insert 4. Else, split! 24 public func insert(_ newMember: Element) 80 35 60 40 . . . . . . 84 55 insert( ) slot 1 slot 1 71 67 63
  17. Splinter 63 key rightChild 1. Insert for the key X

    2. Find the slot of first key which greater than X till no more traversal 3. If not full, then insert 4. Else, split! 25 public func insert(_ newMember: Element) 80 35 . . . . . . 84 71 67 60 40 55 slot 1
  18. Splinter key rightChild 1. Insert for the key X 2.

    Find the slot of first key which greater than X till no more traversal 3. If not full, then insert 4. Else, split! 26 public func insert(_ newMember: Element) 80 35 71 . . . . . . 84 67 63 60 40 55 slot 1
  19. 1. Insert for the key X 2. Find the slot

    of first key which greater than X till no more traversal 3. If not full, then insert 4. Else, split! 27 public func insert(_ newMember: Element) 80 35 60 40 71 . . . 84 67 63 insert( ) slot 3 slot 1 28 20 55
  20. Splinter 63 key rightChild 1. Insert for the key X

    2. Find the slot of first key which greater than X till no more traversal 3. If not full, then insert 4. Else, split! 28 public func insert(_ newMember: Element) . . . 84 71 67 60 40 slot 3 28 20 80 35 55
  21. Splinter 35 key rightChild 1. Insert for the key X

    2. Find the slot of first key which greater than X till no more traversal 3. If not full, then insert 4. Else, split! 29 public func insert(_ newMember: Element) . . . 84 60 40 55 67 71 28 20 80 63
  22. BTree<Key: Comparable> Splinter 35 key rightChild 1. Insert for the

    key X 2. Find the slot of first key which greater than X till no more traversal 3. If not full, then insert 4. Else, split! 30 public func insert(_ newMember: Element) . . . 84 80 63 60 40 55 67 71 28 20 root
  23. BTree<Key: Comparable> 1. Insert for the key X 2. Find

    the slot of first key which greater than X till no more traversal 3. If not full, then insert 4. Else, split! 31 public func insert(_ newMember: Element) . . . 84 80 63 60 40 55 67 71 28 20 root 35
  24. 1. Remove for the key X 2. Find the slot

    of first key which equal or greater than X till no more traversal 3. Pop last key from the child node at the slot, replace X with the popped key 32 public func remove(_ member: Element) -> Element? 84 80 63 60 40 55 67 71 28 20 35 80 remove( ) slot 1 slot 1 90
  25. 1. Remove for the key X 2. Find the slot

    of first key which equal or greater than X till no more traversal 3. Pop last key from the child node at the slot, replace X with the popped key 33 public func remove(_ member: Element) -> Element? 84 63 60 40 55 67 71 28 20 35 80 remove( ) slot 1 slot 1 90
  26. 1. Remove for the key X 2. Find the slot

    of first key which equal or greater than X till no more traversal 3. Pop last key from the child node at the slot, replace X with the popped key 34 public func remove(_ member: Element) -> Element? 84 63 60 40 55 67 71 28 20 35 80 remove( ) slot 1 slot 1 90
  27. 1. Remove for the key X 2. Find the slot

    of first key which equal or greater than X till no more traversal 3. Pop last key from the child node at the slot, replace X with the popped key 4. Balance the child node if needed 35 public func remove(_ member: Element) -> Element? 84 80 63 60 40 55 67 71 28 20 35 80 remove( ) slot 1 slot 1 90
  28. 1. If of child node equal or greater than ,

    return 2. If of left child node greater than , rotate right from left 3. If of right child node greater than , rotate left from right 36 func balance(atSlot slot: Int) 84 80 40 55 67 71 28 20 35 slot 1 slot 1 90 count capacity / 2 count capacity / 2 count capacity / 2 60 63
  29. 1. If of child node equal or greater than ,

    return 2. If of left child node greater than , rotate right from left 3. If of right child node greater than , rotate left from right 37 func balance(atSlot slot: Int) 84 80 40 55 67 71 28 20 35 slot 1 slot 1 90 count capacity / 2 count capacity / 2 count capacity / 2 63 60
  30. 1. If of child node equal or greater than ,

    return 2. If of left child node greater than , rotate right from left 3. If of right child node greater than , rotate left from right 38 func balance(atSlot slot: Int) 84 40 55 71 28 20 35 slot 1 slot 1 90 count capacity / 2 count capacity / 2 count capacity / 2 63 60 71 remove( ) 67
  31. 1. If of child node equal or greater than ,

    return 2. If of left child node greater than , rotate right from left 3. If of right child node greater than , rotate left from right 39 func balance(atSlot slot: Int) 84 40 55 28 20 35 slot 1 slot 1 90 count capacity / 2 count capacity / 2 count capacity / 2 63 60 71 remove( ) 67
  32. 1. If of child node equal or greater than ,

    return 2. If of left child node greater than , rotate right from left 3. If of right child node greater than , rotate left from right 4. Else, collapse the child 40 func balance(atSlot slot: Int) 40 55 28 20 35 slot 1 slot 1 90 count capacity / 2 count capacity / 2 count capacity / 2 63 60 71 remove( ) 67 84
  33. 1. If of child node equal or greater than ,

    return 2. If of left child node greater than , rotate right from left 3. If of right child node greater than , rotate left from right 4. Else, collapse the child 41 func balance(atSlot slot: Int) 40 55 28 20 slot 1 90 count capacity / 2 count capacity / 2 count capacity / 2 63 60 67 84 35
  34. 1. If of child node equal or greater than ,

    return 2. If of left child node greater than , rotate right from left 3. If of right child node greater than , rotate left from right 4. Else, collapse the child 42 func balance(atSlot slot: Int) 40 55 28 20 90 count capacity / 2 count capacity / 2 count capacity / 2 63 60 67 84 35
  35. BTree<Key: Comparable> 1. If of child node equal or greater

    than , return 2. If of left child node greater than , rotate right from left 3. If of right child node greater than , rotate left from right 4. Else, collapse the child 43 func balance(atSlot slot: Int) 40 55 90 count capacity / 2 count capacity / 2 count capacity / 2 63 67 84 28 20 35 60 root
  36. BTree<Key: Comparable> 1. If of child node equal or greater

    than , return 2. If of left child node greater than , rotate right from left 3. If of right child node greater than , rotate left from right 4. Else, collapse the child 44 func balance(atSlot slot: Int) 40 55 90 count capacity / 2 count capacity / 2 count capacity / 2 63 67 84 28 20 35 60 root