From 8008a24c7a6a631191dcc57191456a9084658867 Mon Sep 17 00:00:00 2001 From: Robert Thompson Date: Thu, 18 Feb 2016 17:46:11 -0500 Subject: [PATCH 0001/1556] Initial commit --- Treap/Treap.swift | 160 ++++ Treap/Treap/Treap.xcodeproj/project.pbxproj | 400 ++++++++++ Treap/Treap/Treap/AppDelegate.swift | 27 + .../AppIcon.appiconset/Contents.json | 58 ++ Treap/Treap/Treap/Base.lproj/MainMenu.xib | 681 ++++++++++++++++++ Treap/Treap/Treap/Info.plist | 34 + Treap/Treap/TreapTests/Info.plist | 24 + Treap/Treap/TreapTests/TreapTests.swift | 57 ++ Treap/TreapCollectionType.swift | 81 +++ Treap/TreapMergeSplit.swift | 113 +++ 10 files changed, 1635 insertions(+) create mode 100644 Treap/Treap.swift create mode 100644 Treap/Treap/Treap.xcodeproj/project.pbxproj create mode 100644 Treap/Treap/Treap/AppDelegate.swift create mode 100644 Treap/Treap/Treap/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 Treap/Treap/Treap/Base.lproj/MainMenu.xib create mode 100644 Treap/Treap/Treap/Info.plist create mode 100644 Treap/Treap/TreapTests/Info.plist create mode 100644 Treap/Treap/TreapTests/TreapTests.swift create mode 100644 Treap/TreapCollectionType.swift create mode 100644 Treap/TreapMergeSplit.swift diff --git a/Treap/Treap.swift b/Treap/Treap.swift new file mode 100644 index 000000000..108eec913 --- /dev/null +++ b/Treap/Treap.swift @@ -0,0 +1,160 @@ +// +// Treap.swift +// TreapExample +// +// Created by Robert Thompson on 7/27/15. +// Copyright © 2015 Robert Thompson. All rights reserved. +// + +import Foundation + +public indirect enum Treap { + case Empty + case Node(key: Key, val: Element, p: Int, left: Treap, right: Treap) + + public init() { + self = .Empty + } + + internal func get(key: Key) -> Element? { + switch self { + case .Empty: + return nil + case let .Node(treeKey, val, _, _, _) where treeKey == key: + return val + case let .Node(treeKey, _, _, left, _) where key < treeKey: + return left.get(key) + case let .Node(treeKey, _, _, _, right) where key > treeKey: + return right.get(key) + default: + return nil + } + } + + public func contains(key: Key) -> Bool { + switch self { + case .Empty: + return false + case let .Node(treeKey, _, _, _, _) where treeKey == key: + return true + case let .Node(treeKey, _, _, left, _) where key < treeKey: + return left.contains(key) + case let .Node(treeKey, _, _, _, right) where key > treeKey: + return right.contains(key) + default: + return false + } + } + + public var depth: Int { + get { + switch self { + case .Empty: + return 0 + case let .Node(_, _, _, left, .Empty): + return 1 + left.depth + case let .Node(_, _, _, .Empty, right): + return 1 + right.depth + case let .Node(_, _, _, left, right): + let leftDepth = left.depth + let rightDepth = right.depth + return 1 + max(leftDepth, rightDepth) + } + + } + } + + public var count: Int { + get { + return Treap.countHelper(self) + } + } + + private static func countHelper(treap: Treap) -> Int + { + if case let .Node(_, _, _, left, right) = treap + { + return countHelper(left) + 1 + countHelper(right) + } + + return 0 + } +} + +internal func leftRotate(tree: Treap) -> Treap { + if case let .Node(key, val, p, .Node(leftKey, leftVal, leftP, leftLeft, leftRight), right) = tree { + return .Node(key: leftKey, val: leftVal, p: leftP, left: leftLeft, right: Treap.Node(key: key, val: val, p: p, left: leftRight, right: right)) + } + else + { + return .Empty + } +} + +internal func rightRotate(tree: Treap) -> Treap { + if case let .Node(key, val, p, left, .Node(rightKey, rightVal, rightP, rightLeft, rightRight)) = tree { + return .Node(key: rightKey, val: rightVal, p: rightP, left: Treap.Node(key: key, val: val, p: p, left: left, right: rightLeft), right: rightRight) + } + else + { + return .Empty + } +} + +public extension Treap { + internal func set(key: Key, val: Element, p: Int = Int(arc4random())) -> Treap { + switch self { + case .Empty: + return .Node(key: key, val: val, p: p, left: .Empty, right: .Empty) + case let .Node(nodeKey, nodeVal, nodeP, left, right) where key != nodeKey: + return insertAndBalance(nodeKey, nodeVal, nodeP, left, right, key, val, p) + case let .Node(nodeKey, _, nodeP, left, right) where key == nodeKey: + return .Node(key: key, val: val, p: nodeP, left: left, right: right) + default: // should never happen + return .Empty + } + + } + + private func insertAndBalance(nodeKey: Key, _ nodeVal: Element, _ nodeP: Int, _ left: Treap, _ right: Treap, _ key: Key, _ val: Element, _ p: Int) -> Treap { + let newChild: Treap + let newNode: Treap + let rotate: (Treap) -> Treap + if key < nodeKey { + newChild = left.set(key, val: val, p: p) + newNode = .Node(key: nodeKey, val: nodeVal, p: nodeP, left: newChild, right: right) + rotate = leftRotate + } + else if key > nodeKey { + newChild = right.set(key, val: val, p: p) + newNode = .Node(key: nodeKey, val: nodeVal, p: nodeP, left: left, right: newChild) + rotate = rightRotate + } + else { + // It should be impossible to reach here + newChild = .Empty + newNode = .Empty + return newNode + } + + if case let .Node(_, _, newChildP, _, _) = newChild where newChildP < nodeP { + return rotate(newNode) + } + else { + return newNode + } + } + + internal func delete(key: Key) throws -> Treap { + switch self { + case .Empty: + throw NSError(domain: "com.wta.treap.errorDomain", code: -1, userInfo: nil) + case let .Node(nodeKey, val, p, left, right) where key < nodeKey: + return try Treap.Node(key: nodeKey, val: val, p: p, left: left.delete(key), right: right) + case let .Node(nodeKey, val, p, left, right) where key > nodeKey: + return try Treap.Node(key: nodeKey, val: val, p: p, left: left, right: right.delete(key)) + case let .Node(_, _, _, left, right): + return merge(left, right: right) + } + } +} diff --git a/Treap/Treap/Treap.xcodeproj/project.pbxproj b/Treap/Treap/Treap.xcodeproj/project.pbxproj new file mode 100644 index 000000000..319a22f37 --- /dev/null +++ b/Treap/Treap/Treap.xcodeproj/project.pbxproj @@ -0,0 +1,400 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + E1E34DC71C7670240023AF4D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E34DC61C7670240023AF4D /* AppDelegate.swift */; }; + E1E34DC91C7670240023AF4D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E1E34DC81C7670240023AF4D /* Assets.xcassets */; }; + E1E34DCC1C7670240023AF4D /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = E1E34DCA1C7670240023AF4D /* MainMenu.xib */; }; + E1E34DD71C7670250023AF4D /* TreapTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E34DD61C7670250023AF4D /* TreapTests.swift */; }; + E1E34DE31C7670350023AF4D /* Treap.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E34DE11C7670350023AF4D /* Treap.swift */; }; + E1E34DE41C7670350023AF4D /* TreapMergeSplit.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E34DE21C7670350023AF4D /* TreapMergeSplit.swift */; }; + E1E34DEA1C7671200023AF4D /* TreapCollectionType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E34DE91C7671200023AF4D /* TreapCollectionType.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + E1E34DD31C7670250023AF4D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E1E34DBB1C7670240023AF4D /* Project object */; + proxyType = 1; + remoteGlobalIDString = E1E34DC21C7670240023AF4D; + remoteInfo = Treap; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + E1E34DC31C7670240023AF4D /* Treap.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Treap.app; sourceTree = BUILT_PRODUCTS_DIR; }; + E1E34DC61C7670240023AF4D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + E1E34DC81C7670240023AF4D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + E1E34DCB1C7670240023AF4D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + E1E34DCD1C7670240023AF4D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + E1E34DD21C7670250023AF4D /* TreapTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TreapTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + E1E34DD61C7670250023AF4D /* TreapTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TreapTests.swift; sourceTree = ""; }; + E1E34DD81C7670250023AF4D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + E1E34DE11C7670350023AF4D /* Treap.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Treap.swift; path = ../../Treap.swift; sourceTree = ""; }; + E1E34DE21C7670350023AF4D /* TreapMergeSplit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TreapMergeSplit.swift; path = ../../TreapMergeSplit.swift; sourceTree = ""; }; + E1E34DE91C7671200023AF4D /* TreapCollectionType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TreapCollectionType.swift; path = ../../TreapCollectionType.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + E1E34DC01C7670240023AF4D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + E1E34DCF1C7670250023AF4D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + E1E34DBA1C7670240023AF4D = { + isa = PBXGroup; + children = ( + E1E34DC51C7670240023AF4D /* Treap */, + E1E34DD51C7670250023AF4D /* TreapTests */, + E1E34DC41C7670240023AF4D /* Products */, + ); + sourceTree = ""; + }; + E1E34DC41C7670240023AF4D /* Products */ = { + isa = PBXGroup; + children = ( + E1E34DC31C7670240023AF4D /* Treap.app */, + E1E34DD21C7670250023AF4D /* TreapTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + E1E34DC51C7670240023AF4D /* Treap */ = { + isa = PBXGroup; + children = ( + E1E34DC61C7670240023AF4D /* AppDelegate.swift */, + E1E34DC81C7670240023AF4D /* Assets.xcassets */, + E1E34DCA1C7670240023AF4D /* MainMenu.xib */, + E1E34DE11C7670350023AF4D /* Treap.swift */, + E1E34DE21C7670350023AF4D /* TreapMergeSplit.swift */, + E1E34DE91C7671200023AF4D /* TreapCollectionType.swift */, + E1E34DCD1C7670240023AF4D /* Info.plist */, + ); + path = Treap; + sourceTree = ""; + }; + E1E34DD51C7670250023AF4D /* TreapTests */ = { + isa = PBXGroup; + children = ( + E1E34DD61C7670250023AF4D /* TreapTests.swift */, + E1E34DD81C7670250023AF4D /* Info.plist */, + ); + path = TreapTests; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + E1E34DC21C7670240023AF4D /* Treap */ = { + isa = PBXNativeTarget; + buildConfigurationList = E1E34DDB1C7670250023AF4D /* Build configuration list for PBXNativeTarget "Treap" */; + buildPhases = ( + E1E34DBF1C7670240023AF4D /* Sources */, + E1E34DC01C7670240023AF4D /* Frameworks */, + E1E34DC11C7670240023AF4D /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Treap; + productName = Treap; + productReference = E1E34DC31C7670240023AF4D /* Treap.app */; + productType = "com.apple.product-type.application"; + }; + E1E34DD11C7670250023AF4D /* TreapTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = E1E34DDE1C7670250023AF4D /* Build configuration list for PBXNativeTarget "TreapTests" */; + buildPhases = ( + E1E34DCE1C7670250023AF4D /* Sources */, + E1E34DCF1C7670250023AF4D /* Frameworks */, + E1E34DD01C7670250023AF4D /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + E1E34DD41C7670250023AF4D /* PBXTargetDependency */, + ); + name = TreapTests; + productName = TreapTests; + productReference = E1E34DD21C7670250023AF4D /* TreapTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + E1E34DBB1C7670240023AF4D /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0720; + LastUpgradeCheck = 0720; + ORGANIZATIONNAME = "WillowTree, Inc."; + TargetAttributes = { + E1E34DC21C7670240023AF4D = { + CreatedOnToolsVersion = 7.2.1; + }; + E1E34DD11C7670250023AF4D = { + CreatedOnToolsVersion = 7.2.1; + TestTargetID = E1E34DC21C7670240023AF4D; + }; + }; + }; + buildConfigurationList = E1E34DBE1C7670240023AF4D /* Build configuration list for PBXProject "Treap" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = E1E34DBA1C7670240023AF4D; + productRefGroup = E1E34DC41C7670240023AF4D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + E1E34DC21C7670240023AF4D /* Treap */, + E1E34DD11C7670250023AF4D /* TreapTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + E1E34DC11C7670240023AF4D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + E1E34DC91C7670240023AF4D /* Assets.xcassets in Resources */, + E1E34DCC1C7670240023AF4D /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + E1E34DD01C7670250023AF4D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + E1E34DBF1C7670240023AF4D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + E1E34DEA1C7671200023AF4D /* TreapCollectionType.swift in Sources */, + E1E34DE31C7670350023AF4D /* Treap.swift in Sources */, + E1E34DC71C7670240023AF4D /* AppDelegate.swift in Sources */, + E1E34DE41C7670350023AF4D /* TreapMergeSplit.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + E1E34DCE1C7670250023AF4D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + E1E34DD71C7670250023AF4D /* TreapTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + E1E34DD41C7670250023AF4D /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = E1E34DC21C7670240023AF4D /* Treap */; + targetProxy = E1E34DD31C7670250023AF4D /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + E1E34DCA1C7670240023AF4D /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + E1E34DCB1C7670240023AF4D /* Base */, + ); + name = MainMenu.xib; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + E1E34DD91C7670250023AF4D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + E1E34DDA1C7670250023AF4D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + }; + name = Release; + }; + E1E34DDC1C7670250023AF4D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Treap/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.willowtree.Treap; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + E1E34DDD1C7670250023AF4D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Treap/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.willowtree.Treap; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + E1E34DDF1C7670250023AF4D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = TreapTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.willowtree.TreapTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Treap.app/Contents/MacOS/Treap"; + }; + name = Debug; + }; + E1E34DE01C7670250023AF4D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = TreapTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.willowtree.TreapTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Treap.app/Contents/MacOS/Treap"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + E1E34DBE1C7670240023AF4D /* Build configuration list for PBXProject "Treap" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + E1E34DD91C7670250023AF4D /* Debug */, + E1E34DDA1C7670250023AF4D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + E1E34DDB1C7670250023AF4D /* Build configuration list for PBXNativeTarget "Treap" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + E1E34DDC1C7670250023AF4D /* Debug */, + E1E34DDD1C7670250023AF4D /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; + E1E34DDE1C7670250023AF4D /* Build configuration list for PBXNativeTarget "TreapTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + E1E34DDF1C7670250023AF4D /* Debug */, + E1E34DE01C7670250023AF4D /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; +/* End XCConfigurationList section */ + }; + rootObject = E1E34DBB1C7670240023AF4D /* Project object */; +} diff --git a/Treap/Treap/Treap/AppDelegate.swift b/Treap/Treap/Treap/AppDelegate.swift new file mode 100644 index 000000000..a156c1cb4 --- /dev/null +++ b/Treap/Treap/Treap/AppDelegate.swift @@ -0,0 +1,27 @@ +// +// AppDelegate.swift +// Treap +// +// Created by Robert Thompson on 2/18/16. +// Copyright © 2016 WillowTree, Inc. All rights reserved. +// + +import Cocoa + +@NSApplicationMain +class AppDelegate: NSObject, NSApplicationDelegate { + + @IBOutlet weak var window: NSWindow! + + + func applicationDidFinishLaunching(aNotification: NSNotification) { + // Insert code here to initialize your application + } + + func applicationWillTerminate(aNotification: NSNotification) { + // Insert code here to tear down your application + } + + +} + diff --git a/Treap/Treap/Treap/Assets.xcassets/AppIcon.appiconset/Contents.json b/Treap/Treap/Treap/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..2db2b1c7c --- /dev/null +++ b/Treap/Treap/Treap/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,58 @@ +{ + "images" : [ + { + "idiom" : "mac", + "size" : "16x16", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "16x16", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "32x32", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "32x32", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "128x128", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "128x128", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "256x256", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "256x256", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "512x512", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "512x512", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Treap/Treap/Treap/Base.lproj/MainMenu.xib b/Treap/Treap/Treap/Base.lproj/MainMenu.xib new file mode 100644 index 000000000..8955ad822 --- /dev/null +++ b/Treap/Treap/Treap/Base.lproj/MainMenu.xib @@ -0,0 +1,681 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Treap/Treap/Treap/Info.plist b/Treap/Treap/Treap/Info.plist new file mode 100644 index 000000000..63294f2da --- /dev/null +++ b/Treap/Treap/Treap/Info.plist @@ -0,0 +1,34 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + Copyright © 2016 WillowTree, Inc. All rights reserved. + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/Treap/Treap/TreapTests/Info.plist b/Treap/Treap/TreapTests/Info.plist new file mode 100644 index 000000000..ba72822e8 --- /dev/null +++ b/Treap/Treap/TreapTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/Treap/Treap/TreapTests/TreapTests.swift b/Treap/Treap/TreapTests/TreapTests.swift new file mode 100644 index 000000000..06421ad78 --- /dev/null +++ b/Treap/Treap/TreapTests/TreapTests.swift @@ -0,0 +1,57 @@ +// +// TreapTests.swift +// TreapTests +// +// Created by Robert Thompson on 2/18/16. +// Copyright © 2016 WillowTree, Inc. All rights reserved. +// + +import XCTest +@testable import Treap + +class TreapTests: XCTestCase { + + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testSanity() { + var treap = Treap.Empty + treap = treap.set(5, val: "a").set(7, val: "b") + XCTAssert(treap.get(5) == "a") + XCTAssert(treap.get(7) == "b") + treap = treap.set(2, val: "c") + XCTAssert(treap.get(2) == "c") + treap = treap.set(2, val: "d") + XCTAssert(treap.get(2) == "d") + treap = try! treap.delete(5) + XCTAssert(!treap.contains(5)) + XCTAssert(treap.contains(7)) + } + + func testFairlyBalanced() { + var treap = Treap.Empty + for i in 0..<1000 { + treap = treap.set(i, val: nil) + } + let depth = treap.depth + XCTAssert(depth < 30, "treap.depth was \(depth)") + } + + func testFairlyBalancedCollection() { + var treap = Treap() + for i in 0..<1000 + { + treap[i] = Optional.None + } + let depth = treap.depth + XCTAssert(depth > 0 && depth < 30) + } + +} diff --git a/Treap/TreapCollectionType.swift b/Treap/TreapCollectionType.swift new file mode 100644 index 000000000..9753b6207 --- /dev/null +++ b/Treap/TreapCollectionType.swift @@ -0,0 +1,81 @@ +// +// TreapCollectionType.swift +// Treap +// +// Created by Robert Thompson on 2/18/16. +// Copyright © 2016 WillowTree, Inc. All rights reserved. +// + +import Foundation + +extension Treap: CollectionType { + public typealias Index = TreapIndex + + public subscript(index: TreapIndex) -> Element { + get { + guard let result = self.get(index.keys[index.keyIndex]) else { + fatalError("Invalid index!") + } + + return result + } + + mutating set { + let key = index.keys[index.keyIndex] + self = self.set(key, val: newValue) + } + } + + public subscript(key: Key) -> Element? { + get { + return self.get(key) + } + + mutating set { + guard let value = newValue else { + let _ = try? self.delete(key) + return + } + + self = self.set(key, val: value) + } + } + + public var startIndex: TreapIndex { + return TreapIndex(keys: keys, keyIndex: 0) + } + + public var endIndex: TreapIndex { + let keys = self.keys + return TreapIndex(keys: keys, keyIndex: keys.count) + } + + private var keys: [Key] { + var results: [Key] = [] + if case let .Node(key, _, _, left, right) = self { + results.appendContentsOf(left.keys) + results.append(key) + results.appendContentsOf(right.keys) + } + + return results + } +} + +public struct TreapIndex: ForwardIndexType { + private let keys: [Key] + private let keyIndex: Int + + public func successor() -> TreapIndex { + return TreapIndex(keys: keys, keyIndex: keyIndex + 1) + } + + private init(keys: [Key] = [], keyIndex: Int = 0) { + self.keys = keys + self.keyIndex = keyIndex + } +} + +public func ==(lhs: TreapIndex, rhs: TreapIndex) -> Bool { + return lhs.keys == rhs.keys && lhs.keyIndex == rhs.keyIndex +} diff --git a/Treap/TreapMergeSplit.swift b/Treap/TreapMergeSplit.swift new file mode 100644 index 000000000..eed6d3d94 --- /dev/null +++ b/Treap/TreapMergeSplit.swift @@ -0,0 +1,113 @@ +// +// TreapMergeSplit.swift +// TreapExample +// +// Created by Robert Thompson on 7/27/15. +// Copyright © 2015 Robert Thompson. All rights reserved. +// + +import Foundation +public extension Treap { + internal func split(key: Key) -> (left: Treap, right: Treap) + { + var current = self + let val: Element + if let newVal = self.get(key) + { + current = try! current.delete(key) + val = newVal + } + else if case let .Node(_, newVal, _, _, _) = self + { + val = newVal + } + else + { + fatalError("No values in treap") + } + + switch self { + case .Node: + if case let .Node(_, _, _, left, right) = current.set(key, val: val, p: -1) + { + return (left: left, right: right) + } + else + { + return (left: .Empty, right: .Empty) + } + default: + return (left: .Empty, right: .Empty) + } + } + + internal var leastKey: Key? { + switch self { + case .Empty: + return nil + case let .Node(key, _, _, .Empty, _): + return key + case let .Node(_, _, _, left, _): + return left.leastKey + } + } + + internal var mostKey: Key? { + switch self { + case .Empty: + return nil + case let .Node(key, _, _, _, .Empty): + return key + case let .Node(_, _, _, _, right): + return right.mostKey + } + } +} + +internal func merge(left: Treap, right: Treap) -> Treap { + switch (left, right) { + case (.Empty, _): + return right + case (_, .Empty): + return left + + case let (.Node(leftKey, leftVal, leftP, leftLeft, leftRight), .Node(rightKey, rightVal, rightP, rightLeft, rightRight)): + if leftP < rightP { + return .Node(key: leftKey, val: leftVal, p: leftP, left: leftLeft, right: merge(leftRight, right: right)) + } + else + { + return .Node(key: rightKey, val: rightVal, p: rightP, left: merge(rightLeft, right: left), right: rightRight) + } + default: + break + } + return .Empty +} + +extension Treap: CustomStringConvertible +{ + public var description: String { + get { + return Treap.descHelper(self, indent: 0) + } + } + + private static func descHelper(treap: Treap, indent: Int) -> String + { + if case let .Node(key, value, priority, left, right) = treap { + var result = "" + let tabs = String(count: indent, repeatedValue: Character("\t")) + + result += descHelper(left, indent: indent + 1) + result += "\n" + tabs + "\(key), \(value), \(priority)\n" + result += descHelper(right, indent: indent + 1) + + return result + } + else + { + return "" + } + } +} \ No newline at end of file From 0598dc1d9105322489522d79d67a64574e8538fc Mon Sep 17 00:00:00 2001 From: Robert Thompson Date: Thu, 18 Feb 2016 17:59:35 -0500 Subject: [PATCH 0002/1556] May as well be BidirectionalIndexType --- Treap/TreapCollectionType.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Treap/TreapCollectionType.swift b/Treap/TreapCollectionType.swift index 9753b6207..a4f37c0b7 100644 --- a/Treap/TreapCollectionType.swift +++ b/Treap/TreapCollectionType.swift @@ -62,7 +62,7 @@ extension Treap: CollectionType { } } -public struct TreapIndex: ForwardIndexType { +public struct TreapIndex: BidirectionalIndexType { private let keys: [Key] private let keyIndex: Int @@ -70,6 +70,10 @@ public struct TreapIndex: ForwardIndexType { return TreapIndex(keys: keys, keyIndex: keyIndex + 1) } + public func predecessor() -> TreapIndex { + return TreapIndex(keys: keys, keyIndex: keyIndex - 1) + } + private init(keys: [Key] = [], keyIndex: Int = 0) { self.keys = keys self.keyIndex = keyIndex From d88f10e94866e1cd6088d6236fcadbf379b51603 Mon Sep 17 00:00:00 2001 From: Robert Thompson Date: Thu, 18 Feb 2016 18:01:22 -0500 Subject: [PATCH 0003/1556] Honestly it's MutableCollectionType --- Treap/TreapCollectionType.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Treap/TreapCollectionType.swift b/Treap/TreapCollectionType.swift index a4f37c0b7..f624bf265 100644 --- a/Treap/TreapCollectionType.swift +++ b/Treap/TreapCollectionType.swift @@ -8,7 +8,7 @@ import Foundation -extension Treap: CollectionType { +extension Treap: MutableCollectionType { public typealias Index = TreapIndex public subscript(index: TreapIndex) -> Element { From 3ed00a3d2dd102b0e68cef456920c7f83416d5b1 Mon Sep 17 00:00:00 2001 From: Robert Thompson Date: Fri, 19 Feb 2016 11:02:24 -0500 Subject: [PATCH 0004/1556] Fix license --- Treap/Treap.swift | 20 ++++++++++++++++++-- Treap/Treap/Treap/AppDelegate.swift | 19 ++++++++++++++++++- Treap/Treap/TreapTests/TreapTests.swift | 20 ++++++++++++++++++-- Treap/TreapCollectionType.swift | 20 ++++++++++++++++++-- Treap/TreapMergeSplit.swift | 20 ++++++++++++++++++-- 5 files changed, 90 insertions(+), 9 deletions(-) diff --git a/Treap/Treap.swift b/Treap/Treap.swift index 108eec913..5413a17c2 100644 --- a/Treap/Treap.swift +++ b/Treap/Treap.swift @@ -3,8 +3,24 @@ // TreapExample // // Created by Robert Thompson on 7/27/15. -// Copyright © 2015 Robert Thompson. All rights reserved. -// +// Copyright © 2016 Robert Thompson +/* Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.*/ import Foundation diff --git a/Treap/Treap/Treap/AppDelegate.swift b/Treap/Treap/Treap/AppDelegate.swift index a156c1cb4..1813d840b 100644 --- a/Treap/Treap/Treap/AppDelegate.swift +++ b/Treap/Treap/Treap/AppDelegate.swift @@ -3,7 +3,24 @@ // Treap // // Created by Robert Thompson on 2/18/16. -// Copyright © 2016 WillowTree, Inc. All rights reserved. +// Copyright © 2016 Robert Thompson +/* Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.*/ // import Cocoa diff --git a/Treap/Treap/TreapTests/TreapTests.swift b/Treap/Treap/TreapTests/TreapTests.swift index 06421ad78..496e2f940 100644 --- a/Treap/Treap/TreapTests/TreapTests.swift +++ b/Treap/Treap/TreapTests/TreapTests.swift @@ -3,8 +3,24 @@ // TreapTests // // Created by Robert Thompson on 2/18/16. -// Copyright © 2016 WillowTree, Inc. All rights reserved. -// +// Copyright © 2016 Robert Thompson +/* Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.*/ import XCTest @testable import Treap diff --git a/Treap/TreapCollectionType.swift b/Treap/TreapCollectionType.swift index f624bf265..36d02eaac 100644 --- a/Treap/TreapCollectionType.swift +++ b/Treap/TreapCollectionType.swift @@ -3,8 +3,24 @@ // Treap // // Created by Robert Thompson on 2/18/16. -// Copyright © 2016 WillowTree, Inc. All rights reserved. -// +// Copyright © 2016 Robert Thompson +/* Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.*/ import Foundation diff --git a/Treap/TreapMergeSplit.swift b/Treap/TreapMergeSplit.swift index eed6d3d94..51929893b 100644 --- a/Treap/TreapMergeSplit.swift +++ b/Treap/TreapMergeSplit.swift @@ -3,8 +3,24 @@ // TreapExample // // Created by Robert Thompson on 7/27/15. -// Copyright © 2015 Robert Thompson. All rights reserved. -// +// Copyright © 2016 Robert Thompson +/* Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.*/ import Foundation public extension Treap { From 87802ee1f878ef854ac52059fac97289e16a163f Mon Sep 17 00:00:00 2001 From: Matthijs Hollemans Date: Wed, 9 Mar 2016 14:28:41 +0100 Subject: [PATCH 0005/1556] Put Edge and Node into Graph.swift It's only supporting code so it shouldn't draw too much attention to itself. --- .../Contents.swift | 4 ++ .../Contents.swift | 7 +++ .../Contents.swift | 5 ++ .../Sources/Graph.swift | 1 - Breadth-First Search/Edge.swift | 11 ---- Breadth-First Search/Graph.swift | 52 ++++++++++++++++++- Breadth-First Search/Node.swift | 32 ------------ .../Tests/Tests.xcodeproj/project.pbxproj | 18 ++----- .../Sources/Graph.swift | 1 - Depth-First Search/Edge.swift | 11 ---- Depth-First Search/Graph.swift | 52 ++++++++++++++++++- Depth-First Search/Node.swift | 32 ------------ .../Tests/Tests.xcodeproj/project.pbxproj | 8 --- 13 files changed, 123 insertions(+), 111 deletions(-) delete mode 100644 Breadth-First Search/Edge.swift delete mode 100644 Breadth-First Search/Node.swift delete mode 100644 Depth-First Search/Edge.swift delete mode 100644 Depth-First Search/Node.swift diff --git a/Breadth-First Search/BreadthFirstSearch.playground/Pages/Minimum spanning tree example.xcplaygroundpage/Contents.swift b/Breadth-First Search/BreadthFirstSearch.playground/Pages/Minimum spanning tree example.xcplaygroundpage/Contents.swift index 181d566d4..c0868c653 100644 --- a/Breadth-First Search/BreadthFirstSearch.playground/Pages/Minimum spanning tree example.xcplaygroundpage/Contents.swift +++ b/Breadth-First Search/BreadthFirstSearch.playground/Pages/Minimum spanning tree example.xcplaygroundpage/Contents.swift @@ -1,3 +1,7 @@ +//: [Previous](@previous) + +//: # Minimum Spanning Tree Example + func breadthFirstSearchMinimumSpanningTree(graph: Graph, source: Node) -> Graph { let minimumSpanningTree = graph.duplicate() diff --git a/Breadth-First Search/BreadthFirstSearch.playground/Pages/Shortest path example.xcplaygroundpage/Contents.swift b/Breadth-First Search/BreadthFirstSearch.playground/Pages/Shortest path example.xcplaygroundpage/Contents.swift index 28cdc6093..be35cc684 100644 --- a/Breadth-First Search/BreadthFirstSearch.playground/Pages/Shortest path example.xcplaygroundpage/Contents.swift +++ b/Breadth-First Search/BreadthFirstSearch.playground/Pages/Shortest path example.xcplaygroundpage/Contents.swift @@ -1,3 +1,7 @@ +//: [Previous](@previous) + +//: # Shortest Path Example + func breadthFirstSearchShortestPath(graph: Graph, source: Node) -> Graph { let shortestPathGraph = graph.duplicate() @@ -44,3 +48,6 @@ graph.addEdge(nodeE, neighbor: nodeH) let shortestPathGraph = breadthFirstSearchShortestPath(graph, source: nodeA) print(shortestPathGraph.nodes) + +//: [Next: Minimum Spanning Tree Example](@next) + diff --git a/Breadth-First Search/BreadthFirstSearch.playground/Pages/Simple example.xcplaygroundpage/Contents.swift b/Breadth-First Search/BreadthFirstSearch.playground/Pages/Simple example.xcplaygroundpage/Contents.swift index ed655b591..8cd7df2f5 100644 --- a/Breadth-First Search/BreadthFirstSearch.playground/Pages/Simple example.xcplaygroundpage/Contents.swift +++ b/Breadth-First Search/BreadthFirstSearch.playground/Pages/Simple example.xcplaygroundpage/Contents.swift @@ -1,3 +1,5 @@ +//: # Breadth-First Search + func breadthFirstSearch(graph: Graph, source: Node) -> [String] { var queue = Queue() queue.enqueue(source) @@ -46,3 +48,6 @@ graph.addEdge(nodeE, neighbor: nodeH) let nodesExplored = breadthFirstSearch(graph, source: nodeA) print(nodesExplored) + +//: [Next: Shortest Path Example](@next) + diff --git a/Breadth-First Search/BreadthFirstSearch.playground/Sources/Graph.swift b/Breadth-First Search/BreadthFirstSearch.playground/Sources/Graph.swift index 181af9e85..e89d4ac97 100644 --- a/Breadth-First Search/BreadthFirstSearch.playground/Sources/Graph.swift +++ b/Breadth-First Search/BreadthFirstSearch.playground/Sources/Graph.swift @@ -13,7 +13,6 @@ public class Graph : CustomStringConvertible, Equatable { public func addEdge(source: Node, neighbor: Node) { let edge = Edge(neighbor: neighbor) - edge.neighbor = neighbor source.neighbors.append(edge) } diff --git a/Breadth-First Search/Edge.swift b/Breadth-First Search/Edge.swift deleted file mode 100644 index 3937a2cc7..000000000 --- a/Breadth-First Search/Edge.swift +++ /dev/null @@ -1,11 +0,0 @@ -public class Edge : Equatable { - public var neighbor: Node - - public init(neighbor: Node) { - self.neighbor = neighbor - } -} - -public func ==(lhs: Edge, rhs: Edge) -> Bool { - return lhs.neighbor == rhs.neighbor -} diff --git a/Breadth-First Search/Graph.swift b/Breadth-First Search/Graph.swift index 181af9e85..6f69ee800 100644 --- a/Breadth-First Search/Graph.swift +++ b/Breadth-First Search/Graph.swift @@ -1,3 +1,54 @@ +// MARK: - Edge + +public class Edge : Equatable { + public var neighbor: Node + + public init(neighbor: Node) { + self.neighbor = neighbor + } +} + +public func ==(lhs: Edge, rhs: Edge) -> Bool { + return lhs.neighbor == rhs.neighbor +} + +// MARK: - Node + +public class Node : CustomStringConvertible, Equatable { + public var neighbors: [Edge] + + public private(set) var label: String + public var distance: Int? + public var visited: Bool + + public init(label: String) { + self.label = label + neighbors = [] + visited = false + } + + public var description: String { + if let distance = distance { + return "Node(label: \(label), distance: \(distance))" + } + return "Node(label: \(label), distance: infinity)" + } + + public var hasDistance: Bool { + return distance != nil + } + + public func remove(edge: Edge) { + neighbors.removeAtIndex(neighbors.indexOf{ $0 === edge }!) + } +} + +public func ==(lhs: Node, rhs: Node) -> Bool { + return lhs.label == rhs.label && lhs.neighbors == rhs.neighbors +} + +// MARK: - Graph + public class Graph : CustomStringConvertible, Equatable { public private(set) var nodes: [Node] @@ -13,7 +64,6 @@ public class Graph : CustomStringConvertible, Equatable { public func addEdge(source: Node, neighbor: Node) { let edge = Edge(neighbor: neighbor) - edge.neighbor = neighbor source.neighbors.append(edge) } diff --git a/Breadth-First Search/Node.swift b/Breadth-First Search/Node.swift deleted file mode 100644 index 000fd78f6..000000000 --- a/Breadth-First Search/Node.swift +++ /dev/null @@ -1,32 +0,0 @@ -public class Node : CustomStringConvertible, Equatable { - public var neighbors: [Edge] - - public private(set) var label: String - public var distance: Int? - public var visited: Bool - - public init(label: String) { - self.label = label - neighbors = [] - visited = false - } - - public var description: String { - if let distance = distance { - return "Node(label: \(label), distance: \(distance))" - } - return "Node(label: \(label), distance: infinity)" - } - - public var hasDistance: Bool { - return distance != nil - } - - public func remove(edge: Edge) { - neighbors.removeAtIndex(neighbors.indexOf{ $0 === edge }!) - } -} - -public func ==(lhs: Node, rhs: Node) -> Bool { - return lhs.label == rhs.label && lhs.neighbors == rhs.neighbors -} diff --git a/Breadth-First Search/Tests/Tests.xcodeproj/project.pbxproj b/Breadth-First Search/Tests/Tests.xcodeproj/project.pbxproj index 8946ba1a6..061e1be44 100644 --- a/Breadth-First Search/Tests/Tests.xcodeproj/project.pbxproj +++ b/Breadth-First Search/Tests/Tests.xcodeproj/project.pbxproj @@ -13,9 +13,7 @@ 83F9C9691C84437C00B3A87F /* BreadthFirstSearchMinimumSpanningTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F9C9661C84437C00B3A87F /* BreadthFirstSearchMinimumSpanningTree.swift */; }; 83F9C96A1C84437C00B3A87F /* BreadthFirstSearchShortestPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F9C9671C84437C00B3A87F /* BreadthFirstSearchShortestPath.swift */; }; 83F9C96C1C8443E800B3A87F /* BreadthFirstSearchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F9C96B1C8443E800B3A87F /* BreadthFirstSearchTests.swift */; }; - 83F9C9711C84449D00B3A87F /* Edge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F9C96D1C84449D00B3A87F /* Edge.swift */; }; 83F9C9721C84449D00B3A87F /* Graph.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F9C96E1C84449D00B3A87F /* Graph.swift */; }; - 83F9C9731C84449D00B3A87F /* Node.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F9C96F1C84449D00B3A87F /* Node.swift */; }; 83F9C9741C84449D00B3A87F /* Queue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F9C9701C84449D00B3A87F /* Queue.swift */; }; /* End PBXBuildFile section */ @@ -28,9 +26,7 @@ 83F9C9661C84437C00B3A87F /* BreadthFirstSearchMinimumSpanningTree.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BreadthFirstSearchMinimumSpanningTree.swift; path = ../BreadthFirstSearchMinimumSpanningTree.swift; sourceTree = SOURCE_ROOT; }; 83F9C9671C84437C00B3A87F /* BreadthFirstSearchShortestPath.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BreadthFirstSearchShortestPath.swift; path = ../BreadthFirstSearchShortestPath.swift; sourceTree = SOURCE_ROOT; }; 83F9C96B1C8443E800B3A87F /* BreadthFirstSearchTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BreadthFirstSearchTests.swift; sourceTree = SOURCE_ROOT; }; - 83F9C96D1C84449D00B3A87F /* Edge.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Edge.swift; path = ../Edge.swift; sourceTree = SOURCE_ROOT; }; 83F9C96E1C84449D00B3A87F /* Graph.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Graph.swift; path = ../Graph.swift; sourceTree = SOURCE_ROOT; }; - 83F9C96F1C84449D00B3A87F /* Node.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Node.swift; path = ../Node.swift; sourceTree = SOURCE_ROOT; }; 83F9C9701C84449D00B3A87F /* Queue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Queue.swift; path = ../Queue.swift; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ @@ -64,16 +60,14 @@ 7B2BBC831C779D720067B71D /* Tests */ = { isa = PBXGroup; children = ( - 83F9C96D1C84449D00B3A87F /* Edge.swift */, - 83F9C96E1C84449D00B3A87F /* Graph.swift */, - 83F9C96F1C84449D00B3A87F /* Node.swift */, - 83F9C9701C84449D00B3A87F /* Queue.swift */, 83F9C9651C84437C00B3A87F /* BreadthFirstSearch.swift */, - 83F9C9671C84437C00B3A87F /* BreadthFirstSearchShortestPath.swift */, - 83F9C9661C84437C00B3A87F /* BreadthFirstSearchMinimumSpanningTree.swift */, 83F9C96B1C8443E800B3A87F /* BreadthFirstSearchTests.swift */, - 83AACB431C8456D200DDAFC7 /* BreadthFirstSearchShortestPathTests.swift */, + 83F9C9661C84437C00B3A87F /* BreadthFirstSearchMinimumSpanningTree.swift */, 83AACB411C844CED00DDAFC7 /* BreadthFirstSearchMinimumSpanningTreeTests.swift */, + 83F9C9671C84437C00B3A87F /* BreadthFirstSearchShortestPath.swift */, + 83AACB431C8456D200DDAFC7 /* BreadthFirstSearchShortestPathTests.swift */, + 83F9C96E1C84449D00B3A87F /* Graph.swift */, + 83F9C9701C84449D00B3A87F /* Queue.swift */, 7B2BBC941C779E7B0067B71D /* Info.plist */, ); name = Tests; @@ -155,9 +149,7 @@ 83F9C9681C84437C00B3A87F /* BreadthFirstSearch.swift in Sources */, 83F9C9741C84449D00B3A87F /* Queue.swift in Sources */, 83F9C96A1C84437C00B3A87F /* BreadthFirstSearchShortestPath.swift in Sources */, - 83F9C9711C84449D00B3A87F /* Edge.swift in Sources */, 83F9C96C1C8443E800B3A87F /* BreadthFirstSearchTests.swift in Sources */, - 83F9C9731C84449D00B3A87F /* Node.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Depth-First Search/DepthFirstSearch.playground/Sources/Graph.swift b/Depth-First Search/DepthFirstSearch.playground/Sources/Graph.swift index 181af9e85..e89d4ac97 100644 --- a/Depth-First Search/DepthFirstSearch.playground/Sources/Graph.swift +++ b/Depth-First Search/DepthFirstSearch.playground/Sources/Graph.swift @@ -13,7 +13,6 @@ public class Graph : CustomStringConvertible, Equatable { public func addEdge(source: Node, neighbor: Node) { let edge = Edge(neighbor: neighbor) - edge.neighbor = neighbor source.neighbors.append(edge) } diff --git a/Depth-First Search/Edge.swift b/Depth-First Search/Edge.swift deleted file mode 100644 index 3937a2cc7..000000000 --- a/Depth-First Search/Edge.swift +++ /dev/null @@ -1,11 +0,0 @@ -public class Edge : Equatable { - public var neighbor: Node - - public init(neighbor: Node) { - self.neighbor = neighbor - } -} - -public func ==(lhs: Edge, rhs: Edge) -> Bool { - return lhs.neighbor == rhs.neighbor -} diff --git a/Depth-First Search/Graph.swift b/Depth-First Search/Graph.swift index 181af9e85..6f69ee800 100644 --- a/Depth-First Search/Graph.swift +++ b/Depth-First Search/Graph.swift @@ -1,3 +1,54 @@ +// MARK: - Edge + +public class Edge : Equatable { + public var neighbor: Node + + public init(neighbor: Node) { + self.neighbor = neighbor + } +} + +public func ==(lhs: Edge, rhs: Edge) -> Bool { + return lhs.neighbor == rhs.neighbor +} + +// MARK: - Node + +public class Node : CustomStringConvertible, Equatable { + public var neighbors: [Edge] + + public private(set) var label: String + public var distance: Int? + public var visited: Bool + + public init(label: String) { + self.label = label + neighbors = [] + visited = false + } + + public var description: String { + if let distance = distance { + return "Node(label: \(label), distance: \(distance))" + } + return "Node(label: \(label), distance: infinity)" + } + + public var hasDistance: Bool { + return distance != nil + } + + public func remove(edge: Edge) { + neighbors.removeAtIndex(neighbors.indexOf{ $0 === edge }!) + } +} + +public func ==(lhs: Node, rhs: Node) -> Bool { + return lhs.label == rhs.label && lhs.neighbors == rhs.neighbors +} + +// MARK: - Graph + public class Graph : CustomStringConvertible, Equatable { public private(set) var nodes: [Node] @@ -13,7 +64,6 @@ public class Graph : CustomStringConvertible, Equatable { public func addEdge(source: Node, neighbor: Node) { let edge = Edge(neighbor: neighbor) - edge.neighbor = neighbor source.neighbors.append(edge) } diff --git a/Depth-First Search/Node.swift b/Depth-First Search/Node.swift deleted file mode 100644 index 000fd78f6..000000000 --- a/Depth-First Search/Node.swift +++ /dev/null @@ -1,32 +0,0 @@ -public class Node : CustomStringConvertible, Equatable { - public var neighbors: [Edge] - - public private(set) var label: String - public var distance: Int? - public var visited: Bool - - public init(label: String) { - self.label = label - neighbors = [] - visited = false - } - - public var description: String { - if let distance = distance { - return "Node(label: \(label), distance: \(distance))" - } - return "Node(label: \(label), distance: infinity)" - } - - public var hasDistance: Bool { - return distance != nil - } - - public func remove(edge: Edge) { - neighbors.removeAtIndex(neighbors.indexOf{ $0 === edge }!) - } -} - -public func ==(lhs: Node, rhs: Node) -> Bool { - return lhs.label == rhs.label && lhs.neighbors == rhs.neighbors -} diff --git a/Depth-First Search/Tests/Tests.xcodeproj/project.pbxproj b/Depth-First Search/Tests/Tests.xcodeproj/project.pbxproj index e3c46e3cc..39c15ce79 100644 --- a/Depth-First Search/Tests/Tests.xcodeproj/project.pbxproj +++ b/Depth-First Search/Tests/Tests.xcodeproj/project.pbxproj @@ -8,9 +8,7 @@ /* Begin PBXBuildFile section */ 83F9C96C1C8443E800B3A87F /* DepthFirstSearchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F9C96B1C8443E800B3A87F /* DepthFirstSearchTests.swift */; }; - 83F9C9711C84449D00B3A87F /* Edge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F9C96D1C84449D00B3A87F /* Edge.swift */; }; 83F9C9721C84449D00B3A87F /* Graph.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F9C96E1C84449D00B3A87F /* Graph.swift */; }; - 83F9C9731C84449D00B3A87F /* Node.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F9C96F1C84449D00B3A87F /* Node.swift */; }; FFC6E11E1C8656D10046BA79 /* DepthFirstSearch.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC6E11D1C8656D10046BA79 /* DepthFirstSearch.swift */; }; /* End PBXBuildFile section */ @@ -18,9 +16,7 @@ 7B2BBC801C779D720067B71D /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 7B2BBC941C779E7B0067B71D /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; }; 83F9C96B1C8443E800B3A87F /* DepthFirstSearchTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DepthFirstSearchTests.swift; sourceTree = SOURCE_ROOT; }; - 83F9C96D1C84449D00B3A87F /* Edge.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Edge.swift; path = ../Edge.swift; sourceTree = SOURCE_ROOT; }; 83F9C96E1C84449D00B3A87F /* Graph.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Graph.swift; path = ../Graph.swift; sourceTree = SOURCE_ROOT; }; - 83F9C96F1C84449D00B3A87F /* Node.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Node.swift; path = ../Node.swift; sourceTree = SOURCE_ROOT; }; FFC6E11D1C8656D10046BA79 /* DepthFirstSearch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DepthFirstSearch.swift; path = ../DepthFirstSearch.swift; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ @@ -54,9 +50,7 @@ 7B2BBC831C779D720067B71D /* Tests */ = { isa = PBXGroup; children = ( - 83F9C96D1C84449D00B3A87F /* Edge.swift */, 83F9C96E1C84449D00B3A87F /* Graph.swift */, - 83F9C96F1C84449D00B3A87F /* Node.swift */, 83F9C96B1C8443E800B3A87F /* DepthFirstSearchTests.swift */, FFC6E11D1C8656D10046BA79 /* DepthFirstSearch.swift */, 7B2BBC941C779E7B0067B71D /* Info.plist */, @@ -134,10 +128,8 @@ buildActionMask = 2147483647; files = ( 83F9C9721C84449D00B3A87F /* Graph.swift in Sources */, - 83F9C9711C84449D00B3A87F /* Edge.swift in Sources */, FFC6E11E1C8656D10046BA79 /* DepthFirstSearch.swift in Sources */, 83F9C96C1C8443E800B3A87F /* DepthFirstSearchTests.swift in Sources */, - 83F9C9731C84449D00B3A87F /* Node.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From 619e604e0086cdc4a4752eb7bdac163c776f3b74 Mon Sep 17 00:00:00 2001 From: Matthijs Hollemans Date: Wed, 9 Mar 2016 14:32:20 +0100 Subject: [PATCH 0006/1556] Add link to @lorentey's repos --- README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/README.markdown b/README.markdown index 1465626f5..833d12a54 100644 --- a/README.markdown +++ b/README.markdown @@ -200,6 +200,7 @@ The following books are available for free online: Other algorithm repositories: - [EKAlgorithms](https://github.com/EvgenyKarkan/EKAlgorithms). A great collection of algorithms in Objective-C. +- [@lorentey](https://github.com/lorentey/). Production-quality Swift implementations of common algorithms and data structures. - [Rosetta Code](http://rosettacode.org). Implementations in pretty much any language you can think of. ## License From a6ddf98faa0d68865b6edf0d70308a16055efa4e Mon Sep 17 00:00:00 2001 From: Matthijs Hollemans Date: Sat, 12 Mar 2016 14:25:21 +0100 Subject: [PATCH 0007/1556] Add explanation of alternative algorithm + more tests --- README.markdown | 2 +- Topological Sort/README.markdown | 15 +++- .../Tests/TopologicalSortTests.swift | 73 ++++++++++++++----- 3 files changed, 71 insertions(+), 19 deletions(-) diff --git a/README.markdown b/README.markdown index 833d12a54..92dfa013f 100644 --- a/README.markdown +++ b/README.markdown @@ -74,7 +74,7 @@ Special-purpose sorts: - Bucket Sort - Counting Sort - Radix Sort -- [Topological Sort](Topological Sort/) +- [Topological Sort](Topological Sort/) :construction: Bad sorting algorithms (don't use these!): diff --git a/Topological Sort/README.markdown b/Topological Sort/README.markdown index 045f910b6..58985c908 100644 --- a/Topological Sort/README.markdown +++ b/Topological Sort/README.markdown @@ -70,5 +70,18 @@ The result of the topological sort looks like this: TODO: I don't think this is correct! There should be no arrows going from right to left! (A valid topological order would be 3, 7, 5, 10, 8, 11, 9, 2 -- or 3, 7, 5, 8, 11, 2, 9, 10.) +## Alternative algorithm -*Written for Swift Algorithm Club by Ali Hafizji* +Even though depth-first search is the typical way to perform a topological sort, there is another algorithm that also does the job. + +1. Find out what the in-degree is of every vertex. +2. Put all the vertices that have no predecessors in a new array called `leaders`. These vertices have in-degree 0 and therefore do not depend on any other vertices. +3. Go through this list of leaders and remove them one-by-one from the graph. We don't actually modify the graph, we just decrement the in-degree of the vertices they point to. That has the same effect. +4. Look at the (former) immediate neighbor vertices of each leader. If any of them now have an in-degree of 0, then they no longer have any predecessors themselves. We'll add those vertices to the `leaders` array too. +5. This repeats until there are no more vertices left to look at. At this point, the `leaders` array contains all the vertices in sorted order. + +This is an **O(n + m)** algorithm where **n** is the number of vertices and **m** is the number of edges. You can see the implementation in [TopologicalSort2.swift](TopologicalSort2.swift). + +I first read about this algorithm in the Algorithm Alley column in Dr. Dobb's Magazine from May 1993. + +*Written for Swift Algorithm Club by Ali Hafizji and Matthijs Hollemans* diff --git a/Topological Sort/Tests/TopologicalSortTests.swift b/Topological Sort/Tests/TopologicalSortTests.swift index 41e7a854f..4d4178cfb 100644 --- a/Topological Sort/Tests/TopologicalSortTests.swift +++ b/Topological Sort/Tests/TopologicalSortTests.swift @@ -1,20 +1,25 @@ -// -// TopologicalSort.swift -// TopologicalSort -// -// Created by Kauserali on 07/03/16. -// -// - +import Foundation import XCTest +extension Graph { + public func loadEdgeList(lines: [String]) { + for line in lines { + let items = line.componentsSeparatedByString(" ").filter { s in !s.isEmpty } + if adjacencyList(forNode: items[0]) == nil { + addNode(items[0]) + } + if adjacencyList(forNode: items[1]) == nil { + addNode(items[1]) + } + addEdge(fromNode: items[0], toNode: items[1]) + } + } +} + class TopologicalSort: XCTestCase { - var graph: Graph! - - override func setUp() { - super.setUp() - graph = Graph() + func testTopologicalSort() { + let graph = Graph() let node5 = graph.addNode("5") let node7 = graph.addNode("7") @@ -34,11 +39,45 @@ class TopologicalSort: XCTestCase { graph.addEdge(fromNode: node11, toNode: node9) graph.addEdge(fromNode: node11, toNode: node10) graph.addEdge(fromNode: node8, toNode: node9) - } - - func testTopologicalSort() { - XCTAssertEqual(graph.topologicalSort(), ["3", "8", "9", "10", "7", "11", "2", "5"]) + XCTAssertEqual(graph.topologicalSort(), ["3", "8", "9", "10", "7", "11", "2", "5"]) XCTAssertEqual(graph.topologicalSort2(), ["3", "7", "5", "8", "11", "2", "9", "10"]) } + + func testTopologicalSortEdgeLists() { + let p1 = ["A B", "A C", "B C", "B D", "C E", "C F", "E D", "F E", "G A", "G F"] + let a1 = ["G", "A", "B", "C", "F", "E", "D"] // TODO + let s1 = ["G", "A", "B", "C", "F", "E", "D"] + + let p2 = ["B C", "C D", "C G", "B F", "D G", "G E", "F G", "F G"] + let a2 = ["B", "C", "F", "D", "G", "E"] // TODO + let s2 = ["B", "C", "F", "D", "G", "E"] + + let p3 = ["S V", "S W", "V T", "W T"] + let a3 = ["S", "V", "W", "T"] // TODO + let s3 = ["S", "V", "W", "T"] + + let p4 = ["5 11", "7 11", "7 8", "3 8", "3 10", "11 2", "11 9", "11 10", "8 9"] + let a4 = ["3", "8", "9", "10", "7", "11", "2", "5"] + let s4 = ["3", "7", "5", "8", "11", "2", "9", "10"] + + let data = [ + (p1, a1, s1), + (p2, a2, s2), + (p3, a3, s3), + (p4, a4, s4), + ] + + for d in data { + let graph = Graph() + graph.loadEdgeList(d.0) + + // TODO: this fails the tests + //let sorted1 = graph.topologicalSort() + //XCTAssertEqual(sorted1, d.1) + + let sorted2 = graph.topologicalSort2() + XCTAssertEqual(sorted2, d.2) + } + } } From 6a7d25873f9adde1e844e3ad95ae412dd408683a Mon Sep 17 00:00:00 2001 From: Pedro Vereza Date: Wed, 9 Mar 2016 09:45:32 -0300 Subject: [PATCH 0008/1556] Adds playground for Longest Common Subsequence --- .../Contents.swift | 62 +++++++++++++++++++ .../contents.xcplayground | 4 ++ .../timeline.xctimeline | 6 ++ 3 files changed, 72 insertions(+) create mode 100644 Longest Common Subsequence/LongestCommonSubsequence.playground/Contents.swift create mode 100644 Longest Common Subsequence/LongestCommonSubsequence.playground/contents.xcplayground create mode 100644 Longest Common Subsequence/LongestCommonSubsequence.playground/timeline.xctimeline diff --git a/Longest Common Subsequence/LongestCommonSubsequence.playground/Contents.swift b/Longest Common Subsequence/LongestCommonSubsequence.playground/Contents.swift new file mode 100644 index 000000000..8f49b45fb --- /dev/null +++ b/Longest Common Subsequence/LongestCommonSubsequence.playground/Contents.swift @@ -0,0 +1,62 @@ +extension String { + func longestCommonSubsequence(other:String) -> String { + + func lcsLength(other: String) -> [[Int]] { + var matrix = [[Int]](count:self.characters.count+1, repeatedValue:[Int](count:other.characters.count+1, repeatedValue:0)) + + for (i, selfChar) in self.characters.enumerate() { + for (j, otherChar) in other.characters.enumerate() { + if (otherChar == selfChar) { + matrix[i+1][j+1] = (matrix[i][j]) + 1 + } + else { + matrix[i+1][j+1] = max(matrix[i][j+1], matrix[i+1][j]) + } + } + } + + return matrix; + } + + func backtrack(matrix: [[Int]]) -> String { + var i = self.characters.count + var j = other.characters.count + var charInSequence = self.endIndex + + var lcs = String() + + while (i >= 1 && j >= 1) { + if (matrix[i][j] == matrix[i][j - 1]) { + j = j - 1 + } + else if (matrix[i][j] == matrix[i - 1][j]) { + i = i - 1 + charInSequence = charInSequence.predecessor() + } + else { + i = i - 1 + j = j - 1 + charInSequence = charInSequence.predecessor() + + lcs.append(self[charInSequence]) + } + } + + return String(lcs.characters.reverse()); + } + + return backtrack(lcsLength(other)) + } +} + +// Examples + +let a = "ABCBX" +let b = "ABDCAB" +let c = "KLMK" + +a.longestCommonSubsequence(c) //"" +a.longestCommonSubsequence("") //"" +a.longestCommonSubsequence(b) //"ABCB" +b.longestCommonSubsequence(a) //"ABCB" +a.longestCommonSubsequence(a) // "ABCBX" diff --git a/Longest Common Subsequence/LongestCommonSubsequence.playground/contents.xcplayground b/Longest Common Subsequence/LongestCommonSubsequence.playground/contents.xcplayground new file mode 100644 index 000000000..5da2641c9 --- /dev/null +++ b/Longest Common Subsequence/LongestCommonSubsequence.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Longest Common Subsequence/LongestCommonSubsequence.playground/timeline.xctimeline b/Longest Common Subsequence/LongestCommonSubsequence.playground/timeline.xctimeline new file mode 100644 index 000000000..bf468afec --- /dev/null +++ b/Longest Common Subsequence/LongestCommonSubsequence.playground/timeline.xctimeline @@ -0,0 +1,6 @@ + + + + + From 308d8e040a41817929509d9b73d593742a901c55 Mon Sep 17 00:00:00 2001 From: Pedro Vereza Date: Wed, 9 Mar 2016 21:20:16 -0300 Subject: [PATCH 0009/1556] Adds code with comments --- .../LongestCommonSubsequence.swift | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 Longest Common Subsequence/LongestCommonSubsequence.swift diff --git a/Longest Common Subsequence/LongestCommonSubsequence.swift b/Longest Common Subsequence/LongestCommonSubsequence.swift new file mode 100644 index 000000000..a6225bb74 --- /dev/null +++ b/Longest Common Subsequence/LongestCommonSubsequence.swift @@ -0,0 +1,68 @@ +extension String { + func longestCommonSubsequence(other:String) -> String { + + // Computes the length of the lcs using dynamic programming + // Output is a matrix of size (n+1)x(m+1), where matrix[x][y] indicates the length + // of lcs between substring (0, x-1) of self and substring (0, y-1) of other. + func lcsLength(other: String) -> [[Int]] { + + //Matrix of size (n+1)x(m+1), algorithm needs first row and first column to be filled with 0 + var matrix = [[Int]](count:self.characters.count+1, repeatedValue:[Int](count:other.characters.count+1, repeatedValue:0)) + + for (i, selfChar) in self.characters.enumerate() { + for (j, otherChar) in other.characters.enumerate() { + if (otherChar == selfChar) { + //Common char found, add 1 to highest lcs found so far + matrix[i+1][j+1] = (matrix[i][j]) + 1 + } + else { + //Not a match, propagates highest lcs length found so far + matrix[i+1][j+1] = max(matrix[i][j+1], matrix[i+1][j]) + } + } + } + + //Due to propagation, lcs length is at matrix[n][m] + return matrix; + } + + //Backtracks from matrix[n][m] to matrix[1][1] looking for chars that are common to both strings + func backtrack(matrix: [[Int]]) -> String { + var i = self.characters.count + var j = other.characters.count + + //charInSequence is in sync with i so we can get self[i] + var charInSequence = self.endIndex + + var lcs = String() + + while (i >= 1 && j >= 1) { + //Indicates propagation without change, i.e. no new char was added to lcs + if (matrix[i][j] == matrix[i][j - 1]) { + j = j - 1 + } + //Indicates propagation without change, i.e. no new char was added to lcs + else if (matrix[i][j] == matrix[i - 1][j]) { + i = i - 1 + //As i was subtracted, move back charInSequence + charInSequence = charInSequence.predecessor() + } + //Value on the left and above are different than current cell. This means 1 was added to lcs length (line 16) + else { + i = i - 1 + j = j - 1 + charInSequence = charInSequence.predecessor() + + lcs.append(self[charInSequence]) + } + } + + //Due to backtrack, chars were added in reverse order: reverse it back. + //Append and reverse is faster than inserting at index 0 + return String(lcs.characters.reverse()); + } + + //Combine dynamic programming approach with backtrack to find the lcs + return backtrack(lcsLength(other)) + } +} \ No newline at end of file From 1a075f3a636d96977c7719d4ec7d5a918cbb3782 Mon Sep 17 00:00:00 2001 From: Pedro Vereza Date: Sat, 12 Mar 2016 17:27:14 -0300 Subject: [PATCH 0010/1556] Adds tests for LCS --- .../Tests/LongestCommonSubsquenceTests.swift | 32 +++ .../Tests/Tests.xcodeproj/project.pbxproj | 257 ++++++++++++++++++ .../xcshareddata/xcschemes/Tests.xcscheme | 90 ++++++ .../Tests/Tests/Info.plist | 24 ++ 4 files changed, 403 insertions(+) create mode 100644 Longest Common Subsequence/Tests/LongestCommonSubsquenceTests.swift create mode 100644 Longest Common Subsequence/Tests/Tests.xcodeproj/project.pbxproj create mode 100644 Longest Common Subsequence/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme create mode 100644 Longest Common Subsequence/Tests/Tests/Info.plist diff --git a/Longest Common Subsequence/Tests/LongestCommonSubsquenceTests.swift b/Longest Common Subsequence/Tests/LongestCommonSubsquenceTests.swift new file mode 100644 index 000000000..75859ca1a --- /dev/null +++ b/Longest Common Subsequence/Tests/LongestCommonSubsquenceTests.swift @@ -0,0 +1,32 @@ +import Foundation +import XCTest + +class LongestCommonSubsquenceTests: XCTestCase { + + func testLCSwithSelfIsSelf() { + let a = "ABCDE" + + XCTAssertEqual(a, a.longestCommonSubsequence(a)) + } + + func testLCSWithEmptyStringIsEmptyString() { + let a = "ABCDE" + + XCTAssertEqual("", a.longestCommonSubsequence("")) + } + + func testLCSIsEmptyWhenNoCharMatches() { + let a = "ABCDE" + let b = "WXYZ" + + XCTAssertEqual("", a.longestCommonSubsequence(b)) + } + + func testLCSIsNotCommutative() { + let a = "ABCDEF" + let b = "XAWDMVBEKD" + + XCTAssertEqual("ADE", a.longestCommonSubsequence(b)) + XCTAssertEqual("ABD", b.longestCommonSubsequence(a)) + } +} diff --git a/Longest Common Subsequence/Tests/Tests.xcodeproj/project.pbxproj b/Longest Common Subsequence/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..39422654f --- /dev/null +++ b/Longest Common Subsequence/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,257 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 4716C7AF1C93751E00F6C1C0 /* LongestCommonSubsquenceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4716C7891C936E0E00F6C1C0 /* LongestCommonSubsquenceTests.swift */; }; + 4716C7B01C93751E00F6C1C0 /* LongestCommonSubsequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4716C7881C936DDD00F6C1C0 /* LongestCommonSubsequence.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 4716C7881C936DDD00F6C1C0 /* LongestCommonSubsequence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LongestCommonSubsequence.swift; path = ../../LongestCommonSubsequence.swift; sourceTree = ""; }; + 4716C7891C936E0E00F6C1C0 /* LongestCommonSubsquenceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LongestCommonSubsquenceTests.swift; path = ../LongestCommonSubsquenceTests.swift; sourceTree = ""; }; + 4716C7A71C93750500F6C1C0 /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 4716C7AB1C93750500F6C1C0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 4716C7A41C93750500F6C1C0 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 4716C7811C936DCB00F6C1C0 = { + isa = PBXGroup; + children = ( + 4716C7A81C93750500F6C1C0 /* Tests */, + 4716C78F1C93746D00F6C1C0 /* Products */, + ); + sourceTree = ""; + }; + 4716C78F1C93746D00F6C1C0 /* Products */ = { + isa = PBXGroup; + children = ( + 4716C7A71C93750500F6C1C0 /* Tests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 4716C7A81C93750500F6C1C0 /* Tests */ = { + isa = PBXGroup; + children = ( + 4716C7891C936E0E00F6C1C0 /* LongestCommonSubsquenceTests.swift */, + 4716C7881C936DDD00F6C1C0 /* LongestCommonSubsequence.swift */, + 4716C7AB1C93750500F6C1C0 /* Info.plist */, + ); + path = Tests; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 4716C7A61C93750500F6C1C0 /* Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4716C7AC1C93750500F6C1C0 /* Build configuration list for PBXNativeTarget "Tests" */; + buildPhases = ( + 4716C7A31C93750500F6C1C0 /* Sources */, + 4716C7A41C93750500F6C1C0 /* Frameworks */, + 4716C7A51C93750500F6C1C0 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Tests; + productName = Tests; + productReference = 4716C7A71C93750500F6C1C0 /* Tests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 4716C7821C936DCB00F6C1C0 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0720; + LastUpgradeCheck = 0720; + TargetAttributes = { + 4716C7A61C93750500F6C1C0 = { + CreatedOnToolsVersion = 7.2.1; + }; + }; + }; + buildConfigurationList = 4716C7851C936DCB00F6C1C0 /* Build configuration list for PBXProject "Tests" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 4716C7811C936DCB00F6C1C0; + productRefGroup = 4716C78F1C93746D00F6C1C0 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 4716C7A61C93750500F6C1C0 /* Tests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 4716C7A51C93750500F6C1C0 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 4716C7A31C93750500F6C1C0 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4716C7AF1C93751E00F6C1C0 /* LongestCommonSubsquenceTests.swift in Sources */, + 4716C7B01C93751E00F6C1C0 /* LongestCommonSubsequence.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 4716C7861C936DCB00F6C1C0 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + }; + name = Debug; + }; + 4716C7871C936DCB00F6C1C0 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + }; + name = Release; + }; + 4716C7AD1C93750500F6C1C0 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = Tests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = me.pedrovereza.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 4716C7AE1C93750500F6C1C0 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = Tests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = me.pedrovereza.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 4716C7851C936DCB00F6C1C0 /* Build configuration list for PBXProject "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4716C7861C936DCB00F6C1C0 /* Debug */, + 4716C7871C936DCB00F6C1C0 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4716C7AC1C93750500F6C1C0 /* Build configuration list for PBXNativeTarget "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4716C7AD1C93750500F6C1C0 /* Debug */, + 4716C7AE1C93750500F6C1C0 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; +/* End XCConfigurationList section */ + }; + rootObject = 4716C7821C936DCB00F6C1C0 /* Project object */; +} diff --git a/Longest Common Subsequence/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Longest Common Subsequence/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..19caeb2ad --- /dev/null +++ b/Longest Common Subsequence/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Longest Common Subsequence/Tests/Tests/Info.plist b/Longest Common Subsequence/Tests/Tests/Info.plist new file mode 100644 index 000000000..ba72822e8 --- /dev/null +++ b/Longest Common Subsequence/Tests/Tests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + From 6832500b62dba4676c2beffd3451f00827acd033 Mon Sep 17 00:00:00 2001 From: Pedro Vereza Date: Sat, 12 Mar 2016 17:47:51 -0300 Subject: [PATCH 0011/1556] Adds README for LCS --- Longest Common Subsequence/README.markdown | 211 +++++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 Longest Common Subsequence/README.markdown diff --git a/Longest Common Subsequence/README.markdown b/Longest Common Subsequence/README.markdown new file mode 100644 index 000000000..719135a54 --- /dev/null +++ b/Longest Common Subsequence/README.markdown @@ -0,0 +1,211 @@ +# Longest Common Subsequence + + +The Longest Common Subsequence (LCS) of two strings is the longest sequence of characters that appear in the same order in both strings. Should not be confused with the Longest Common Substring problem, where characters **must** be a substring of both strings (i.e they have to be immediate neighbours). + +One way to find what's the LCS of two strings `a` and `b` is using Dynamic Programming and a backtracking strategy. During the explanation, remember that `n` is the length of `a` and `m` the length of `b`. + +## Length of LCS - Dynamic Programming + +Dynamic programming is used to determine the length of LCS between all combinations of substrings of `a` and `b`. + + +```swift + // Computes the length of the lcs using dynamic programming + // Output is a matrix of size (n+1)x(m+1), where matrix[x][y] indicates the length + // of lcs between substring (0, x-1) of self and substring (0, y-1) of other. + func lcsLength(other: String) -> [[Int]] { + + //Matrix of size (n+1)x(m+1), algorithm needs first row and first line to be filled with 0 + var matrix = [[Int]](count:self.characters.count+1, repeatedValue:[Int](count:other.characters.count+1, repeatedValue:0)) + + for (i, selfChar) in self.characters.enumerate() { + for (j, otherChar) in other.characters.enumerate() { + if (otherChar == selfChar) { + //Common char found, add 1 to highest lcs found so far + matrix[i+1][j+1] = (matrix[i][j]) + 1 + } + else { + //Not a match, propagates highest lcs length found so far + matrix[i+1][j+1] = max(matrix[i][j+1], matrix[i+1][j]) + } + } + } + + //Due to propagation, lcs length is at matrix[n][m] + return matrix; + } +``` + +Given strings `"ABCBX"` and `"ABDCAB"` the output matrix of `lcsLength` is the following: + +*First row and column added for easier understanding, actual matrix starts on zeros* + +``` +| | Ø | A | B | D | C | A | B | +| Ø | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| A | 0 | 1 | 1 | 1 | 1 | 1 | 1 | +| B | 0 | 1 | 2 | 2 | 2 | 2 | 2 | +| C | 0 | 1 | 2 | 2 | 3 | 3 | 3 | +| B | 0 | 1 | 2 | 2 | 3 | 3 | 4 | +| X | 0 | 1 | 2 | 2 | 3 | 3 | 4 | +``` + +The content of the matrix indicates that position `(i, j)` contains the length of the LCS between substring `(0, i - 1)` of `a` and substring `(0, j - 1)` of `b`. + +Example: `(2, 3)` says that the LCS for `"AB"` and `"ABD"` is 2 + + +## Actual LCS - Backtrack + +Having the length of every combination makes it possible to determine *which* characters are part of the LCS itself by using a backtracking strategy. + +Backtrack starts at matrix[n + 1][m + 1] and *walks* up and left (in this priority) looking for changes that do not indicate a simple propagation. If the number on the left and above are different than the number in the current cell, no propagation happened, it means that `(i, j)` indicates a common char between `a` and `b`, so char at `a[i - 1]` and `b[j - 1]` are part of the LCS and should be stored in the returned value (`self[i - 1]` was used in the code but could be `other[j - 1]`). + +``` +| | Ø| A| B| D| C| A| B| +| Ø | 0| 0| 0| 0| 0| 0| 0| +| A | 0|↖ 1| 1| 1| 1| 1| 1| +| B | 0| 1|↖ 2|← 2| 2| 2| 2| +| C | 0| 1| 2| 2|↖ 3|← 3| 3| +| B | 0| 1| 2| 2| 3| 3|↖ 4| +| X | 0| 1| 2| 2| 3| 3|↑ 4| +``` +Each `↖` move indicates a character (in row/column header) that is part of the LCS. + +One thing to notice is, as it's running backwards, the LCS is built in reverse order. Before returning, the result is reversed to reflect the actual LCS. + + + +```swift + //Backtracks from matrix[n][m] to matrix[1][1] looking for chars that are common to both strings + func backtrack(matrix: [[Int]]) -> String { + var i = self.characters.count + var j = other.characters.count + + //charInSequence is in sync with i so we can get self[i] + var charInSequence = self.endIndex + + var lcs = String() + + while (i >= 1 && j >= 1) { + //Indicates propagation without change, i.e. no new char was added to lcs + if (matrix[i][j] == matrix[i][j - 1]) { + j = j - 1 + } + //Indicates propagation without change, i.e. no new char was added to lcs + else if (matrix[i][j] == matrix[i - 1][j]) { + i = i - 1 + //As i was subtracted, move back charInSequence + charInSequence = charInSequence.predecessor() + } + //Value on the left and above are different than current cell. This means 1 was added to lcs length (line 16) + else { + i = i - 1 + j = j - 1 + charInSequence = charInSequence.predecessor() + + lcs.append(self[charInSequence]) + } + } + + //Due to backtrack, chars were added in reverse order: reverse it back. + //Append and reverse is faster than inserting at index 0 + return String(lcs.characters.reverse()); + } + +``` + + + + +## Putting it all together + + +```swift +extension String { + func longestCommonSubsequence(other:String) -> String { + + // Computes the same of the lcs using dynamic programming + // Output is a matrix of size (n+1)x(m+1), where matrix[x][y] indicates the length + // of lcs between substring (0, x-1) of self and substring (0, y-1) of other. + func lcsLength(other: String) -> [[Int]] { + + //Matrix of size (n+1)x(m+1), algorithm needs first row and first line to be filled with 0 + var matrix = [[Int]](count:self.characters.count+1, repeatedValue:[Int](count:other.characters.count+1, repeatedValue:0)) + + for (i, selfChar) in self.characters.enumerate() { + for (j, otherChar) in other.characters.enumerate() { + if (otherChar == selfChar) { + //Common char found, add 1 to highest lcs found so far + matrix[i+1][j+1] = (matrix[i][j]) + 1 + } + else { + //Not a match, propagates highest lcs length found so far + matrix[i+1][j+1] = max(matrix[i][j+1], matrix[i+1][j]) + } + } + } + + //Due to propagation, lcs length is at matrix[n][m] + return matrix; + } + + //Backtracks from matrix[n][m] to matrix[1][1] looking for chars that are common to both strings + func backtrack(matrix: [[Int]]) -> String { + var i = self.characters.count + var j = other.characters.count + + //charInSequence is in sync with i so we can get self[i] + var charInSequence = self.endIndex + + var lcs = String() + + while (i >= 1 && j >= 1) { + //Indicates propagation without change, i.e. no new char was added to lcs + if (matrix[i][j] == matrix[i][j - 1]) { + j = j - 1 + } + //Indicates propagation without change, i.e. no new char was added to lcs + else if (matrix[i][j] == matrix[i - 1][j]) { + i = i - 1 + //As i was subtracted, move back charInSequence + charInSequence = charInSequence.predecessor() + } + //Value on the left and above are different than current cell. This means 1 was added to lcs length (line 16) + else { + i = i - 1 + j = j - 1 + charInSequence = charInSequence.predecessor() + + lcs.append(self[charInSequence]) + } + } + + //Due to backtrack, chars were added in reverse order: reverse it back. + //Append and reverse is faster than inserting at index 0 + return String(lcs.characters.reverse()); + } + + //Combine dynamic programming approach with backtrack to find the lcs + return backtrack(lcsLength(other)) + } +} +``` + +**Examples:** + +```swift +let a = "ABCBX" +let b = "ABDCAB" +let c = "KLMK" + +a.longestCommonSubsequence(c) //"" +a.longestCommonSubsequence("") //"" +a.longestCommonSubsequence(b) //"ABCB" +b.longestCommonSubsequence(a) //"ABCB" +a.longestCommonSubsequence(a) // "ABCBX" +``` + + +*Written for Swift Algorithm Club by Pedro Vereza* \ No newline at end of file From a5440104ba5008b3105f0f0208bad28b84e95c8e Mon Sep 17 00:00:00 2001 From: Pedro Vereza Date: Sat, 12 Mar 2016 17:49:32 -0300 Subject: [PATCH 0012/1556] Adds LCS tests on travis --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 9a4806998..3a2bcb7b2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,3 +22,4 @@ script: - xcodebuild test -project ./Selection\ Sort/Tests/Tests.xcodeproj -scheme Tests - xcodebuild test -project ./Shell\ Sort/Tests/Tests.xcodeproj -scheme Tests - xcodebuild test -project ./Stack/Tests/Tests.xcodeproj -scheme Tests +- xcodebuild test -project ./Longest\ Common\ Subsequence/Tests/Tests.xcodeproj -scheme Tests From d344becbfbfb054269148cc23261306c337c246a Mon Sep 17 00:00:00 2001 From: Matteo Piombo Date: Sun, 13 Mar 2016 10:15:58 +0100 Subject: [PATCH 0013/1556] Introduce Associated Labels to centroids. This could help showing how to use KMeans as a classifier. Some changes to KMeans properties and function. Updated Tests accordingly. Demo the usage of labels in one small test. --- K-Means/KMeans.swift | 58 ++++++++++++------- K-Means/Tests/KMeansTests.swift | 45 ++++++++------ K-Means/Tests/Tests.xcodeproj/project.pbxproj | 2 +- 3 files changed, 67 insertions(+), 38 deletions(-) diff --git a/K-Means/KMeans.swift b/K-Means/KMeans.swift index 9073b7b46..245a93b4a 100644 --- a/K-Means/KMeans.swift +++ b/K-Means/KMeans.swift @@ -5,21 +5,24 @@ import Foundation -class KMeans { +class KMeans { let numCenters: Int - let convergeDist: Double + let labels: Array