├── .gitattributes ├── .gitignore ├── Chapter 1 └── B05101_1_Walking_Across_The_Playground.playground.zip ├── Chapter 2 └── B05101_2_Commonly_Used_Data_Structures.playground.zip ├── Chapter 3 └── B05101_3_Standing_On_The_Shoulders_Of_Giants.playground.zip ├── Chapter 4 └── B05101_4_Sorting_Algorithms.playground.zip ├── Chapter 5 └── B05101_5_Trees.playground.zip ├── Chapter 6 └── B05101_6_Playgrounds │ ├── B05101_6_AVLTree.playground │ ├── Pages │ │ ├── AVLTree.xcplaygroundpage │ │ │ └── Contents.swift │ │ └── License.xcplaygroundpage │ │ │ └── Contents.swift │ ├── Sources │ │ └── AVLTreeNode.swift │ ├── contents.xcplayground │ └── playground.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcuserdata │ │ ├── erik.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ │ └── mario.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ ├── B05101_6_RedBlackTree.playground │ ├── Pages │ │ ├── License.xcplaygroundpage │ │ │ └── Contents.swift │ │ └── RedBlackTree.xcplaygroundpage │ │ │ └── Contents.swift │ ├── Sources │ │ └── RedBlackTreeNode.swift │ ├── contents.xcplayground │ └── playground.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcuserdata │ │ ├── erik.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ │ └── mario.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ └── B05101_6_StringSearch.playground │ ├── Pages │ ├── License.xcplaygroundpage │ │ └── Contents.swift │ └── StringSearch.xcplaygroundpage │ │ └── Contents.swift │ ├── Sources │ └── StringSearch.swift │ ├── contents.xcplayground │ └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ ├── erik.xcuserdatad │ └── UserInterfaceState.xcuserstate │ └── mario.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── Chapter 7 └── B05101_7_Playgrounds.zip ├── Chapter 8 └── B05101_8_Performance_Efficiency.playground.zip ├── Chapter 9 └── B05101_9_URLShortener.playground.zip ├── README.md └── license /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | -------------------------------------------------------------------------------- /Chapter 1/B05101_1_Walking_Across_The_Playground.playground.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Swift-Data-Structure-and-Algorithms/5487c541cfc5e87cf329bb40d0b647f9738f1ef0/Chapter 1/B05101_1_Walking_Across_The_Playground.playground.zip -------------------------------------------------------------------------------- /Chapter 2/B05101_2_Commonly_Used_Data_Structures.playground.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Swift-Data-Structure-and-Algorithms/5487c541cfc5e87cf329bb40d0b647f9738f1ef0/Chapter 2/B05101_2_Commonly_Used_Data_Structures.playground.zip -------------------------------------------------------------------------------- /Chapter 3/B05101_3_Standing_On_The_Shoulders_Of_Giants.playground.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Swift-Data-Structure-and-Algorithms/5487c541cfc5e87cf329bb40d0b647f9738f1ef0/Chapter 3/B05101_3_Standing_On_The_Shoulders_Of_Giants.playground.zip -------------------------------------------------------------------------------- /Chapter 4/B05101_4_Sorting_Algorithms.playground.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Swift-Data-Structure-and-Algorithms/5487c541cfc5e87cf329bb40d0b647f9738f1ef0/Chapter 4/B05101_4_Sorting_Algorithms.playground.zip -------------------------------------------------------------------------------- /Chapter 5/B05101_5_Trees.playground.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Swift-Data-Structure-and-Algorithms/5487c541cfc5e87cf329bb40d0b647f9738f1ef0/Chapter 5/B05101_5_Trees.playground.zip -------------------------------------------------------------------------------- /Chapter 6/B05101_6_Playgrounds/B05101_6_AVLTree.playground/Pages/AVLTree.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | /*: 2 | # Chapter 6 3 | ## Advanced Search methods 4 | */ 5 | 6 | //: ## Demonstrate use of the AVL tree type. 7 | //: 8 | //: ### Find the AVLTreeNode implementation in the Sources/AVLTreeNode.swift file located within this project. 9 | 10 | //: Create a nonbalanced AVLTree 11 | var avlRootNode = AVLTreeNode.init(value: 100) 12 | avlRootNode.insertNodeFromRoot(value: 50) 13 | avlRootNode.insertNodeFromRoot(value: 200) 14 | avlRootNode.insertNodeFromRoot(value: 150) 15 | avlRootNode.insertNodeFromRoot(value: 125) 16 | avlRootNode.insertNodeFromRoot(value: 250) 17 | 18 | avlRootNode.balanceFactor = 2 19 | avlRootNode.rightChild?.balanceFactor = -1 20 | avlRootNode.rightChild?.rightChild?.balanceFactor = 0 21 | avlRootNode.rightChild?.leftChild?.balanceFactor = -1 22 | avlRootNode.rightChild?.leftChild?.leftChild?.balanceFactor = 0 23 | avlRootNode.leftChild?.balanceFactor = 0 24 | 25 | print("Invalid AVL tree") 26 | AVLTreeNode.printTree(nodes: [avlRootNode]) 27 | 28 | //: Perform rotations to fix it 29 | if let newRoot = avlRootNode.rightChild?.leftChild?.rotateRightLeft() { 30 | avlRootNode = newRoot 31 | } 32 | 33 | //: Print each layer of the tree 34 | print("Valid AVL tree") 35 | AVLTreeNode.printTree(nodes: [avlRootNode]) 36 | 37 | /*: 38 | 39 | The license for this document is available [here](License). 40 | */ 41 | -------------------------------------------------------------------------------- /Chapter 6/B05101_6_Playgrounds/B05101_6_AVLTree.playground/Pages/License.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | /*: 2 | [Previous](@previous) 3 | **** 4 | # The MIT License (MIT) 5 | 6 | ### Copyright (c) 2016 Erik J. Azar & Mario Eguiluz 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in all 16 | copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | 26 | **** 27 | [Previous](@previous) 28 | */ 29 | -------------------------------------------------------------------------------- /Chapter 6/B05101_6_Playgrounds/B05101_6_AVLTree.playground/Sources/AVLTreeNode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AVLTreeNode.swift 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2016 Erik J. Azar & Mario Eguiluz 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | 26 | public class AVLTreeNode { 27 | 28 | //Value and children-parent vars 29 | public var value:T 30 | public var leftChild:AVLTreeNode? 31 | public var rightChild:AVLTreeNode? 32 | public weak var parent:AVLTreeNode? 33 | public var balanceFactor:Int = 0 34 | 35 | //Initialization 36 | public convenience init(value: T) { 37 | self.init(value: value, left: nil, right: nil, parent:nil) 38 | } 39 | 40 | public init(value:T, left:AVLTreeNode?, right:AVLTreeNode?, parent:AVLTreeNode?) { 41 | self.value = value 42 | self.leftChild = left 43 | self.rightChild = right 44 | self.parent = parent 45 | self.balanceFactor = 0 46 | } 47 | 48 | //Right 49 | public func rotateRight() -> AVLTreeNode { 50 | guard let parent = parent else { 51 | return self 52 | } 53 | 54 | // Step 1: Rotation 55 | // 0.Lets store some temporary references to use them later 56 | let grandParent = parent.parent 57 | let newRightChildsLeftChild = self.rightChild 58 | var wasLeftChild = false 59 | if parent === grandParent?.leftChild { 60 | wasLeftChild = true 61 | } 62 | 63 | //1. My new right child is my old parent 64 | self.rightChild = parent 65 | self.rightChild?.parent = self 66 | 67 | //2. My new parent is my old grandparent 68 | self.parent = grandParent 69 | if wasLeftChild { 70 | grandParent?.leftChild = self 71 | }else { 72 | grandParent?.rightChild = self 73 | } 74 | 75 | //3. The left child of my new right child is my old right child 76 | self.rightChild?.leftChild = newRightChildsLeftChild 77 | self.rightChild?.leftChild?.parent = self.rightChild 78 | 79 | // Step 2: Height update 80 | if self.balanceFactor == 0 { 81 | self.balanceFactor = 1 82 | self.rightChild?.balanceFactor = -1 83 | } else { 84 | self.balanceFactor = 0 85 | self.rightChild?.balanceFactor = 0 86 | } 87 | 88 | return self 89 | } 90 | 91 | //Left 92 | public func rotateLeft() -> AVLTreeNode { 93 | guard let parent = parent else { 94 | return self 95 | } 96 | 97 | // Step 1: Rotation 98 | // 0.Lets store some temporary references to use them later 99 | let grandParent = parent.parent 100 | let newLeftChildsRightChild = self.leftChild 101 | var wasLeftChild = false 102 | if parent === grandParent?.leftChild { 103 | wasLeftChild = true 104 | } 105 | 106 | //1. My new left child is my old parent 107 | self.leftChild = parent 108 | self.leftChild?.parent = self 109 | 110 | //2. My new parent is my old grandparent 111 | self.parent = grandParent 112 | if wasLeftChild { 113 | grandParent?.leftChild = self 114 | }else { 115 | grandParent?.rightChild = self 116 | } 117 | 118 | //3. The right child of my new left child is my old left child 119 | self.leftChild?.rightChild = newLeftChildsRightChild 120 | self.leftChild?.rightChild?.parent = self.leftChild 121 | 122 | // Step 2: Height update 123 | if self.balanceFactor == 0 { 124 | self.balanceFactor = -1 125 | self.leftChild?.balanceFactor = 1 126 | } else { 127 | self.balanceFactor = 0 128 | self.leftChild?.balanceFactor = 0 129 | } 130 | 131 | return self 132 | } 133 | 134 | //Right - Left 135 | public func rotateRightLeft() -> AVLTreeNode { 136 | 137 | // 1: Double rotation 138 | _ = self.rotateRight() 139 | _ = self.rotateLeft() 140 | 141 | // 2: Update Balance Factors 142 | if (self.balanceFactor > 0) { 143 | self.leftChild?.balanceFactor = -1; 144 | self.rightChild?.balanceFactor = 0; 145 | } 146 | else if (self.balanceFactor == 0) { 147 | self.leftChild?.balanceFactor = 0; 148 | self.rightChild?.balanceFactor = 0; 149 | } 150 | else { 151 | self.leftChild?.balanceFactor = 0; 152 | self.rightChild?.balanceFactor = 1; 153 | } 154 | 155 | self.balanceFactor = 0; 156 | 157 | return self 158 | } 159 | 160 | //Left - Right 161 | public func rotateLeftRight() -> AVLTreeNode { 162 | 163 | // 1: Double rotation 164 | _ = self.rotateLeft() 165 | _ = self.rotateRight() 166 | 167 | // 2: Update Balance Factors 168 | if (self.balanceFactor > 0) { 169 | self.leftChild?.balanceFactor = -1; 170 | self.rightChild?.balanceFactor = 0; 171 | } 172 | else if (self.balanceFactor == 0) { 173 | self.leftChild?.balanceFactor = 0; 174 | self.rightChild?.balanceFactor = 0; 175 | } 176 | else { 177 | self.leftChild?.balanceFactor = 0; 178 | self.rightChild?.balanceFactor = 1; 179 | } 180 | 181 | self.balanceFactor = 0; 182 | 183 | return self 184 | } 185 | 186 | // MARK: Helper method to build a initial AVL-tree (not a insertion by retracing) 187 | 188 | //Insert operation methods 189 | public func insertNodeFromRoot(value:T) { 190 | //To mantain the binary search tree property, we must ensure that we run the insertNode process from the root node 191 | if let _ = self.parent { 192 | // If parent exists, it is not the root node of the tree 193 | print("You can only add new nodes from the root node of the tree"); 194 | return 195 | } 196 | 197 | self.addNode(value: value) 198 | } 199 | 200 | private func addNode(value:T) { 201 | if value < self.value { 202 | // Value is less than root value: We should insert it in the left subtree. 203 | // Insert it into the left subtree if it exists, if not, create a new node and put it as the left child. 204 | if let leftChild = leftChild { 205 | leftChild.addNode(value: value) 206 | }else { 207 | let newNode = AVLTreeNode(value: value) 208 | newNode.parent = self 209 | leftChild = newNode 210 | 211 | } 212 | }else { 213 | // Value is greater than root value: We should insert it in the right subtree 214 | // Insert it into the right subtree if it exists, if not, create a new node and put it as the right child. 215 | if let rightChild = rightChild { 216 | rightChild.addNode(value: value) 217 | }else { 218 | let newNode = AVLTreeNode(value: value) 219 | newNode.parent = self 220 | rightChild = newNode 221 | } 222 | } 223 | } 224 | 225 | // Prints each layer of the tree from top to bottom with the node value and the balance factor 226 | public static func printTree(nodes:[AVLTreeNode]) { 227 | var children:[AVLTreeNode] = Array() 228 | 229 | for node:AVLTreeNode in nodes { 230 | print("\(node.value)" + " " + "\(node.balanceFactor)") 231 | if let leftChild = node.leftChild { 232 | children.append(leftChild) 233 | } 234 | if let rightChild = node.rightChild { 235 | children.append(rightChild) 236 | } 237 | } 238 | 239 | if children.count > 0 { 240 | printTree(nodes: children) 241 | } 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /Chapter 6/B05101_6_Playgrounds/B05101_6_AVLTree.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Chapter 6/B05101_6_Playgrounds/B05101_6_AVLTree.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Chapter 6/B05101_6_Playgrounds/B05101_6_AVLTree.playground/playground.xcworkspace/xcuserdata/erik.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Swift-Data-Structure-and-Algorithms/5487c541cfc5e87cf329bb40d0b647f9738f1ef0/Chapter 6/B05101_6_Playgrounds/B05101_6_AVLTree.playground/playground.xcworkspace/xcuserdata/erik.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Chapter 6/B05101_6_Playgrounds/B05101_6_AVLTree.playground/playground.xcworkspace/xcuserdata/mario.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Swift-Data-Structure-and-Algorithms/5487c541cfc5e87cf329bb40d0b647f9738f1ef0/Chapter 6/B05101_6_Playgrounds/B05101_6_AVLTree.playground/playground.xcworkspace/xcuserdata/mario.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Chapter 6/B05101_6_Playgrounds/B05101_6_RedBlackTree.playground/Pages/License.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | /*: 2 | [Previous](@previous) 3 | **** 4 | # The MIT License (MIT) 5 | 6 | ### Copyright (c) 2016 Erik J. Azar & Mario Eguiluz 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in all 16 | copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | 26 | **** 27 | [Previous](@previous) 28 | */ 29 | -------------------------------------------------------------------------------- /Chapter 6/B05101_6_Playgrounds/B05101_6_RedBlackTree.playground/Pages/RedBlackTree.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | /*: 2 | # Chapter 6 3 | ## Advanced Search methods 4 | */ 5 | 6 | //: ## Demonstrate use of the Red-Black tree type. 7 | //: 8 | //: ### Find the RedBlackTreeNode implementation in the Sources/RedBlackTreeNode.swift file located within this project. 9 | 10 | //: Create the root node 11 | let rootNode = RedBlackTreeNode.init(value: 10) 12 | 13 | //: Insert nodes in the proper place 14 | rootNode.insertNodeFromRoot(value: 12) 15 | rootNode.insertNodeFromRoot(value: 5) 16 | rootNode.insertNodeFromRoot(value: 3) 17 | rootNode.insertNodeFromRoot(value: 8) 18 | rootNode.insertNodeFromRoot(value: 30) 19 | rootNode.insertNodeFromRoot(value: 11) 20 | rootNode.insertNodeFromRoot(value: 32) 21 | rootNode.insertNodeFromRoot(value: 4) 22 | rootNode.insertNodeFromRoot(value: 2) 23 | 24 | //: Print the tree 25 | RedBlackTreeNode.printTree(nodes: [rootNode]) 26 | 27 | /*: 28 | 29 | The license for this document is available [here](License). 30 | */ 31 | -------------------------------------------------------------------------------- /Chapter 6/B05101_6_Playgrounds/B05101_6_RedBlackTree.playground/Sources/RedBlackTreeNode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RedBlackTreeNode.swift 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2016 Erik J. Azar & Mario Eguiluz 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | 26 | //Enumeration to model the possible colors of a node 27 | public enum RedBlackTreeColor : Int { 28 | case red = 0 29 | case black = 1 30 | } 31 | 32 | public class RedBlackTreeNode { 33 | //Value and children-parent vars 34 | public var value:T 35 | public var leftChild:RedBlackTreeNode? 36 | public var rightChild:RedBlackTreeNode? 37 | public weak var parent:RedBlackTreeNode? 38 | //Color var 39 | public var color:RedBlackTreeColor 40 | 41 | //Initialization 42 | public convenience init(value: T) { 43 | self.init(value: value, left: nil, right: nil, parent:nil, color: RedBlackTreeColor.black) 44 | } 45 | 46 | public init(value:T, left:RedBlackTreeNode?, right:RedBlackTreeNode?, parent:RedBlackTreeNode?, color:RedBlackTreeColor) { 47 | self.value = value 48 | self.color = color 49 | self.leftChild = left 50 | self.rightChild = right 51 | self.parent = parent 52 | } 53 | 54 | //MARK: Helper methods 55 | 56 | //Returns the grandparent of the node, or nil 57 | public func grandParentNode() -> RedBlackTreeNode? { 58 | guard let grandParentNode = self.parent?.parent else { 59 | return nil 60 | } 61 | return grandParentNode 62 | } 63 | 64 | //Returns the "uncle" of the node, or nil if doesn't exist. This is the sibling of its parent node 65 | public func uncleNode() -> RedBlackTreeNode? { 66 | guard let grandParent = self.grandParentNode() else { 67 | return nil 68 | } 69 | 70 | if parent === grandParent.leftChild { 71 | return grandParent.rightChild 72 | }else { 73 | return grandParent.leftChild 74 | } 75 | } 76 | 77 | // Prints each layer of the tree from top to bottom with the node value and the color 78 | public static func printTree(nodes:[RedBlackTreeNode]) { 79 | var children:[RedBlackTreeNode] = Array() 80 | 81 | for node:RedBlackTreeNode in nodes { 82 | print("\(node.value)" + " " + "\(node.color)") 83 | if let leftChild = node.leftChild { 84 | children.append(leftChild) 85 | } 86 | if let rightChild = node.rightChild { 87 | children.append(rightChild) 88 | } 89 | } 90 | 91 | if children.count > 0 { 92 | printTree(nodes: children) 93 | } 94 | } 95 | 96 | //MARK: Rotations 97 | 98 | //Right 99 | public func rotateRight() { 100 | guard let parent = parent else { 101 | return 102 | } 103 | 104 | //1.Lets store some temporary references to use them later 105 | let grandParent = parent.parent 106 | let newRightChildsLeftChild = self.rightChild 107 | var wasLeftChild = false 108 | if parent === grandParent?.leftChild { 109 | wasLeftChild = true 110 | } 111 | 112 | //2. My new right child is my old parent 113 | self.rightChild = parent 114 | self.rightChild?.parent = self 115 | 116 | //3. My new parent is my old grandparent 117 | self.parent = grandParent 118 | if wasLeftChild { 119 | grandParent?.leftChild = self 120 | }else { 121 | grandParent?.rightChild = self 122 | } 123 | 124 | //4. The left child of my new right child is my old right child 125 | self.rightChild?.leftChild = newRightChildsLeftChild 126 | self.rightChild?.leftChild?.parent = self.rightChild 127 | } 128 | 129 | //Left 130 | public func rotateLeft() { 131 | guard let parent = parent else { 132 | return 133 | } 134 | 135 | //1.Lets store some temporary references to use them later 136 | let grandParent = parent.parent 137 | let newLeftChildsRightChild = self.leftChild 138 | var wasLeftChild = false 139 | if parent === grandParent?.leftChild { 140 | wasLeftChild = true 141 | } 142 | 143 | //2. My new left child is my old parent 144 | self.leftChild = parent 145 | self.leftChild?.parent = self 146 | 147 | //3. My new parent is my old grandparent 148 | self.parent = grandParent 149 | if wasLeftChild { 150 | grandParent?.leftChild = self 151 | }else { 152 | grandParent?.rightChild = self 153 | } 154 | 155 | //4. The right child of my new left child is my old left child 156 | self.leftChild?.rightChild = newLeftChildsRightChild 157 | self.leftChild?.rightChild?.parent = self.leftChild 158 | } 159 | 160 | // MARK: Insertion 161 | 162 | //Insert operation methods 163 | public func insertNodeFromRoot(value:T) { 164 | //To mantain the binary search tree property, we must ensure that we run the insertNode process from the root node 165 | if let _ = self.parent { 166 | // If parent exists, it is not the root node of the tree 167 | print("You can only add new nodes from the root node of the tree"); 168 | return 169 | } 170 | 171 | self.addNode(value: value) 172 | } 173 | 174 | private func addNode(value:T) { 175 | if value < self.value { 176 | // Value is less than root value: We should insert it in the left subtree. 177 | // Insert it into the left subtree if it exists, if not, create a new node and put it as the left child. 178 | if let leftChild = leftChild { 179 | leftChild.addNode(value: value) 180 | }else { 181 | let newNode = RedBlackTreeNode(value: value) 182 | newNode.parent = self 183 | newNode.color = RedBlackTreeColor.red 184 | leftChild = newNode 185 | 186 | //Review tree color structure 187 | insertionReviewStep1 (node: newNode) 188 | } 189 | }else { 190 | // Value is greater than root value: We should insert it in the right subtree 191 | // Insert it into the right subtree if it exists, if not, create a new node and put it as the right child. 192 | if let rightChild = rightChild { 193 | rightChild.addNode(value: value) 194 | }else { 195 | let newNode = RedBlackTreeNode(value: value) 196 | newNode.parent = self 197 | newNode.color = RedBlackTreeColor.red 198 | rightChild = newNode 199 | 200 | //Review tree color structure 201 | insertionReviewStep1(node: newNode) 202 | } 203 | } 204 | } 205 | 206 | // 1. Root must be black 207 | private func insertionReviewStep1(node:RedBlackTreeNode) { 208 | if let _ = node.parent { 209 | insertionReviewStep2(node: node) 210 | } else { 211 | node.color = .black 212 | } 213 | } 214 | 215 | // 2. Parent is black? 216 | private func insertionReviewStep2(node:RedBlackTreeNode) { 217 | if node.parent?.color == .black { 218 | return 219 | } 220 | 221 | insertionReviewStep3(node: node) 222 | } 223 | 224 | // 3. Parent and uncle are red? 225 | private func insertionReviewStep3(node:RedBlackTreeNode) { 226 | if let uncle = node.uncleNode() { 227 | if uncle.color == .red { 228 | node.parent?.color = .black 229 | uncle.color = .black 230 | if let grandParent = node.grandParentNode() { 231 | grandParent.color = .red 232 | insertionReviewStep1(node: grandParent) 233 | } 234 | return 235 | } 236 | } 237 | 238 | insertionReviewStep4(node: node) 239 | } 240 | 241 | // 4. Parent is red, uncle is black. Node is left child of a right child or right child of a left child 242 | private func insertionReviewStep4(node:RedBlackTreeNode) { 243 | var node = node 244 | guard let grandParent = node.grandParentNode() else { 245 | return 246 | } 247 | 248 | if node === node.parent?.rightChild && node.parent === grandParent.leftChild { 249 | node.parent?.rotateLeft() 250 | node = node.leftChild! 251 | } else if node === node.parent?.leftChild && node.parent === grandParent.rightChild { 252 | node.parent?.rotateRight() 253 | node = node.rightChild! 254 | } 255 | insertionReviewStep5(node: node) 256 | } 257 | 258 | // 5. Parent is red, uncle is black. Node is left child of a left child or it is right child of a right child 259 | private func insertionReviewStep5(node:RedBlackTreeNode) { 260 | guard let grandParent = node.grandParentNode() else { 261 | return 262 | } 263 | node.parent?.color = .black 264 | grandParent.color = .red 265 | if node === node.parent?.leftChild { 266 | grandParent.rotateRight() 267 | }else { 268 | grandParent.rotateLeft() 269 | } 270 | } 271 | 272 | } 273 | 274 | 275 | -------------------------------------------------------------------------------- /Chapter 6/B05101_6_Playgrounds/B05101_6_RedBlackTree.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Chapter 6/B05101_6_Playgrounds/B05101_6_RedBlackTree.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Chapter 6/B05101_6_Playgrounds/B05101_6_RedBlackTree.playground/playground.xcworkspace/xcuserdata/erik.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Swift-Data-Structure-and-Algorithms/5487c541cfc5e87cf329bb40d0b647f9738f1ef0/Chapter 6/B05101_6_Playgrounds/B05101_6_RedBlackTree.playground/playground.xcworkspace/xcuserdata/erik.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Chapter 6/B05101_6_Playgrounds/B05101_6_RedBlackTree.playground/playground.xcworkspace/xcuserdata/mario.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Swift-Data-Structure-and-Algorithms/5487c541cfc5e87cf329bb40d0b647f9738f1ef0/Chapter 6/B05101_6_Playgrounds/B05101_6_RedBlackTree.playground/playground.xcworkspace/xcuserdata/mario.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Chapter 6/B05101_6_Playgrounds/B05101_6_StringSearch.playground/Pages/License.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | /*: 2 | [Previous](@previous) 3 | **** 4 | # The MIT License (MIT) 5 | 6 | ### Copyright (c) 2016 Erik J. Azar & Mario Eguiluz 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in all 16 | copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | 26 | **** 27 | [Previous](@previous) 28 | */ 29 | -------------------------------------------------------------------------------- /Chapter 6/B05101_6_Playgrounds/B05101_6_StringSearch.playground/Pages/StringSearch.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | /*: 2 | # Chapter 6 3 | ## Advanced Searching methods 4 | */ 5 | 6 | //: ## Demonstrate use of different String search methods. 7 | //: 8 | //: ### Find the StringSearch implementation in the Sources/StringSearch.swift file located within this project. 9 | 10 | //: Brute force search 11 | StringSearch.bruteForce(search: ["3","4"], in: ["1","2","3","4","5","6"]) 12 | 13 | //: RabinKarp search 14 | let text = "2359023141526739921" 15 | let pattern = "31415" 16 | let modulo = 13 17 | let base = 10 18 | StringSearch.rabinKarpNumbers(search: pattern, in: text, modulo: modulo, base: base) 19 | 20 | /*: 21 | 22 | The license for this document is available [here](License). 23 | */ 24 | -------------------------------------------------------------------------------- /Chapter 6/B05101_6_Playgrounds/B05101_6_StringSearch.playground/Sources/StringSearch.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StringSearch.swift 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Copyright (c) 2016 Erik J. Azar & Mario Eguiluz 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | 26 | import Foundation 27 | 28 | precedencegroup PowerPrecedence { higherThan: MultiplicationPrecedence } 29 | infix operator ^^ : PowerPrecedence 30 | func ^^ (radix: Int, power: Int) -> Int { 31 | return Int(pow(Double(radix), Double(power))) 32 | } 33 | 34 | public class StringSearch { 35 | // Brutce force using Array of chars 36 | public static func bruteForce(search pattern:[Character], in text:[Character]) { 37 | // Extract m and n 38 | let m = pattern.count - 1 39 | let n = text.count - 1 40 | // Search for the pattern in the text 41 | for index in 0...n - m { 42 | let substringToMatch = text[index...index+m] 43 | print(substringToMatch) 44 | 45 | if substringToMatch == pattern[0...m] { 46 | print("Pattern found") 47 | } 48 | } 49 | } 50 | 51 | // Brutce force using Strings 52 | public static func bruteForce(search pattern:String, in text:String) { 53 | // Extract m and n 54 | let m = pattern.characters.count 55 | let n = text.characters.count 56 | 57 | // Search for the pattern in the text 58 | for index in 0...n - m { 59 | let start = text.index(text.startIndex, offsetBy: index) 60 | let end = text.index(text.startIndex, offsetBy: index + m - 1) 61 | let substringToMatch = text[start...end] 62 | print(substringToMatch) 63 | 64 | if substringToMatch == pattern { 65 | print("Pattern found") 66 | } 67 | } 68 | } 69 | 70 | public static func rabinKarpNumbers(search pattern:String, in text:String, modulo:Int, base:Int) { 71 | // 1. Initialize 72 | 73 | // Put the pattern and the text into arrays of strings -> So "123" will be ["1","2","3"] 74 | let patternArray = pattern.characters.map { String($0) } 75 | let textArray = text.characters.map { String($0) } 76 | 77 | let n = textArray.count 78 | let m = patternArray.count 79 | let h = (base ^^ (m-1)) % modulo 80 | var patternModulo = 0 81 | var lastTextModulo = 0 82 | 83 | // 2. Calculate pattern modulo and the modulo of the first digits of the text (that we will use later to calculate the following ones with modulo arithmetic properties) 84 | for i in 0...m-1 { 85 | guard let nextPatternDigit = Int(patternArray[i]), 86 | let nextTextDigit = Int(textArray[i]) else { 87 | print("Error") 88 | return 89 | } 90 | patternModulo = (base * patternModulo + nextPatternDigit) % modulo 91 | lastTextModulo = (base * lastTextModulo + nextTextDigit) % modulo 92 | } 93 | 94 | // 3. Check for equality and calculate sucesive positions modulos 95 | for s in 0...n - m - 1 { 96 | // Check last calculated modulo with the modulo of the pattern 97 | if patternModulo == lastTextModulo { 98 | // We have a modulo equality. Now we check for the same digits equality (different digits could have the same modulo, so we need this double check) 99 | let substringToMatch = textArray[s...s + m - 1].joined(separator: "") 100 | if pattern == substringToMatch { 101 | print("Pattern occurs at shift: " + "\(s)") 102 | }else { 103 | print("Same modulo but not same pattern: " + "\(s)") 104 | } 105 | } 106 | // Now calculate the modulo of the next group of digits 107 | if s < n - m { 108 | guard let highOrderDigit = Int(textArray[s]), 109 | let lowOrderDigit = Int(textArray[s + m]) else { 110 | print("Error") 111 | return 112 | } 113 | // To calculate the next modulo, we have to subtract the modulo of the high order digit and add in a next step the modulo of the new low order digit 114 | 115 | //1. Subtract previous high order digit modulo 116 | var substractedHighOrderDigit = (base*(lastTextModulo - highOrderDigit * h)) % modulo 117 | if substractedHighOrderDigit < 0 { 118 | //If the modulo was negative we turn it positive (this is because '%' operator in swift is remainder, not modulo) 119 | substractedHighOrderDigit = substractedHighOrderDigit + modulo 120 | } 121 | 122 | //2. Add the new low order digit modulo 123 | var next = (substractedHighOrderDigit + lowOrderDigit) % modulo; 124 | if (next < 0) { 125 | //If the modulo was negative we turn it positive (this is because '%' operator in swift is remainder, not modulo) 126 | next = (next + modulo); 127 | } 128 | 129 | lastTextModulo = next 130 | } 131 | } 132 | } 133 | 134 | } 135 | -------------------------------------------------------------------------------- /Chapter 6/B05101_6_Playgrounds/B05101_6_StringSearch.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Chapter 6/B05101_6_Playgrounds/B05101_6_StringSearch.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Chapter 6/B05101_6_Playgrounds/B05101_6_StringSearch.playground/playground.xcworkspace/xcuserdata/erik.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Swift-Data-Structure-and-Algorithms/5487c541cfc5e87cf329bb40d0b647f9738f1ef0/Chapter 6/B05101_6_Playgrounds/B05101_6_StringSearch.playground/playground.xcworkspace/xcuserdata/erik.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Chapter 6/B05101_6_Playgrounds/B05101_6_StringSearch.playground/playground.xcworkspace/xcuserdata/mario.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Swift-Data-Structure-and-Algorithms/5487c541cfc5e87cf329bb40d0b647f9738f1ef0/Chapter 6/B05101_6_Playgrounds/B05101_6_StringSearch.playground/playground.xcworkspace/xcuserdata/mario.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Chapter 7/B05101_7_Playgrounds.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Swift-Data-Structure-and-Algorithms/5487c541cfc5e87cf329bb40d0b647f9738f1ef0/Chapter 7/B05101_7_Playgrounds.zip -------------------------------------------------------------------------------- /Chapter 8/B05101_8_Performance_Efficiency.playground.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Swift-Data-Structure-and-Algorithms/5487c541cfc5e87cf329bb40d0b647f9738f1ef0/Chapter 8/B05101_8_Performance_Efficiency.playground.zip -------------------------------------------------------------------------------- /Chapter 9/B05101_9_URLShortener.playground.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Swift-Data-Structure-and-Algorithms/5487c541cfc5e87cf329bb40d0b647f9738f1ef0/Chapter 9/B05101_9_URLShortener.playground.zip -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # Swift-Data-Structure-and-Algorithms 5 | This is the code repository for [Swift Data Structure and Algorithms](https://www.packtpub.com/application-development/swift-data-structure-and-algorithms?utm_source=GitHub&utm_campaign=9781785884504&utm_medium=repository), published by Packt. It contains all the supporting project files necessary to work through the book from start to finish. 6 | 7 | ## Instructions and Navigations 8 | All of the code is organized into folders. Each folder starts with a number followed by the application name. For example, Chapter02. 9 | 10 | The code will look like the following: 11 | ``` 12 | var myDict = [1: "One", 2: "Two", 3: "Three"] 13 | if let optResult = myDict[4] { 14 | print(optResult) 15 | } 16 | else { 17 | print("Key Not Found") 18 | } 19 | ``` 20 | 21 | ## What you need: 22 | | Chapter number | Software required (with version) | Hardware specification | OS required | 23 | | -------- | -------- | -------- | -------- | 24 | | All | Xcode 8.1 | Any hardware capable of running macOS | macOS | 25 | 26 | ## Related Books: 27 | [Mastering Swift 3](https://www.packtpub.com/application-development/mastering-swift-3?utm_source=GitHub&utm_medium=repository&utm_campaign=9781786466129) 28 | 29 | [Swift 3 Functional Programming](https://www.packtpub.com/application-development/swift-3-functional-programming?utm_source=GitHub&utm_medium=repository&utm_campaign=9781785883880) 30 | 31 | [Swift: Developing iOS Applications](https://www.packtpub.com/virtualization-and-cloud/swift-developing-ios-applications?utm_source=GitHub&utm_medium=repository&utm_campaign=9781787120242) 32 | ### Download a free PDF 33 | 34 | If you have already purchased a print or Kindle version of this book, you can get a DRM-free PDF version at no cost.
Simply click on the link to claim your free PDF.
35 |

https://packt.link/free-ebook/9781785884504

-------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Packt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | --------------------------------------------------------------------------------