diff --git a/SPM/.gitignore b/SPM/.gitignore
new file mode 100644
index 0000000..6564d5e
--- /dev/null
+++ b/SPM/.gitignore
@@ -0,0 +1,92 @@
+# Xcode
+#
+# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
+
+*.DS_Store
+
+## User settings
+xcuserdata/
+
+## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
+*.xcscmblueprint
+*.xccheckout
+
+## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
+build/
+DerivedData/
+*.moved-aside
+*.pbxuser
+!default.pbxuser
+*.mode1v3
+!default.mode1v3
+*.mode2v3
+!default.mode2v3
+*.perspectivev3
+!default.perspectivev3
+
+## Obj-C/Swift specific
+*.hmap
+
+## App packaging
+*.ipa
+*.dSYM.zip
+*.dSYM
+
+## Playgrounds
+timeline.xctimeline
+playground.xcworkspace
+
+# Swift Package Manager
+#
+# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
+# Packages/
+# Package.pins
+# Package.resolved
+# *.xcodeproj
+#
+# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
+# hence it is not needed unless you have added a package configuration file to your project
+# .swiftpm
+
+.build/
+
+# CocoaPods
+#
+# We recommend against adding the Pods directory to your .gitignore. However
+# you should judge for yourself, the pros and cons are mentioned at:
+# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
+#
+# Pods/
+#
+# Add this line if you want to avoid checking in source code from the Xcode workspace
+# *.xcworkspace
+
+# Carthage
+#
+# Add this line if you want to avoid checking in source code from Carthage dependencies.
+# Carthage/Checkouts
+
+Carthage/Build/
+
+# Accio dependency management
+Dependencies/
+.accio/
+
+# fastlane
+#
+# It is recommended to not store the screenshots in the git repo.
+# Instead, use fastlane to re-generate the screenshots whenever they are needed.
+# For more information about the recommended setup visit:
+# https://docs.fastlane.tools/best-practices/source-control/#source-control
+
+fastlane/report.xml
+fastlane/Preview.html
+fastlane/screenshots/**/*.png
+fastlane/test_output
+
+# Code Injection
+#
+# After new code Injection tools there's a generated folder /iOSInjectionProject
+# https://github.com/johnno1962/injectionforxcode
+
+iOSInjectionProject/
diff --git a/SPM/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/SPM/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..919434a
--- /dev/null
+++ b/SPM/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/SPM/LICENSE b/SPM/LICENSE
new file mode 100644
index 0000000..f288702
--- /dev/null
+++ b/SPM/LICENSE
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
diff --git a/SPM/Package.swift b/SPM/Package.swift
new file mode 100644
index 0000000..c48c764
--- /dev/null
+++ b/SPM/Package.swift
@@ -0,0 +1,28 @@
+// swift-tools-version:5.2
+// The swift-tools-version declares the minimum version of Swift required to build this package.
+
+import PackageDescription
+
+let package = Package(
+ name: "DataStructuresAlgorithms",
+ products: [
+ // Products define the executables and libraries produced by a package, and make them visible to other packages.
+ .library(
+ name: "DataStructuresAlgorithms",
+ targets: ["DataStructuresAlgorithms"]),
+ ],
+ dependencies: [
+ // Dependencies declare other packages that this package depends on.
+ // .package(url: /* package url */, from: "1.0.0"),
+ ],
+ targets: [
+ // Targets are the basic building blocks of a package. A target can define a module or a test suite.
+ // Targets can depend on other targets in this package, and on products in packages which this package depends on.
+ .target(
+ name: "DataStructuresAlgorithms",
+ dependencies: []),
+ .testTarget(
+ name: "DataStructuresAlgorithmsTests",
+ dependencies: ["DataStructuresAlgorithms"]),
+ ]
+)
diff --git a/SPM/README.md b/SPM/README.md
new file mode 100644
index 0000000..d85aa88
--- /dev/null
+++ b/SPM/README.md
@@ -0,0 +1,16 @@
+# DataStructuresAlgs
+This package offers a collection of data structures and algorithms written in Swift.
+This includes well-known data structures and algorithms such as Djikstra's shortest path algorithm, as well as algorithms for specific problems such as checking whether a string contains all unique characters.
+
+Each data structures and algorithm class also has a corresponding unit test with, if applicable, a link to test data/further decription.
+
+## Licence
+
+This swift package can be used freely, see https://github.com/sjaindl/DataStructuresAlgs/blob/master/DataStructuresAlgorithms/LICENSE for license notes.
+
+## Installation
+
+No special prerequisites required. You just need an IDE (preferably Xcode) and clone the source code:
+`git clone https://github.com/sjaindl/DataStructuresAlgs.git`
+
+You can execute all unit tests in the DataStructuresAlgorithmsTest class.
diff --git a/SPM/Sources/DataStructuresAlgorithms/Algorithms/BellmanFord.swift b/SPM/Sources/DataStructuresAlgorithms/Algorithms/BellmanFord.swift
new file mode 100644
index 0000000..7cc769c
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/Algorithms/BellmanFord.swift
@@ -0,0 +1,42 @@
+//
+// BellmanFord.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 09.04.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+open class BellmanFord {
+ public let graph: WeightedDirectedGraph
+
+ public init(graph: WeightedDirectedGraph) {
+ self.graph = graph
+ }
+
+ open func findShortestPath(source: Vertice, target: Vertice) throws -> Int {
+ var distTo = [Int] (repeating: Int.max, count: graph.vertices.count)
+ distTo[source.id] = 0
+
+ var pass = 1
+
+ while pass < graph.vertices.count {
+ for edge in graph.edges() {
+ if distTo[edge.from.id] != Int.max && distTo[edge.to.id] > distTo[edge.from.id] + edge.weight {
+ distTo[edge.to.id] = distTo[edge.from.id] + edge.weight
+ }
+ }
+ pass += 1
+ }
+
+ //Check for negative cycle: There is one, if edges can be forever relaxed.
+ for edge in graph.edges() {
+ if distTo[edge.from.id] != Int.max && distTo[edge.to.id] > distTo[edge.from.id] + edge.weight {
+ throw NSError(domain: "Bellman Ford: Negative Cycle", code: 0, userInfo: nil)
+ }
+ }
+
+ return distTo[target.id]
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/Algorithms/BipartiteGraphChecker.swift b/SPM/Sources/DataStructuresAlgorithms/Algorithms/BipartiteGraphChecker.swift
new file mode 100644
index 0000000..41f3195
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/Algorithms/BipartiteGraphChecker.swift
@@ -0,0 +1,80 @@
+//
+// BipartiteGraph.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 23.04.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+open class BipartiteGraphChecker {
+
+ public enum Color {
+ case red
+ case black
+ case none
+ }
+
+ public var graph: UndirectedGraph
+
+ public init(graph: UndirectedGraph) {
+ self.graph = graph
+ }
+
+ open func isBipartite() throws -> [Color]? {
+ if graph.vertices.count < 1 {
+ return []
+ //a graph with no edges is also Bipiartite. Note that the Bipartite condition says all edges should be from one set to another.
+ }
+
+ var colors: [Color]? = [Color] (repeating: .none, count: graph.vertices.count)
+
+ for vertice in graph.vertices { //important if graph is not connected
+ if colors?[vertice.id] == BipartiteGraphChecker.Color.none {
+ colors = try isBipartite(vertice: vertice, colors: colors)
+ }
+ }
+
+ return colors
+ }
+
+ open func isBipartite(vertice: Vertice, colors: [Color]?) throws -> [Color]? {
+ guard var colors = colors else {
+ return nil
+ }
+
+ let bfsQueue = Queue()
+ let rootNode = graph.vertices[vertice.id]
+
+ colors[rootNode.id] = .red
+ bfsQueue.enqueue(val: rootNode)
+
+ while !bfsQueue.isEmpty() {
+ let curNode = try bfsQueue.dequeue()
+
+ let neighbours = graph.neighbours(v: curNode)
+ var currentHead = neighbours.head
+ let colorForNeighbors: Color = colors[curNode.id] == .black ? .red : .black
+ while let curHead = currentHead {
+ let curVertice = curHead.val
+ if colors[curVertice.id] == colors[curNode.id] {
+ return nil //same color between neighbors (not possible cycle)!
+ }
+
+ if curVertice.id == curNode.id {
+ return nil //graph is not bipartite, if there's a self-loop
+ }
+
+ if colors[curVertice.id] == .none {
+ colors[curVertice.id] = colorForNeighbors
+ bfsQueue.enqueue(val: curVertice)
+ }
+
+ currentHead = currentHead?.next
+ }
+ }
+
+ return colors
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/Algorithms/Djikstra.swift b/SPM/Sources/DataStructuresAlgorithms/Algorithms/Djikstra.swift
new file mode 100644
index 0000000..3d30615
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/Algorithms/Djikstra.swift
@@ -0,0 +1,65 @@
+//
+// Djikstra.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 02.04.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+open class Djikstra {
+ public var graph: WeightedUndirectedGraph
+ public var previous = Dictionary()
+ public var distanceTo = Dictionary()
+
+ public init(graph: WeightedUndirectedGraph) {
+ self.graph = graph
+ for vertice in graph.vertices {
+ vertice.distanceTo = Int.max
+ distanceTo[vertice] = Int.max
+ }
+ }
+
+ open func djikstra(from: Vertice, to: Vertice) throws -> Int? {
+ distanceTo[from] = 0
+ let pq = IndexedMinPriorityQueue(maxElements: graph.vertices.count)
+
+ for vertice in graph.vertices {
+ try? pq.insert(index: vertice.id, key: vertice)
+ }
+
+ while !pq.isEmpty(), let vertice = try? pq.extractMin() {
+ let neighbours = graph.neighbours(v: vertice)
+ var neighbour = neighbours.head
+
+ while let n = neighbour, let curDistToV = distanceTo[vertice], let curDistToNeighbour = distanceTo[n.val.to] {
+ let distInPath = curDistToV == Int.max ? Int.max : curDistToV + n.val.weight
+
+ if distInPath < curDistToNeighbour {
+ distanceTo[n.val.to] = distInPath
+ previous[n.val.to] = vertice
+
+ n.val.to.distanceTo = distInPath
+ try? pq.changeKey(index: n.val.to.id, key: n.val.to)
+ }
+
+ neighbour = neighbour?.next
+ }
+ }
+
+ return distanceTo[to]
+ }
+
+ open func path(to: Vertice) -> [Vertice] {
+ var path: [Vertice] = []
+
+ var prev: Vertice? = to
+ while let prevVertice = prev {
+ path.append(prevVertice)
+ prev = previous[prevVertice]
+ }
+
+ return path.reversed()
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/Algorithms/FloydWarshall.swift b/SPM/Sources/DataStructuresAlgorithms/Algorithms/FloydWarshall.swift
new file mode 100644
index 0000000..f5504f3
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/Algorithms/FloydWarshall.swift
@@ -0,0 +1,37 @@
+//
+// FloydWarshall.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 11.04.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+open class FloydWarshall {
+ public let graph: WeightedDirectedGraphWithAdjMatrix
+
+ public init(graph: WeightedDirectedGraphWithAdjMatrix) {
+ self.graph = graph
+ }
+
+ open func findShortestPaths() throws {
+ for intermediateIndex in 0 ... graph.vertices.count - 1 {
+ for startIndex in 0 ... graph.vertices.count - 1 {
+ for endIndex in 0 ... graph.vertices.count - 1 {
+ if graph.adjMatrix[startIndex][intermediateIndex] < Int.max && graph.adjMatrix[intermediateIndex][endIndex] < Int.max
+ && graph.adjMatrix[startIndex][intermediateIndex] + graph.adjMatrix[intermediateIndex][endIndex] < graph.adjMatrix[startIndex][endIndex] {
+ graph.adjMatrix[startIndex][endIndex] = graph.adjMatrix[startIndex][intermediateIndex] + graph.adjMatrix[intermediateIndex][endIndex]
+ }
+ }
+ }
+ }
+
+ //Check for negative cycle:
+ for index in 0 ... graph.vertices.count - 1 {
+ if graph.adjMatrix[index][index] < 0 {
+ throw NSError(domain: "FloydWarshall: Negative Cycle", code: 0, userInfo: nil)
+ }
+ }
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/Algorithms/GraphSearch.swift b/SPM/Sources/DataStructuresAlgorithms/Algorithms/GraphSearch.swift
new file mode 100644
index 0000000..f55c6fe
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/Algorithms/GraphSearch.swift
@@ -0,0 +1,89 @@
+//
+// GraphSearch.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 27.03.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+open class GraphSearch {
+ private let graph: UndirectedGraph
+ private let start: Vertice
+ private var visited: [Bool]
+
+ public init(graph: UndirectedGraph, start: Vertice) {
+ self.graph = graph
+ self.start = start
+
+ visited = [Bool] (repeating: false, count: graph.vertices.count)
+ }
+
+ open func bfs() {
+ let q = Queue()
+
+ q.enqueue(val: start)
+ visited[start.id] = true
+ while !q.isEmpty() {
+ let v = try! q.dequeue()
+
+ let n = graph.neighbours(v: v)
+ var curNode = n.head
+ while curNode != nil {
+ if !visited[curNode!.val.id] {
+ q.enqueue(val: curNode!.val)
+ visited[curNode!.val.id] = true
+ }
+ curNode = curNode!.next
+ }
+ }
+ }
+
+ open func dfs() {
+ visited[start.id] = true
+ dfs(v: start)
+ }
+
+ open func dfs(v: Vertice) {
+ let n = graph.neighbours(v: v)
+ var curVertice = n.head
+
+ while curVertice != nil {
+ if !visited[curVertice!.val.id] {
+ visited[curVertice!.val.id] = true
+ dfs(v: curVertice!.val)
+ }
+
+ curVertice = curVertice?.next
+ }
+ }
+
+ open func dfsIterative() {
+ let s = Stack()
+ s.push(val: start)
+ visited[start.id] = true
+
+ while !s.isEmpty() {
+ do {
+ let v = try s.pop()
+
+ let n = graph.neighbours(v: v)
+ var curVertice = n.head
+
+ while curVertice != nil {
+ if !visited[curVertice!.val.id] {
+ visited[curVertice!.val.id] = true
+ s.push(val: curVertice!.val)
+ }
+
+ curVertice = curVertice?.next
+ }
+
+ }
+ catch {
+ fatalError()
+ }
+ }
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/Algorithms/Knapsack.swift b/SPM/Sources/DataStructuresAlgorithms/Algorithms/Knapsack.swift
new file mode 100644
index 0000000..9351cc9
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/Algorithms/Knapsack.swift
@@ -0,0 +1,71 @@
+//
+// Knapsack.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 26.04.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+//https://www.geeksforgeeks.org/0-1-knapsack-problem-dp-10/
+open class Knapsack {
+
+ private var knapsack: [[Int]] = []
+
+ public init() { }
+
+ open func knapsack(weights: [Int], values: [Int], maxWeight: Int) throws -> Int {
+ if values.count != weights.count {
+ throw NSError(domain: "Knapsack: values and weights are not of same size", code: 0, userInfo: nil)
+ }
+
+ //base case: no more weight left OR no values left
+ if maxWeight == 0 || values.isEmpty {
+ return 0
+ }
+
+ //compute knapsack without last element
+ let knapsackWithoutLastElement = try knapsack(weights: Array(weights[0 ..< weights.count - 1]), values: Array(values[0 ..< values.count - 1]), maxWeight: maxWeight)
+
+ //if weight of last > maxWeight, the last element definitely can't be included in knapsack
+ if weights[values.count - 1] > maxWeight {
+ return knapsackWithoutLastElement
+ }
+
+ //compute knapsack with last element
+ let knapsackWithLastElement = try values[values.count - 1] + knapsack(weights: Array(weights[0 ..< weights.count - 1]), values: Array(values[0 ..< values.count - 1]), maxWeight: maxWeight - weights[weights.count - 1])
+
+ //case 1: value at last position in values array may be included in knapsack
+ //case 2: value at last position in values array is NOT included in knapsack
+ return max(knapsackWithLastElement, knapsackWithoutLastElement)
+ }
+
+ open func knapsackDynamicProgramming(weights: [Int], values: [Int], maxWeight: Int) throws -> Int {
+ if values.count != weights.count {
+ throw NSError(domain: "Knapsack: values and weights are not of same size", code: 0, userInfo: nil)
+ }
+
+ var knapsack = Array(repeating: Array(repeating: -1, count: maxWeight + 1), count: values.count + 1)
+
+ for valueIndex in 0 ... values.count {
+ for weight in 0 ... maxWeight {
+ if valueIndex == 0 || weight == 0 {
+ knapsack[valueIndex][weight] = 0
+ } else if weights[valueIndex - 1] > weight {
+ //value doesn't fit it knapsack (too much weight)
+ knapsack[valueIndex][weight] = knapsack[valueIndex - 1][weight]
+ } else {
+ //value would fit, take max of both cases:
+ //case 1: value at last position in values array may be included in knapsack
+ //case 2: value at last position in values array is NOT included in knapsack
+ let knapsackWithLastElement = values[valueIndex - 1] + knapsack[valueIndex - 1][weight - weights[valueIndex - 1]]
+ let knapsackWithoutLastElement = knapsack[valueIndex - 1][weight]
+ knapsack[valueIndex][weight] = max(knapsackWithLastElement, knapsackWithoutLastElement)
+ }
+ }
+ }
+
+ return knapsack[values.count][maxWeight]
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/Algorithms/MapReduce.swift b/SPM/Sources/DataStructuresAlgorithms/Algorithms/MapReduce.swift
new file mode 100644
index 0000000..d43b4db
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/Algorithms/MapReduce.swift
@@ -0,0 +1,69 @@
+//
+// MapReduce.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 08.04.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+open class Document {
+ let words: [String]
+
+ public init(words: [String]) {
+ self.words = words
+ }
+}
+
+open class Result: Comparable {
+ public let key: String
+ public let value: Int
+
+ public init(key: String, value: Int) {
+ self.key = key
+ self.value = value
+ }
+
+ public static func < (lhs: Result, rhs: Result) -> Bool {
+ return lhs.key < rhs.key
+ }
+
+ public static func == (lhs: Result, rhs: Result) -> Bool {
+ return lhs.key == rhs.key
+ }
+}
+
+open class MapReduceWordCount {
+ var partialResults: [Result] = []
+ var finalResults: [Result] = []
+
+ public init() { }
+
+ open func map(document: Document) {
+ for word in document.words {
+ emit(partialResult: Result(key: word, value: 1))
+ }
+ }
+
+ open func emit(partialResult: Result) {
+ partialResults.append(partialResult)
+ }
+
+ open func shuffleAndSort() {
+ partialResults.sort()
+ }
+
+ open func reduce(partialResults: [Result]) {
+ if partialResults.count > 0 {
+ let key = partialResults[0].key
+ var sum = 0
+
+ for partialResult in partialResults {
+ sum += partialResult.value
+ }
+
+ finalResults.append(Result(key: key, value: sum))
+ }
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/Algorithms/MergeSort.swift b/SPM/Sources/DataStructuresAlgorithms/Algorithms/MergeSort.swift
new file mode 100644
index 0000000..162393a
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/Algorithms/MergeSort.swift
@@ -0,0 +1,50 @@
+//
+// MergeSort.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 28.03.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+open class MergeSort {
+
+ public static func mergeSort(array: inout [T]) {
+ mergeSort(array: &array, min: 0, max: array.count - 1)
+ }
+
+ public static func mergeSort(array: inout [T], min: Int, max: Int) {
+ if max <= min {
+ return
+ }
+
+ let middle = min + (max - min) / 2
+ mergeSort(array: &array, min: min, max: middle)
+ mergeSort(array: &array, min: middle + 1, max: max)
+ merge(array: &array, min: min, middle: middle, max: max)
+ }
+
+ private static func merge(array: inout [T], min: Int, middle: Int, max: Int) {
+ let aux = array
+ var cur = min
+ var left = min
+ var right = middle + 1
+ while cur <= max {
+ if left > middle {
+ array[cur] = aux[right]
+ right += 1
+ } else if right > max {
+ array[cur] = aux[left]
+ left += 1
+ } else if aux[left] <= aux[right] {
+ array[cur] = aux[left]
+ left += 1
+ } else {
+ array[cur] = aux[right]
+ right += 1
+ }
+ cur += 1
+ }
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/Algorithms/MinimumSpanningTreeKruskal.swift b/SPM/Sources/DataStructuresAlgorithms/Algorithms/MinimumSpanningTreeKruskal.swift
new file mode 100644
index 0000000..494ca34
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/Algorithms/MinimumSpanningTreeKruskal.swift
@@ -0,0 +1,97 @@
+//
+// MinimumSpanningTreeKruskal.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 12.04.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+open class MinimumSpanningTreeKruskal {
+ //1. Sort edges by weight --> O(E log E)
+ //alternative use priority queue --> O(E log E)
+ //2. Pop min edge
+ //3. If there is a cycle, discard (detection with UnionFind)
+ //4. Else include in MST
+
+ public var graph: WeightedUndirectedGraph
+
+ public init(graph: WeightedUndirectedGraph) {
+ self.graph = graph
+ }
+
+ open func minimumSpanningTreeQuickSort() -> [Edge] {
+ var mst: [Edge] = []
+ var edges = graph.edges()
+
+ //test
+ let pq1 = MinHeap()
+ for edge in edges {
+ pq1.insert(val: edge.weight)
+ }
+
+ QuickSort.quickSort(array: &edges) // O(E log E)
+
+ let components = UnionFind(graph: graph)
+
+ var index = 0
+ while mst.count < graph.vertices.count - 1 {
+ let edge = edges[index]
+ let firstVertice = edges[index].from
+ let secondVertice = edges[index].to
+
+ let parentOfFirstVertice = components.find(index: firstVertice.id)
+ let parentOfSecondVertice = components.find(index: secondVertice.id)
+
+ if parentOfFirstVertice != parentOfSecondVertice {
+ //no cylce, if we take this edge
+ mst.append(edge)
+ components.union(firstIndex: parentOfFirstVertice, secondIndex: parentOfSecondVertice)
+ } // else we have a cycle: ignore edge
+
+ index += 1
+ }
+
+ return mst
+ }
+
+ open func minimumSpanningTreeHeap() -> [Edge] {
+ var mst: [Edge] = []
+ let edges = graph.edges()
+
+ //test
+ let pq1 = MinHeap()
+ for edge in edges {
+ pq1.insert(val: edge.weight)
+ }
+
+ let pq = MinHeap()
+ for edge in edges { //O(E log E)
+ pq.insert(val: edge)
+ }
+
+ let components = UnionFind(graph: graph)
+
+ var index = 0
+ while mst.count < graph.vertices.count - 1 {
+
+ let edge = try! pq.extractMin()
+ let firstVertice = edge.from
+ let secondVertice = edge.to
+
+ let parentOfFirstVertice = components.find(index: firstVertice.id)
+ let parentOfSecondVertice = components.find(index: secondVertice.id)
+
+ if parentOfFirstVertice != parentOfSecondVertice {
+ //no cylce, if we take this edge
+ mst.append(edge)
+ components.union(firstIndex: parentOfFirstVertice, secondIndex: parentOfSecondVertice)
+ } // else we have a cycle: ignore edge
+
+ index += 1
+ }
+
+ return mst
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/Algorithms/MinimumSpanningTreePrim.swift b/SPM/Sources/DataStructuresAlgorithms/Algorithms/MinimumSpanningTreePrim.swift
new file mode 100644
index 0000000..21ddeed
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/Algorithms/MinimumSpanningTreePrim.swift
@@ -0,0 +1,58 @@
+//
+// MinimumSpanningTreePrim.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 13.04.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+open class MinimumSpanningTreePrim {
+
+ public var graph: WeightedUndirectedGraph
+
+ public init(graph: WeightedUndirectedGraph) {
+ self.graph = graph
+ }
+
+ open func minimumSpanningTree() -> [Edge] {
+ var mstEdges: [Edge] = []
+ var mstVertices: Set = Set()
+ let outsideVertices: IndexedMinPriorityQueue = IndexedMinPriorityQueue(maxElements: graph.vertices.count)
+
+ for vertice in graph.vertices { // O(V)
+ let weight = vertice.id == 0 ? 0 : Int.max
+ vertice.weight = weight
+ try! outsideVertices.insert(index: vertice.id, key: vertice)
+ }
+
+ while mstVertices.count < graph.vertices.count { // O(V)
+ let minVertice = try! outsideVertices.extractMin()! //O(log V)
+ mstVertices.insert(minVertice)
+
+ if let edge = minVertice.minIngoingEdge {
+ mstEdges.append(edge)
+ }
+
+ let neighbours = graph.neighbours(v: minVertice)
+ var neighbour = neighbours.head
+
+ while let curNeighbour = neighbour { //O(E/V)
+ let edge = curNeighbour.val
+ let otherVertice = minVertice == edge.from ? edge.to : edge.from
+ if !mstVertices.contains(otherVertice) { //O(1)
+ if otherVertice.weight > edge.weight {
+ otherVertice.weight = edge.weight
+ otherVertice.minIngoingEdge = edge
+ try! outsideVertices.changeKey(index: otherVertice.id, key: otherVertice) //O(log V) with IndexPQ.
+ }
+ }
+
+ neighbour = neighbour?.next
+ }
+ }
+
+ return mstEdges
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/Algorithms/Permutation.swift b/SPM/Sources/DataStructuresAlgorithms/Algorithms/Permutation.swift
new file mode 100644
index 0000000..a80d68a
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/Algorithms/Permutation.swift
@@ -0,0 +1,72 @@
+//
+// Permutation.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 27.04.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+//https://www.topcoder.com/generating-permutations/
+open class Permuation {
+
+ public init() { }
+
+ open func permutations(array: inout [T]) -> [[T]] {
+ if array.isEmpty {
+ return []
+ }
+
+ var generatedPermutations: [[T]] = []
+ permutations(array: &array, currentArrayCount: array.count, generatedPermutations: &generatedPermutations)
+ return generatedPermutations
+ }
+
+ private func permutations(array: inout [T], currentArrayCount: Int, generatedPermutations: inout [[T]]) {
+ if currentArrayCount == 1 {
+ generatedPermutations.append(array)
+ return
+ } else {
+ for count in 0 ..< currentArrayCount {
+ swap(array: &array, from: count, to: currentArrayCount - 1)
+ permutations(array: &array, currentArrayCount: currentArrayCount - 1, generatedPermutations: &generatedPermutations)
+ swap(array: &array, from: count, to: currentArrayCount - 1)
+ }
+ }
+ }
+
+ open func heapsPermutations(array: inout [T]) -> [[T]] {
+ if array.isEmpty {
+ return []
+ }
+
+ var permutations: [[T]] = []
+
+ heapsPermutations(array: &array, currentArrayCount: array.count, permutations: &permutations)
+ return permutations
+ }
+
+ private func heapsPermutations(array: inout [T], currentArrayCount: Int, permutations: inout [[T]]) {
+ if currentArrayCount == 1 {
+ permutations.append(array)
+ return
+ } else {
+ for count in 0 ..< currentArrayCount - 1 {
+ heapsPermutations(array: &array, currentArrayCount: currentArrayCount - 1, permutations: &permutations)
+ if currentArrayCount % 2 == 0 {
+ swap(array: &array, from: count, to: currentArrayCount - 1)
+ } else {
+ swap(array: &array, from: 0, to: currentArrayCount - 1)
+ }
+ }
+ }
+ heapsPermutations(array: &array, currentArrayCount: currentArrayCount - 1, permutations: &permutations)
+ }
+
+ private func swap(array: inout [T], from: Int, to: Int) {
+ let temp = array[from]
+ array[from] = array[to]
+ array[to] = temp
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/Algorithms/QuickSort.swift b/SPM/Sources/DataStructuresAlgorithms/Algorithms/QuickSort.swift
new file mode 100644
index 0000000..59d128e
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/Algorithms/QuickSort.swift
@@ -0,0 +1,88 @@
+//
+// QuickSort.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 29.03.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+open class QuickSort {
+ public static func quickSort(array: inout [T]) {
+ if array.count <= 1 {
+ return
+ }
+
+ quickSort(array: &array, min: 0, max: array.count - 1)
+ }
+
+ private static func quickSort(array: inout [T], min: Int, max: Int) {
+ if min < max {
+ let pivot = partition(array: &array, min: min, max: max)
+ quickSort(array: &array, min: min, max: pivot - 1)
+ quickSort(array: &array, min: pivot + 1, max: max)
+ }
+ }
+
+ private static func partition(array: inout [T], min: Int, max: Int) -> Int {
+ var left = min + 1
+ var pivot = medianOfThree(array: array, min: min, max: max)
+ exchange(array: &array, index1: pivot, index2: min)
+ pivot = min
+ var right = max
+
+ while true {
+ while array[left] < array[pivot] {
+ left += 1
+ if left == max {
+ break
+ }
+ }
+
+ while array[right] > array[pivot] {
+ right -= 1
+ if right == min {
+ break
+ }
+ }
+
+ if left >= right {
+ break
+ }
+
+ if !(array[left] < array[right]), !(array[right] < array[left]) {
+ right -= 1
+ } else {
+ exchange(array: &array, index1: left, index2: right)
+ }
+ }
+
+ exchange(array: &array, index1: pivot, index2: right)
+ pivot = right
+
+ return pivot
+ }
+
+ private static func medianOfThree(array: [T], min: Int, max: Int) -> Int {
+ let middle = min + (max - min) / 2
+
+ if array[min] < array[middle] && array[min] > array[max]
+ || array[min] > array[middle] && array[min] < array[max] {
+ return min
+ }
+
+ if array[max] < array[middle] && array[max] > array[min]
+ || array[max] > array[middle] && array[max] < array[min] {
+ return max
+ }
+
+ return middle
+ }
+
+ private static func exchange(array: inout [T], index1: Int, index2: Int) {
+ let temp = array[index1]
+ array[index1] = array[index2]
+ array[index2] = temp
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/Algorithms/RabinKarp.swift b/SPM/Sources/DataStructuresAlgorithms/Algorithms/RabinKarp.swift
new file mode 100644
index 0000000..7bb61f3
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/Algorithms/RabinKarp.swift
@@ -0,0 +1,88 @@
+//
+// RabinKarp.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 04.04.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+open class RabinKarpSubstringSearch {
+ private var base: Int
+ public let hashSize: Int = 2147483647
+ //A good rule of thumb is to pick both values as prime numbers with M (hashSize) as large as possible
+ //so that no integer overflow occurs and "base" being at least the size of the alphabet.
+
+ public init(base: Int) {
+ self.base = base
+ }
+
+ open func substr(of sub: String, in str: String) -> Int? {
+ if sub.count < 1 {
+ return nil
+ }
+
+ if sub.count > str.count {
+ return nil
+ }
+
+ var hashes = [Int] (repeating: -1, count: str.count - sub.count + 1)
+ let stringChars = Array(str)
+
+ hashes[0] = rabinFinterprint(Array(stringChars[0 ... sub.count - 1]))
+
+ for index in 1 ... str.count - sub.count {
+ //let compare = rabinFinterprint(Array(stringChars[index ... index + sub.count - 1]))
+ hashes[index] = shiftedRabin(prevHash: hashes[index - 1], prevChar: stringChars[index - 1], newChar: stringChars[index + sub.count - 1], exp: sub.count - 1)
+ }
+
+ let subStrHash = rabinFinterprint(Array(sub))
+
+ Hash:
+ for (index, hash) in hashes.enumerated() {
+ if hash == subStrHash {
+ for (subIndex, char) in sub.enumerated() {
+ if stringChars[index + subIndex] != char {
+ continue Hash
+ }
+ }
+ return index
+ }
+ }
+
+ return nil
+ }
+
+ private func rabinFinterprint(_ c: [Character]) -> Int {
+ var hash = 0
+ var index = 0
+
+ for exp in stride(from: c.count - 1, to: -1, by: -1) {
+ hash += Int(c[index].asciiValue!) * Int(pow(Double(base), Double(exp)))
+ index += 1
+ }
+
+ hash = hash % hashSize
+
+ if hash < 0 { // in case overflows occurs
+ hash += hashSize;
+ }
+
+ return hash
+ }
+
+ private func shiftedRabin(prevHash: Int, prevChar: Character, newChar: Character, exp: Int) -> Int {
+ let hashOfPrevChar = Int(prevChar.asciiValue!) * Int(pow(Double(base), Double(exp)))
+ let leftShiftedValue = (prevHash - hashOfPrevChar) * base
+ var hash = leftShiftedValue + Int(newChar.asciiValue!)
+
+ hash = hash % hashSize
+
+ if hash < 0 { // in case overflows occurs
+ hash += hashSize;
+ }
+
+ return hash
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/Algorithms/TopologicalSort.swift b/SPM/Sources/DataStructuresAlgorithms/Algorithms/TopologicalSort.swift
new file mode 100644
index 0000000..3f1664f
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/Algorithms/TopologicalSort.swift
@@ -0,0 +1,57 @@
+//
+// TopologicalSort.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 01.04.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+open class TopologicalSort {
+ private var graph: DirectedGraph
+
+ public init(graph: DirectedGraph) {
+ self.graph = graph
+ }
+
+ open func topologicalSort() throws -> Queue {
+ let sort = Queue()
+ let processNext = Queue()
+
+ for vertice in graph.vertices {
+ let neighbours = graph.neighbours(v: vertice)
+ var currentNeighbour = neighbours.head
+ while let current = currentNeighbour {
+ current.val.inboundCount += 1
+ currentNeighbour = current.next
+ }
+ }
+
+ for vertice in graph.vertices {
+ if vertice.inboundCount == 0 {
+ processNext.enqueue(val: vertice)
+ }
+ }
+
+ while !processNext.isEmpty(), let vertice = try? processNext.dequeue() {
+ sort.enqueue(val: vertice)
+ let neighbours = graph.neighbours(v: vertice)
+ var currentNeighbour = neighbours.head
+ while let current = currentNeighbour {
+ current.val.inboundCount -= 1
+ if current.val.inboundCount == 0 {
+ processNext.enqueue(val: current.val)
+ }
+
+ currentNeighbour = current.next
+ }
+ }
+
+ if sort.size != graph.vertices.count {
+ throw NSError(domain: "topologicalSort: There is a cycle in the graph", code: 0, userInfo: nil)
+ }
+
+ return sort
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/Algorithms/TravelingSalesman.swift b/SPM/Sources/DataStructuresAlgorithms/Algorithms/TravelingSalesman.swift
new file mode 100644
index 0000000..e7baf56
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/Algorithms/TravelingSalesman.swift
@@ -0,0 +1,53 @@
+//
+// TravellingSalesman.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 27.04.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+open class TravelingSalesman {
+
+ private var graph: WeightedUndirectedGraphWithAdjMatrix
+ public var minimumDistance = Int.max
+
+ public init(graph: WeightedUndirectedGraphWithAdjMatrix) {
+ self.graph = graph //this should be a complete graph
+ }
+
+ open func travelingSalesman(startCity: Vertice) -> [Int] {
+ var cities: [Int] = []
+
+ for city in graph.vertices {
+ if city != startCity {
+ cities.append(city.id)
+ }
+ }
+
+ var permutations = Permuation().heapsPermutations(array: &cities)
+
+ var minimumRoute: [Int] = []
+
+ while var currentPermutation = permutations.popLast() {
+
+ currentPermutation.append(startCity.id)
+
+ var currentDistance = 0
+ var currentCity = startCity.id
+ for city in currentPermutation {
+ currentDistance += graph.adjMatrix[currentCity][city]
+ currentCity = city
+ }
+
+ if currentDistance < minimumDistance {
+ minimumDistance = currentDistance
+ currentPermutation.insert(startCity.id, at: 0)
+ minimumRoute = currentPermutation
+ }
+ }
+
+ return minimumRoute
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/DataStructures/AVLTree.swift b/SPM/Sources/DataStructuresAlgorithms/DataStructures/AVLTree.swift
new file mode 100644
index 0000000..e013153
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/DataStructures/AVLTree.swift
@@ -0,0 +1,332 @@
+//
+// AVLTree.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 05.04.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+open class AVLTreeNode {
+
+ public var left: AVLTreeNode?
+ public var right: AVLTreeNode?
+ public var parent: AVLTreeNode?
+ public var value: T
+ public var height: Int
+
+ public init(parent: AVLTreeNode?, value: T, height: Int) {
+ self.parent = parent
+ self.value = value
+ self.height = height
+ }
+
+ open func isRoot() -> Bool {
+ return parent == nil
+ }
+
+ open func other() -> AVLTreeNode? {
+ if let left = parent?.left, left.value == value {
+ return parent?.right
+ }
+
+ return parent?.left
+ }
+}
+
+open class AVLTree {
+ public var root: AVLTreeNode?
+ public var count = 0
+
+ public init() { }
+
+ open func insert(val: T) {
+ count += 1
+
+ if root == nil {
+ root = AVLTreeNode(parent: nil, value: val, height: 1)
+ return
+ }
+
+ var current = root
+ while current != nil, let cur = current {
+ if cur.value > val {
+ if cur.left == nil {
+ cur.left = AVLTreeNode(parent: cur, value: val, height: 1)
+ increaseHeight(cur)
+ return
+ } else {
+ current = cur.left
+ }
+ } else {
+ if cur.right == nil {
+ cur.right = AVLTreeNode(parent: cur, value: val, height: 1)
+ increaseHeight(cur)
+ return
+ } else {
+ current = cur.right
+ }
+ }
+ }
+ }
+
+ @discardableResult
+ open func deleteTop() -> AVLTreeNode? {
+ guard let value = root?.value else {
+ return nil
+ }
+
+ count -= 1
+
+ return delete(value: value, root: &root)
+ }
+
+ private func delete(value: T, root: inout AVLTreeNode?) -> AVLTreeNode? {
+ // step 1: Standard BST deletion
+ guard let currentRoot = root else {
+ return nil
+ }
+
+ if value < currentRoot.value {
+ // If the key to be deleted is smaller than the root's key, then it lies in left subtree
+ currentRoot.left = delete(value: value, root: ¤tRoot.left)
+ } else if value > currentRoot.value {
+ // If the key to be deleted is greater than the root's key, then it lies in right subtree
+ currentRoot.right = delete(value: value, root: ¤tRoot.right)
+ } else {
+ // if key is same as root's key, then this is the node to be deleted
+
+ // node with only one child or no child
+ if currentRoot.left == nil || currentRoot.right == nil {
+ root = currentRoot.right == nil ? currentRoot.left : currentRoot.right //could be no or one child
+ } else {
+ // node with two children: Get the inorder successor (smallest in the right subtree)
+ let temp = min(from: currentRoot.right)!
+
+ // Copy the inorder successor's data to this node
+ currentRoot.value = temp.value
+
+ // Delete the inorder successor
+ currentRoot.right = delete(value: temp.value, root: ¤tRoot.right)
+ }
+ }
+
+ // If the tree had only one node then return
+ if root == nil {
+ return nil
+ }
+
+ // step 2: Update height of the current node
+ currentRoot.height = max(currentRoot.left?.height ?? 0, currentRoot.right?.height ?? 0) + 1
+
+ // step 3: Get the balance factor of this node (to check whether this node became unbalanced)
+ let rootBalance = balance(of: currentRoot)
+
+ // If this node becomes unbalanced, then there are 4 cases Left Left Case
+ if rootBalance > 1 && balance(of: currentRoot.left) >= 0 {
+ return rightRotateForDelete(y: currentRoot)
+ }
+
+ // Left Right Case
+ if rootBalance > 1 && balance(of: currentRoot.left) < 0 {
+ currentRoot.left = leftRotateForDelete(x: currentRoot.left)
+ return rightRotateForDelete(y: currentRoot)
+ }
+
+ // Right Right Case
+ if (rootBalance < -1 && balance(of: currentRoot.right) <= 0) {
+ return leftRotateForDelete(x: currentRoot)
+ }
+
+ // Right Left Case
+ if (rootBalance < -1 && balance(of: currentRoot.right) > 0)
+ {
+ currentRoot.right = rightRotateForDelete(y: currentRoot.right);
+ return leftRotateForDelete(x: currentRoot)
+ }
+
+ return root
+ }
+
+ open func minNode() -> AVLTreeNode? {
+ return min(from: root)
+ }
+
+ open func min(from node: AVLTreeNode?) -> AVLTreeNode? {
+ var curNode = node
+ while curNode?.left != nil {
+ curNode = curNode?.left
+ }
+
+ return curNode
+ }
+
+ // Get Balance factor of node N
+ private func balance(of node: AVLTreeNode?) -> Int {
+ guard let left = node?.left, let right = node?.right else {
+ return 0
+ }
+
+ return left.height - right.height
+ }
+
+ private func increaseHeight(_ node: AVLTreeNode) {
+ if node.left != nil, node.right != nil {
+ return //must be balanced
+ }
+
+ var current: AVLTreeNode? = node
+ while current != nil, let cur = current {
+ let leftHeight = cur.left?.height ?? 0
+ let rightHeight = cur.right?.height ?? 0
+
+ cur.height = max(leftHeight, rightHeight) + 1
+
+ let heightDiff = leftHeight - rightHeight
+
+ if heightDiff == 0 {
+ return
+ } else if heightDiff == -2 {
+ let rightLeftHeight = cur.right?.left?.height ?? 0
+ let rightRightHeight = cur.right?.right?.height ?? 0
+
+ if rightLeftHeight > rightRightHeight {
+ //right left shape -> left + right rotation
+ let nodeToRotate = cur.right?.left
+ rightRotate(n: nodeToRotate)
+ leftRotate(n: nodeToRotate)
+ } else {
+ //right right shape -> right rotation
+ leftRotate(n: cur.right)
+ }
+ current = cur.parent
+ } else if heightDiff == 2 {
+ let leftLeftHeight = cur.left?.left?.height ?? 0
+ let leftRightHeight = cur.left?.right?.height ?? 0
+
+ if leftRightHeight > leftLeftHeight {
+ //left right shape -> left + right rotation
+ let nodeToRotate = cur.left?.right
+ leftRotate(n: nodeToRotate)
+ rightRotate(n: nodeToRotate)
+ } else {
+ //left left shape -> right rotation
+ rightRotate(n: cur.left)
+ }
+ current = cur.parent
+ } else {
+ current = cur.parent
+ }
+ }
+ }
+
+ open func description() -> Stack {
+ var stack = Stack()
+ description(node: root, stack: &stack)
+
+ return stack
+ }
+
+ private func description(node: AVLTreeNode?, stack: inout Stack) {
+ if let node = node {
+ stack.push(val: "\(node.value): \(node.height)")
+ description(node: node.left, stack: &stack)
+ description(node: node.right, stack: &stack)
+ }
+ }
+
+ private func rightRotate(n: AVLTreeNode?) {
+ let p = n?.parent
+ let gp = p?.parent
+ let gpLeft = p?.value == gp?.left?.value
+
+ p?.left = n?.right
+ p?.left?.parent = p
+
+ n?.right = p
+ p?.parent = n // p? = n?.right
+
+ n?.parent = gp
+ if gpLeft {
+ gp?.left = n
+ } else {
+ gp?.right = n
+ }
+
+ if gp == nil {
+ root = n
+ }
+
+ let pLeftHeight = p?.left?.height ?? 0
+ let pRightHeight = p?.right?.height ?? 0
+ p?.height = max(pLeftHeight, pRightHeight) + 1
+
+ let nLeftHeight = n?.left?.height ?? 0
+ let nRightHeight = n?.right?.height ?? 0
+ n?.height = max(nLeftHeight, nRightHeight) + 1
+ }
+
+ private func leftRotate(n: AVLTreeNode?) {
+ let p = n?.parent
+ let gp = p?.parent
+ let gpLeft = p?.value == gp?.left?.value
+
+ p?.right = n?.left
+ p?.right?.parent = p
+
+ n?.left = p
+ p?.parent = n
+
+ n?.parent = gp
+ if gpLeft {
+ gp?.left = n
+ } else {
+ gp?.right = n
+ }
+
+ if gp == nil {
+ root = n
+ }
+
+ let pLeftHeight = p?.left?.height ?? 0
+ let pRightHeight = p?.right?.height ?? 0
+ p?.height = max(pLeftHeight, pRightHeight) + 1
+
+ let nLeftHeight = n?.left?.height ?? 0
+ let nRightHeight = n?.right?.height ?? 0
+ n?.height = max(nLeftHeight, nRightHeight) + 1
+ }
+
+ private func rightRotateForDelete(y: AVLTreeNode?) -> AVLTreeNode? {
+ let x = y?.left
+ let T2 = x?.right
+
+ // Perform rotation
+ x?.right = y
+ y?.left = T2
+
+ // Update heights
+ y?.height = max(y?.left?.height ?? 0, y?.right?.height ?? 0) + 1
+ x?.height = max(x?.left?.height ?? 0, x?.right?.height ?? 0) + 1
+
+ // Return new root
+ return x
+ }
+
+ private func leftRotateForDelete(x: AVLTreeNode?) -> AVLTreeNode? {
+ let y = x?.left
+ let T2 = y?.right
+
+ // Perform rotation
+ y?.left = x
+ x?.right = T2
+
+ // Update heights
+ x?.height = max(x?.left?.height ?? 0, x?.right?.height ?? 0) + 1
+ y?.height = max(y?.left?.height ?? 0, y?.right?.height ?? 0) + 1
+
+ // Return new root
+ return y
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/DataStructures/BTree.swift b/SPM/Sources/DataStructuresAlgorithms/DataStructures/BTree.swift
new file mode 100644
index 0000000..b4008a1
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/DataStructures/BTree.swift
@@ -0,0 +1,233 @@
+//
+// BTree.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 18.04.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+open class BTreeNode {
+
+ public var degree: Int
+
+ public var numberOfKeys: Int
+ public var numberOfChilds: Int
+
+ public var keys: [T?]
+ public var childNodes: [BTreeNode?]
+
+ private var maxKeys: Int {
+ return 2 * degree - 1
+ }
+
+ private var maxChilds: Int {
+ return 2 * degree
+ }
+
+ public init(degree: Int) {
+ self.degree = degree
+ numberOfKeys = 0
+ numberOfChilds = 0
+ keys = [T?] (repeatElement(nil, count: 2 * degree - 1))
+ childNodes = [BTreeNode?] (repeatElement(nil, count: 2 * degree))
+ }
+
+ open func traverse(stack: inout Stack) {
+ //inorder traversal
+ for keyIndex in 0 ... numberOfKeys { // numberOfChilds can be one greater than numberOfKeys
+ childNodes[keyIndex]?.traverse(stack: &stack)
+ if let key = keys[keyIndex] {
+ stack.push(val: key)
+ }
+ }
+ }
+
+ open func search(key: T) -> Bool {
+ for nodeIndex in 0 ... numberOfKeys { // numberOfChilds can be one greater than numberOfKeys
+ if let child = childNodes[nodeIndex], child.search(key: key) {
+ return true
+ }
+
+ if let keyAtIndex = keys[nodeIndex] {
+ if keyAtIndex == key {
+ return true
+ }
+ }
+ }
+
+ return false
+ }
+
+ open func isLeafNode() -> Bool {
+ return numberOfChilds == 0
+ }
+
+ open func isFull() -> Bool {
+ return numberOfKeys == maxKeys
+ }
+
+ open func insert(key: T) throws {
+ if numberOfKeys == 0 {
+ try insert(key: key, at: 0)
+ } else {
+ for index in 0 ... numberOfKeys {
+ if let keyAtIndex = keys[index], keyAtIndex > key {
+ try insert(key: key, at: index - 1)
+ return
+ }
+ }
+ try insert(key: key, at: numberOfKeys)
+ }
+ }
+
+ open func insert(key: T?, at index: Int) throws {
+ guard let key = key else {
+ return
+ }
+
+ if numberOfKeys == maxKeys {
+ throw NSError(domain: "BTreeNode: BTreeNode is full", code: 0, userInfo: nil)
+ }
+
+ for keyIndex in stride(from: numberOfKeys - 2, to: index + 1, by: -1) {
+ keys.insert(keys[keyIndex], at: keyIndex + 1)
+ }
+
+ keys[index] = key
+ numberOfKeys += 1
+ }
+
+ open func addChild(child: BTreeNode?, at index: Int) throws {
+ guard let child = child else {
+ return
+ }
+
+ if numberOfChilds == maxChilds {
+ throw NSError(domain: "BTreeNode: BTreeNode is full", code: 0, userInfo: nil)
+ }
+
+ for childIndex in stride(from: numberOfChilds - 2, to: index + 1, by: -1) {
+ childNodes.insert(childNodes[childIndex], at: childIndex + 1)
+ }
+
+ childNodes[index] = child
+ numberOfChilds += 1
+ }
+
+ open func replaceChild(child: BTreeNode?, at index: Int) {
+ if child != nil, childNodes[index] == nil {
+ numberOfChilds += 1
+ }
+
+ childNodes[index] = child
+ }
+}
+
+open class BTree {
+ public var root: BTreeNode?
+
+ public init(root: BTreeNode) {
+ self.root = root
+ }
+
+ open func traverse() -> Stack {
+ var stack = Stack()
+
+ guard let root = root else {
+ return stack
+ }
+
+ root.traverse(stack: &stack)
+
+ return stack
+ }
+
+ open func search(key: T) -> Bool {
+ guard let root = root else {
+ return false
+ }
+
+ return root.search(key: key)
+ }
+
+ open func insert(key: T) throws {
+ guard var root = root else {
+ return
+ }
+
+ if root.isFull() {
+ root = try splitChild(root, of: nil, childIndex: 0)
+ self.root = root
+ }
+
+ var currentNode = root
+
+ while !currentNode.isLeafNode() {
+ var childIndex = currentNode.numberOfChilds - 1
+ for keysIndex in 0 ... currentNode.numberOfKeys {
+ if let keysValue = currentNode.keys[keysIndex], keysValue > key {
+ childIndex = keysIndex
+ break
+ }
+ }
+
+ let childNode = currentNode.childNodes[childIndex]!
+ if !childNode.isFull() {
+ currentNode = currentNode.childNodes[childIndex]!
+ }
+ else {
+ currentNode = try splitChild(childNode, of: currentNode, childIndex: childIndex)
+
+ if key < currentNode.keys[childIndex]! {
+ currentNode = currentNode.childNodes[childIndex]!
+ } else {
+ currentNode = currentNode.childNodes[childIndex + 1]!
+ }
+ }
+ }
+
+ try currentNode.insert(key: key)
+ }
+
+ private func splitChild(_ child: BTreeNode, of root: BTreeNode?, childIndex: Int) throws -> BTreeNode {
+ let leftChild: BTreeNode = BTreeNode(degree: child.degree)
+ let rightChild: BTreeNode = BTreeNode(degree: child.degree)
+
+ let parentNodeIndex = child.numberOfKeys / 2
+
+ for leftIndex in 0 ..< parentNodeIndex {
+ try leftChild.insert(key: child.keys[leftIndex], at: leftIndex)
+ }
+
+ for leftIndex in 0 ... parentNodeIndex {
+ try leftChild.addChild(child: child.childNodes[leftIndex], at: leftIndex)
+ }
+
+ for rightIndex in parentNodeIndex + 1 ..< child.numberOfKeys {
+ try rightChild.insert(key: child.keys[rightIndex], at: rightIndex - parentNodeIndex - 1)
+ }
+
+ if child.numberOfChilds >= parentNodeIndex + 1 {
+ for rightIndex in parentNodeIndex + 1 ... child.numberOfChilds {
+ try rightChild.addChild(child: child.childNodes[rightIndex], at: rightIndex - parentNodeIndex - 1)
+ }
+ }
+
+ if let root = root {
+ try root.insert(key: child.keys[parentNodeIndex], at: childIndex)
+ root.replaceChild(child: leftChild, at: childIndex)
+ try root.addChild(child: rightChild, at: childIndex + 1)
+
+ return root
+ } else {
+ let rootNode = BTreeNode(degree: child.degree)
+ try rootNode.insert(key: child.keys[parentNodeIndex], at: childIndex)
+ try rootNode.addChild(child: leftChild, at: 0)
+ try rootNode.addChild(child: rightChild, at: 1)
+
+ return rootNode
+ }
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/DataStructures/BitVector.swift b/SPM/Sources/DataStructuresAlgorithms/DataStructures/BitVector.swift
new file mode 100644
index 0000000..09b35f4
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/DataStructures/BitVector.swift
@@ -0,0 +1,47 @@
+//
+// BitVector.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 03.05.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+open class BitVector {
+ private let numberOfBits: Int
+ private var bitStorage: [UInt64]
+ private let base = 64
+
+ public init(numberOfBits: Int) {
+ self.numberOfBits = numberOfBits
+
+ //storage has place for 64 bits per UInt64 array entry. Round up.
+ let arraySize = (numberOfBits + base - 1) / base
+ bitStorage = [UInt64] (repeating: 0, count: arraySize)
+ }
+
+ open func setBit(index: Int) {
+ let arrayIndex = index / base
+ let bitIndex = index % base
+ let bit: UInt64 = 1 << bitIndex
+
+ bitStorage[arrayIndex] |= bit
+ }
+
+ open func unsetBit(index: Int) {
+ let arrayIndex = index / base
+ let bitIndex = index % base
+ let bit: UInt64 = ~(1 << bitIndex)
+
+ bitStorage[arrayIndex] &= bit
+ }
+
+ open func isBitSet(index: Int) -> Bool {
+ let arrayIndex = index / base
+ let bitIndex = index % base
+ let bit: UInt64 = 1 << bitIndex
+
+ return bitStorage[arrayIndex] & bit > 0
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/DataStructures/CompressedAVLChildCountTree.swift b/SPM/Sources/DataStructuresAlgorithms/DataStructures/CompressedAVLChildCountTree.swift
new file mode 100644
index 0000000..2605b07
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/DataStructures/CompressedAVLChildCountTree.swift
@@ -0,0 +1,279 @@
+//
+// CompressedAVLChildCountTree.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 27.09.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+open class CompressedAVLChildCountTreeNode {
+ public var left: CompressedAVLChildCountTreeNode?
+ public var right: CompressedAVLChildCountTreeNode?
+ public var parent: CompressedAVLChildCountTreeNode?
+ public var value: T
+ public var height: Int
+
+ //Count of value duplicates in tree node
+ public var valueCount: Int
+
+ public var numElementsInSubtree: Int
+
+ public var totalRank: Int {
+ return valueCount - 1 + leftChildRank
+ }
+
+ public var rightChildRank: Int {
+ return right?.numElementsInSubtree ?? 0
+ }
+
+ public var leftChildRank: Int {
+ return left?.numElementsInSubtree ?? 0
+ }
+
+ public init(parent: CompressedAVLChildCountTreeNode?, value: T, valueCount: Int, numElementsInSubtree: Int, height: Int) {
+ self.parent = parent
+ self.value = value
+ self.valueCount = valueCount
+ self.numElementsInSubtree = numElementsInSubtree
+ self.height = height
+ }
+
+ open func isRoot() -> Bool {
+ return parent == nil
+ }
+
+ open func other() -> CompressedAVLChildCountTreeNode? {
+ if let left = parent?.left, left.value == value {
+ return parent?.right
+ }
+
+ return parent?.left
+ }
+}
+
+open class CompressedAVLChildCountTree {
+ public var root: CompressedAVLChildCountTreeNode?
+
+ public init() { }
+
+ open func insert(val: T) {
+ if root == nil {
+ root = CompressedAVLChildCountTreeNode(parent: nil, value: val, valueCount: 1, numElementsInSubtree: 1, height: 1)
+ return
+ }
+
+ var current = root
+ while current != nil, let cur = current {
+ if cur.value == val {
+ cur.valueCount += 1
+ cur.numElementsInSubtree += 1
+ increaseHeightAndNumElementsInSubtree(cur, duplicate: true)
+ break
+ } else if cur.value > val {
+ if cur.left == nil {
+ cur.left = CompressedAVLChildCountTreeNode(parent: cur, value: val, valueCount: 1, numElementsInSubtree: 1, height: 1)
+ increaseHeightAndNumElementsInSubtree(cur, duplicate: false)
+ return
+ } else {
+ current = cur.left
+ }
+ } else {
+ if cur.right == nil {
+ cur.right = CompressedAVLChildCountTreeNode(parent: cur, value: val, valueCount: 1, numElementsInSubtree: 1, height: 1)
+ increaseHeightAndNumElementsInSubtree(cur, duplicate: false)
+ return
+ } else {
+ current = cur.right
+ }
+ }
+ }
+ }
+
+ open func rank(of value: T) -> Int {
+ guard root != nil else {
+ return 0
+ }
+
+ if let root = root, root.value == value {
+ return root.totalRank
+ }
+
+ var currentNode = root
+ var pathCount = 0
+
+ while let curNode = currentNode, curNode.value != value {
+ if curNode.value > value {
+ //go left
+ if curNode.left == nil {
+ break
+ } else {
+ currentNode = curNode.left
+ }
+ } else {
+ //go right
+ if curNode.right == nil {
+ break
+ } else {
+ pathCount += curNode.totalRank + 1
+ currentNode = curNode.right
+ }
+ }
+ }
+
+ guard let curNode = currentNode else {
+ return 0
+ }
+
+ if curNode.value == value {
+ //exact match
+ return pathCount + curNode.totalRank
+ } else {
+ //element is bigger or smaller
+ return pathCount + (curNode.value < value ? curNode.totalRank + 1 : 0)
+ }
+ }
+
+ private func increaseHeightAndNumElementsInSubtree(_ node: CompressedAVLChildCountTreeNode, duplicate: Bool) {
+ if node.left != nil, node.right != nil {
+ return //must be balanced
+ }
+
+ var current: CompressedAVLChildCountTreeNode? = node
+ while current != nil, let cur = current {
+ let leftNumElementsInSubtree = cur.left?.numElementsInSubtree ?? 0
+ let rightNumElementsInSubtree = cur.right?.numElementsInSubtree ?? 0
+ let leftHeight = cur.left?.height ?? 0
+ let rightHeight = cur.right?.height ?? 0
+
+ cur.numElementsInSubtree = leftNumElementsInSubtree + rightNumElementsInSubtree + cur.valueCount
+ cur.height = max(leftHeight, rightHeight) + 1
+
+ let heightDiff = leftHeight - rightHeight
+
+ if heightDiff == 0, !duplicate {
+ return
+ } else if heightDiff == -2 {
+ let rightLeftHeight = cur.right?.left?.height ?? 0
+ let rightRightHeight = cur.right?.right?.height ?? 0
+
+ if rightLeftHeight > rightRightHeight {
+ //right left shape -> left + right rotation
+ let nodeToRotate = cur.right?.left
+ rightRotate(n: nodeToRotate)
+ leftRotate(n: nodeToRotate)
+ } else {
+ //right right shape -> right rotation
+ leftRotate(n: cur.right)
+ }
+ current = cur.parent
+ } else if heightDiff == 2 {
+ let leftLeftHeight = cur.left?.left?.height ?? 0
+ let leftRightHeight = cur.left?.right?.height ?? 0
+
+ if leftRightHeight > leftLeftHeight {
+ //left right shape -> left + right rotation
+ let nodeToRotate = cur.left?.right
+ leftRotate(n: nodeToRotate)
+ rightRotate(n: nodeToRotate)
+ } else {
+ //left left shape -> right rotation
+ rightRotate(n: cur.left)
+ }
+ current = cur.parent
+ } else {
+ current = cur.parent
+ }
+ }
+ }
+
+ open func description() -> Stack {
+ var stack = Stack()
+ description(node: root, stack: &stack)
+
+ return stack
+ }
+
+ private func description(node: CompressedAVLChildCountTreeNode?, stack: inout Stack) {
+ if let node = node {
+ stack.push(val: "\(node.value): \(node.numElementsInSubtree) - (duplicates \(node.valueCount))")
+ description(node: node.left, stack: &stack)
+ description(node: node.right, stack: &stack)
+ }
+ }
+
+ private func rightRotate(n: CompressedAVLChildCountTreeNode?) {
+ let p = n?.parent
+ let gp = p?.parent
+ let gpLeft = p?.value == gp?.left?.value
+
+ p?.left = n?.right
+ p?.left?.parent = p
+
+ n?.right = p
+ p?.parent = n // p? = n?.right
+
+ n?.parent = gp
+ if gpLeft {
+ gp?.left = n
+ } else {
+ gp?.right = n
+ }
+
+ if gp == nil {
+ root = n
+ }
+
+ let pLeftNumElementsInSubtree = p?.left?.numElementsInSubtree ?? 0
+ let pRightNumElementsInSubtree = p?.right?.numElementsInSubtree ?? 0
+ p?.numElementsInSubtree = pLeftNumElementsInSubtree + pRightNumElementsInSubtree + (p?.valueCount ?? 0)
+ let pLeftHeight = p?.left?.height ?? 0
+ let pRightHeight = p?.right?.height ?? 0
+ p?.height = max(pLeftHeight, pRightHeight) + 1
+
+ let nLeftNumElementsInSubtree = n?.left?.numElementsInSubtree ?? 0
+ let nRightNumElementsInSubtree = n?.right?.numElementsInSubtree ?? 0
+ n?.numElementsInSubtree = nLeftNumElementsInSubtree + nRightNumElementsInSubtree + (n?.valueCount ?? 0)
+ let nLeftHeight = n?.left?.height ?? 0
+ let nRightHeight = n?.right?.height ?? 0
+ n?.height = max(nLeftHeight, nRightHeight) + 1
+ }
+
+ private func leftRotate(n: CompressedAVLChildCountTreeNode?) {
+ let p = n?.parent
+ let gp = p?.parent
+ let gpLeft = p?.value == gp?.left?.value
+
+ p?.right = n?.left
+ p?.right?.parent = p
+
+ n?.left = p
+ p?.parent = n
+
+ n?.parent = gp
+ if gpLeft {
+ gp?.left = n
+ } else {
+ gp?.right = n
+ }
+
+ if gp == nil {
+ root = n
+ }
+
+ let pLeftNumElementsInSubtree = p?.left?.numElementsInSubtree ?? 0
+ let pRightNumElementsInSubtree = p?.right?.numElementsInSubtree ?? 0
+ p?.numElementsInSubtree = pLeftNumElementsInSubtree + pRightNumElementsInSubtree + (p?.valueCount ?? 0)
+ let pLeftHeight = p?.left?.height ?? 0
+ let pRightHeight = p?.right?.height ?? 0
+ p?.height = max(pLeftHeight, pRightHeight) + 1
+
+ let nLeftNumElementsInSubtree = n?.left?.numElementsInSubtree ?? 0
+ let nRightNumElementsInSubtree = n?.right?.numElementsInSubtree ?? 0
+ n?.numElementsInSubtree = nLeftNumElementsInSubtree + nRightNumElementsInSubtree + (n?.valueCount ?? 0)
+ let nLeftHeight = n?.left?.height ?? 0
+ let nRightHeight = n?.right?.height ?? 0
+ n?.height = max(nLeftHeight, nRightHeight) + 1
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/DataStructures/DirectedGraph.swift b/SPM/Sources/DataStructuresAlgorithms/DataStructures/DirectedGraph.swift
new file mode 100644
index 0000000..17a7a37
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/DataStructures/DirectedGraph.swift
@@ -0,0 +1,36 @@
+//
+// DirectedGraph.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 01.04.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+open class DirectedGraph {
+ public let vertices: [Vertice]
+ private var adjList: [DoubleLinkedList] = []
+
+ public init(vertices: [Vertice]) {
+ self.vertices = vertices
+
+ for _ in vertices {
+ adjList.append(DoubleLinkedList())
+ }
+ }
+
+ open func addEdge(v1: Vertice, v2: Vertice) {
+ adjList[v1.id].add(node: Node(val: v2))
+ }
+
+ open func removeEdge(v1: Vertice, v2: Vertice) {
+ if adjList.count > v1.id {
+ adjList[v1.id].removeByKey(val: v2.id)
+ }
+ }
+
+ open func neighbours(v: Vertice) -> DoubleLinkedList {
+ return adjList[v.id]
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/DataStructures/DoubleLinkedList.swift b/SPM/Sources/DataStructuresAlgorithms/DataStructures/DoubleLinkedList.swift
new file mode 100644
index 0000000..96e3fdd
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/DataStructures/DoubleLinkedList.swift
@@ -0,0 +1,122 @@
+import Foundation
+
+public enum MyError: Error {
+ case runtimeError(String)
+}
+
+open class Node: Hashable {
+ var next: Node?
+ var val: T
+ var prev: Node?
+
+ init(val: T, next: Node? = nil, prev: Node? = nil) {
+ self.val = val
+ self.next = next
+ self.prev = prev
+ }
+
+ public static func == (lhs: Node, rhs: Node) -> Bool {
+ return lhs.val == rhs.val && lhs.next == rhs.next && lhs.prev == rhs.prev
+ }
+
+ public func hash(into hasher: inout Hasher) {
+ hasher.combine(val)
+ hasher.combine(next)
+ hasher.combine(prev)
+ }
+}
+
+open class DoubleLinkedList {
+ public var head: Node?
+ public var tail: Node?
+ public var count: Int = 0
+
+ public init() { }
+
+ open func add(node: Node) {
+ if count == 0 {
+ head = node
+ tail = node
+ } else {
+ let temp = tail
+ tail = node
+ temp?.next = tail
+ tail?.prev = temp
+ }
+ count += 1
+ }
+
+ open func removeFirst() throws -> Node? {
+ if count == 0 {
+ throw MyError.runtimeError("Invalid call")
+ }
+
+ let node = head
+
+ if count == 1 {
+ head = nil; tail = nil
+ } else {
+ head = node?.next
+ head?.prev = nil
+ node?.next = nil
+ }
+
+ count -= 1
+
+ return node
+ }
+
+ open func removeLast() throws -> Node? {
+ if count == 0 {
+ throw MyError.runtimeError("Invalid call")
+ }
+
+ let node = tail
+
+ if count == 1 {
+ head = nil; tail = nil
+ } else {
+ tail?.prev?.next = nil
+ tail = tail?.prev
+ }
+
+ count -= 1
+
+ return node
+ }
+
+ open func removeByKey(val: Int) {
+ var current = head
+
+ while current != nil {
+ if let cur = current, let curVal = current?.val as? Int, curVal == val, let headVal = head?.val as? Int, let tailVal = tail?.val as? Int {
+ if count == 1 {
+ head = nil; tail = nil;
+ } else if curVal == headVal {
+ head?.next?.prev = nil
+ head = head?.next
+ } else if curVal == tailVal {
+ tail?.prev?.next = nil
+ tail = tail?.prev
+ } else {
+ if let prev = cur.prev {
+ prev.next = cur.next
+ }
+ if let next = cur.next {
+ next.prev = cur.prev
+ }
+ }
+
+ if headVal == tailVal {
+ head = tail
+ }
+
+ count -= 1
+
+ return
+ }
+
+ current = current?.next
+ }
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/DataStructures/Edge.swift b/SPM/Sources/DataStructuresAlgorithms/DataStructures/Edge.swift
new file mode 100644
index 0000000..779366c
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/DataStructures/Edge.swift
@@ -0,0 +1,35 @@
+//
+// Edge.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 02.04.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+open class Edge: Comparable, Hashable {
+ public let from: Vertice
+ public let to: Vertice
+ public let weight: Int
+
+ public init(from: Vertice, to: Vertice, weight: Int) {
+ self.from = from
+ self.to = to
+ self.weight = weight
+ }
+
+ public static func < (lhs: Edge, rhs: Edge) -> Bool {
+ return lhs.weight < rhs.weight
+ }
+
+ public static func == (lhs: Edge, rhs: Edge) -> Bool {
+ return lhs.from == rhs.from && lhs.to == rhs.to
+ }
+
+ public func hash(into hasher: inout Hasher) {
+ hasher.combine(from)
+ hasher.combine(to)
+ hasher.combine(weight)
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/DataStructures/HashTable.swift b/SPM/Sources/DataStructuresAlgorithms/DataStructures/HashTable.swift
new file mode 100644
index 0000000..98fc3af
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/DataStructures/HashTable.swift
@@ -0,0 +1,53 @@
+//
+// HashTable.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 26.03.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+open class HashTable {
+ private var table: [DoubleLinkedList] = []
+
+ public init(size: Int) {
+ table = [DoubleLinkedList] (repeating: DoubleLinkedList(), count: size)
+ for i in 0 ... size - 1 {
+ table[i] = DoubleLinkedList()
+ }
+ }
+
+ open func hash(val: String) -> Int {
+ var hash: Int = 0
+ var index: Int = 0
+
+ for char in Array(val) {
+ index += 1
+ hash += Int(char.asciiValue!) * index
+ }
+
+ hash %= table.count
+
+ return Int(hash)
+ }
+
+ open func insert(val: String) {
+ let h = hash(val: val)
+ table[h].add(node: Node(val: val))
+ }
+
+ open func contains(val: String) -> Bool {
+ let h = hash(val: val)
+ let list = table[h]
+
+ var curNode = list.head
+ while curNode != nil {
+ if curNode?.val == val {
+ return true
+ }
+ curNode = curNode?.next
+ }
+ return false
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/DataStructures/IndexedMinPriorityQueue.swift b/SPM/Sources/DataStructuresAlgorithms/DataStructures/IndexedMinPriorityQueue.swift
new file mode 100644
index 0000000..d1b65d3
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/DataStructures/IndexedMinPriorityQueue.swift
@@ -0,0 +1,179 @@
+//
+// IndexedMinPriorityQueue.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 15.04.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+open class IndexedMinPriorityQueue {
+ private var keys = [T?]()
+ private var keyIndeces: [Int] //qp
+ private var heapIndeces = [Int]() //pq
+ private var maxElements: Int = 0
+
+ public var size: Int = 0
+
+ public init(maxElements: Int) {
+ keyIndeces = [Int] (repeating: -1, count: maxElements)
+ heapIndeces = [Int] (repeating: Int.max, count: maxElements)
+ keys = [T?] (repeating: nil, count: maxElements)
+ self.maxElements = maxElements
+ }
+
+ open func isEmpty() -> Bool {
+ return size == 0
+ }
+
+ open func contains(index: Int) -> Bool {
+ return keyIndeces[index] != -1
+ }
+
+
+ open func insert(index: Int, key: T) throws {
+ if size >= maxElements {
+ throw NSError(domain: "IndexedMinPriorityQueue: PQ is full", code: 0, userInfo: nil)
+ }
+
+ keys[index] = key
+ keyIndeces[index] = size
+ heapIndeces[size] = index
+
+ swim(index: size)
+ size += 1
+ }
+
+ open func minIndex() throws -> Int {
+ if size < 1 {
+ throw NSError(domain: "IndexedMinPriorityQueue: no elements in PQ", code: 0, userInfo: nil)
+ }
+
+ return heapIndeces[0]
+ }
+
+ open func minKey() throws -> T? {
+ if size < 1 {
+ throw NSError(domain: "IndexedMinPriorityQueue: no elements in PQ", code: 0, userInfo: nil)
+ }
+
+ return keys[heapIndeces[0]]
+ }
+
+ open func extractMin() throws -> T? {
+ let key = try minKey()
+ let index = try minIndex()
+
+ exchange(index1: 0, index2: size - 1)
+ size -= 1
+ sink(index: 0)
+
+ keyIndeces[index] = -1
+ keys[index] = nil
+ heapIndeces[size] = Int.max
+
+ return key
+ }
+
+ open func delete(index: Int) throws {
+ if !contains(index: index) {
+ throw NSError(domain: "IndexedMinPriorityQueue: Element not in queue", code: 0, userInfo: nil)
+ }
+
+ let heapIndex = keyIndeces[index]
+ exchange(index1: heapIndex, index2: size - 1)
+ size -= 1
+ swim(index: heapIndex)
+ sink(index: heapIndex)
+
+ keyIndeces[index] = -1
+ keys[index] = nil
+ heapIndeces[size] = Int.max
+ }
+
+ open func keyOf(index: Int) -> T? {
+ return keys[index]
+ }
+
+ open func changeKey(index: Int, key: T) throws {
+ if !contains(index: index) {
+ throw NSError(domain: "IndexedMinPriorityQueue: Element not in queue", code: 0, userInfo: nil)
+ }
+
+ keys[index] = key
+ sink(index: keyIndeces[index])
+ swim(index: keyIndeces[index])
+ }
+
+ open func decreaseKey(index: Int, key: T) throws {
+ if !contains(index: index) {
+ throw NSError(domain: "IndexedMinPriorityQueue: Element not in queue", code: 0, userInfo: nil)
+ }
+
+ if let currentKey = keys[index], currentKey < key {
+ throw NSError(domain: "IndexedMinPriorityQueue: Called decreaseKey with increased or equal value", code: 0, userInfo: nil)
+ }
+
+ keys[index] = key
+ swim(index: keyIndeces[index])
+ }
+
+ open func increaseKey(index: Int, key: T) throws {
+ if !contains(index: index) {
+ throw NSError(domain: "IndexedMinPriorityQueue: Element not in queue", code: 0, userInfo: nil)
+ }
+
+ if let currentKey = keys[index], currentKey > key {
+ throw NSError(domain: "IndexedMinPriorityQueue: Called increaseKey with decreased or equal value", code: 0, userInfo: nil)
+ }
+
+ keys[index] = key
+ sink(index: keyIndeces[index])
+ }
+
+ private func greater(_ i: Int?, _ j: Int?) -> Bool {
+ guard let i = i, let j = j, i >= 0, i < size, j >= 0, j < size,
+ heapIndeces[i] < keys.count, heapIndeces[j] < keys.count,
+ heapIndeces[i] >= 0, heapIndeces[j] >= 0,
+ let key1 = keys[heapIndeces[i]], let key2 = keys[heapIndeces[j]] else {
+ return false
+ }
+
+ return key1 > key2
+ }
+
+ private func swim(index: Int) {
+ if greater((index - 1) / 2, index) {
+ exchange(index1: index, index2: ((index - 1) / 2))
+ swim(index: (index - 1) / 2)
+ }
+ }
+
+ private func sink(index: Int) {
+ let key1Index = 2 * index + 1
+ let key2Index = 2 * index + 2
+
+ if greater(index, key1Index) || greater(index, key2Index) {
+ if greater(key1Index, key2Index) {
+ exchange(index1: index, index2: key2Index)
+ sink(index: key2Index)
+ } else {
+ exchange(index1: index, index2: key1Index)
+ sink(index: key1Index)
+ }
+ } else if greater(index, key1Index) {
+ exchange(index1: index, index2: key1Index)
+ sink(index: key1Index)
+ }
+ }
+
+ private func exchange(index1: Int, index2: Int) {
+ let temp = heapIndeces[index1]
+ heapIndeces[index1] = heapIndeces[index2]
+ heapIndeces[index2] = temp
+
+ keyIndeces[heapIndeces[index1]] = index1
+ keyIndeces[heapIndeces[index2]] = index2
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/DataStructures/IntervalTree.swift b/SPM/Sources/DataStructuresAlgorithms/DataStructures/IntervalTree.swift
new file mode 100644
index 0000000..8489248
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/DataStructures/IntervalTree.swift
@@ -0,0 +1,315 @@
+//
+// IntervalTree.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 19.04.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+public struct Interval {
+ var low: T
+ var high: T
+
+ static func == (lhs: Interval, rhs: Interval) -> Bool {
+ return lhs.low == rhs.low && lhs.high == rhs.high
+ }
+
+ static func < (lhs: Interval, rhs: Interval) -> Bool {
+ return lhs.low < rhs.low
+ }
+
+ static func > (lhs: Interval, rhs: Interval) -> Bool {
+ return lhs.low > rhs.low
+ }
+}
+
+open class IntervalNode {
+ public var interval: Interval
+ public var minMaxInterval: Interval
+ public var left: IntervalNode?
+ public var right: IntervalNode?
+ public var parent: IntervalNode?
+ public var height: Int
+
+ init(parent: IntervalNode? = nil, interval: Interval, height: Int) {
+ self.parent = parent
+ self.interval = interval
+ minMaxInterval = interval
+ self.height = height
+ }
+}
+
+open class IntervalTree {
+ public var root: IntervalNode?
+
+ public init(root: IntervalNode) {
+ self.root = root
+ }
+
+ open func overlapsInterval(interval: Interval) -> Interval? {
+ guard let root = root else {
+ return nil
+ }
+
+ return overlapsInterval(interval: interval, node: root)
+ }
+
+ private func overlapsInterval(interval: Interval, node: IntervalNode) -> Interval? {
+ if interval.low < node.interval.high && interval.high >= node.interval.high //interval overlaps right
+ || interval.low <= node.interval.low && interval.high > node.interval.low //interval overlaps left
+ || interval.low >= node.interval.low && interval.high <= node.interval.high //interval inside
+ || interval.low <= node.interval.low && interval.high >= node.interval.high //interval completely overlaps
+ {
+ return node.interval //overlaps
+ }
+
+ if let leftChild = node.left, leftChild.minMaxInterval.high > interval.low, leftChild.minMaxInterval.low < node.minMaxInterval.high {
+ return overlapsInterval(interval: interval, node: leftChild)
+ }
+
+ if let rightChild = node.right, rightChild.minMaxInterval.high > interval.low, rightChild.minMaxInterval.low < interval.high {
+ return overlapsInterval(interval: interval, node: rightChild)
+ }
+
+ return nil
+ }
+
+ open func insert(interval: Interval) {
+ if root == nil {
+ root = IntervalNode(parent: nil, interval: interval, height: 1)
+ return
+ }
+
+ var current = root
+ while current != nil, let cur = current {
+ if cur.interval > interval {
+ if cur.left == nil {
+ cur.left = IntervalNode(parent: cur, interval: interval, height: 1)
+ increaseHeightAndSetIntervals(cur)
+ return
+ } else {
+ current = cur.left
+ }
+ } else {
+ if cur.right == nil {
+ cur.right = IntervalNode(parent: cur, interval: interval, height: 1)
+ increaseHeightAndSetIntervals(cur)
+ return
+ } else {
+ current = cur.right
+ }
+ }
+ }
+ }
+
+ private func increaseHeightAndSetIntervals(_ node: IntervalNode) {
+ if node.left != nil, node.right != nil {
+ return //must be balanced
+ }
+
+ var current: IntervalNode? = node
+ while current != nil, let cur = current {
+ let leftHeight = cur.left?.height ?? 0
+ let rightHeight = cur.right?.height ?? 0
+
+ cur.height = max(leftHeight, rightHeight) + 1
+
+ let leftInterval = cur.left?.minMaxInterval ?? nil
+ let rightInterval = cur.right?.minMaxInterval ?? nil
+
+ if let interval = leftInterval {
+ cur.minMaxInterval.low = min(cur.minMaxInterval.low, interval.low)
+ cur.minMaxInterval.high = max(cur.minMaxInterval.high, interval.high)
+ }
+
+ if let interval = rightInterval {
+ cur.minMaxInterval.low = min(cur.minMaxInterval.low, interval.low)
+ cur.minMaxInterval.high = max(cur.minMaxInterval.high, interval.high)
+ }
+
+ let heightDiff = leftHeight - rightHeight
+
+ if heightDiff == 0 {
+ return
+ } else if heightDiff == -2 {
+ let rightLeftHeight = cur.right?.left?.height ?? 0
+ let rightRightHeight = cur.right?.right?.height ?? 0
+
+ if rightLeftHeight > rightRightHeight {
+ //right left shape -> left + right rotation
+ let nodeToRotate = cur.right?.left
+ rightRotate(n: nodeToRotate)
+ leftRotate(n: nodeToRotate)
+ } else {
+ //right right shape -> right rotation
+ leftRotate(n: cur.right)
+ }
+ current = cur.parent
+ } else if heightDiff == 2 {
+ let leftLeftHeight = cur.left?.left?.height ?? 0
+ let leftRightHeight = cur.left?.right?.height ?? 0
+
+ if leftRightHeight > leftLeftHeight {
+ //left right shape -> left + right rotation
+ let nodeToRotate = cur.left?.right
+ leftRotate(n: nodeToRotate)
+ rightRotate(n: nodeToRotate)
+ } else {
+ //left left shape -> right rotation
+ rightRotate(n: cur.left)
+ }
+ current = cur.parent
+ } else {
+ current = cur.parent
+ }
+ }
+ }
+
+ open func description() -> Stack {
+ var stack = Stack()
+ description(node: root, stack: &stack)
+
+ return stack
+ }
+
+ private func description(node: IntervalNode?, stack: inout Stack) {
+ if let node = node {
+ stack.push(val: "Low/High: \(node.interval.low)-\(node.interval.high), Min/Max: \(node.minMaxInterval.low)-\(node.minMaxInterval.high), Height: \(node.height)")
+
+ description(node: node.left, stack: &stack)
+ description(node: node.right, stack: &stack)
+ }
+ }
+
+ private func rightRotate(n: IntervalNode?) {
+ let p = n?.parent
+ let gp = p?.parent
+ let gpLeft = p?.interval.low == gp?.left?.interval.low && p?.interval.high == gp?.left?.interval.high
+
+ p?.left = n?.right
+ p?.left?.parent = p
+
+ n?.right = p;
+ p?.parent = n // p? = n?.right
+
+ n?.parent = gp
+ if gpLeft {
+ gp?.left = n
+ } else {
+ gp?.right = n
+ }
+
+ if gp == nil {
+ root = n
+ }
+
+ let pLeftHeight = p?.left?.height ?? 0
+ let pRightHeight = p?.right?.height ?? 0
+ p?.height = max(pLeftHeight, pRightHeight) + 1
+
+ let pLeftInterval = p?.left?.minMaxInterval ?? nil
+ let pRightInterval = p?.right?.minMaxInterval ?? nil
+
+ if let p = p {
+ p.minMaxInterval = p.interval
+
+ if let interval = pLeftInterval {
+ p.minMaxInterval.low = min(p.minMaxInterval.low, interval.low)
+ p.minMaxInterval.high = max(p.minMaxInterval.high, interval.high)
+ }
+
+ if let interval = pRightInterval {
+ p.minMaxInterval.low = min(p.minMaxInterval.low, interval.low)
+ p.minMaxInterval.high = max(p.minMaxInterval.high, interval.high)
+ }
+ }
+
+ let nLeftHeight = n?.left?.height ?? 0
+ let nRightHeight = n?.right?.height ?? 0
+ n?.height = max(nLeftHeight, nRightHeight) + 1
+
+ let nLeftInterval = n?.left?.minMaxInterval ?? nil
+ let nRightInterval = n?.right?.minMaxInterval ?? nil
+
+ if let n = n {
+ n.minMaxInterval = n.interval
+
+ if let interval = nLeftInterval {
+ n.minMaxInterval.low = min(n.minMaxInterval.low, interval.low)
+ n.minMaxInterval.high = max(n.minMaxInterval.high, interval.high)
+ }
+
+ if let interval = nRightInterval {
+ n.minMaxInterval.low = min(n.minMaxInterval.low, interval.low)
+ n.minMaxInterval.high = max(n.minMaxInterval.high, interval.high)
+ }
+ }
+ }
+
+ private func leftRotate(n: IntervalNode?) {
+ let p = n?.parent
+ let gp = p?.parent
+ let gpLeft = p?.interval.low == gp?.left?.interval.low && p?.interval.high == gp?.left?.interval.high
+
+ p?.right = n?.left
+ p?.right?.parent = p
+
+ n?.left = p
+ p?.parent = n
+
+ n?.parent = gp
+ if gpLeft {
+ gp?.left = n
+ } else {
+ gp?.right = n
+ }
+
+ if gp == nil {
+ root = n
+ }
+
+ let pLeftHeight = p?.left?.height ?? 0
+ let pRightHeight = p?.right?.height ?? 0
+ p?.height = max(pLeftHeight, pRightHeight) + 1
+
+ let pLeftInterval = p?.left?.minMaxInterval ?? nil
+ let pRightInterval = p?.right?.minMaxInterval ?? nil
+
+ if let p = p {
+ p.minMaxInterval = p.interval
+
+ if let interval = pLeftInterval {
+ p.minMaxInterval.low = min(p.minMaxInterval.low, interval.low)
+ p.minMaxInterval.high = max(p.minMaxInterval.high, interval.high)
+ }
+
+ if let interval = pRightInterval {
+ p.minMaxInterval.low = min(p.minMaxInterval.low, interval.low)
+ p.minMaxInterval.high = max(p.minMaxInterval.high, interval.high)
+ }
+ }
+
+ let nLeftHeight = n?.left?.height ?? 0
+ let nRightHeight = n?.right?.height ?? 0
+ n?.height = max(nLeftHeight, nRightHeight) + 1
+
+ let nLeftInterval = n?.left?.minMaxInterval ?? nil
+ let nRightInterval = n?.right?.minMaxInterval ?? nil
+
+ if let n = n {
+ n.minMaxInterval = n.interval
+
+ if let interval = nLeftInterval {
+ n.minMaxInterval.low = min(n.minMaxInterval.low, interval.low)
+ n.minMaxInterval.high = max(n.minMaxInterval.high, interval.high)
+ }
+
+ if let interval = nRightInterval {
+ n.minMaxInterval.low = min(n.minMaxInterval.low, interval.low)
+ n.minMaxInterval.high = max(n.minMaxInterval.high, interval.high)
+ }
+ }
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/DataStructures/LRUCache.swift b/SPM/Sources/DataStructuresAlgorithms/DataStructures/LRUCache.swift
new file mode 100644
index 0000000..3dec361
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/DataStructures/LRUCache.swift
@@ -0,0 +1,100 @@
+//
+// LRUCache.swift
+//
+//
+// Created by Stefan Jaindl on 01.12.20.
+//
+
+import Foundation
+
+open class LRUCache {
+
+ private let cacheSize: Int
+ private var currentCount = 0
+ private var cache = DoubleLinkedList()
+ private var lookup = [T: Node]()
+
+ public init(cacheSize: Int) {
+ self.cacheSize = cacheSize
+ }
+
+ open func insert(_ value: T) {
+ if let node = get(value) {
+ node.val = value
+
+ //Promote node to top of cache
+ guard node != cache.tail else {
+ return //already at top of cache
+ }
+
+ promote(node: node)
+
+ return
+ }
+
+ if isFull() {
+ removeHead()
+ }
+
+ updateCache(with: Node(val: value))
+ currentCount += 1
+ }
+
+ open func get(_ value: T) -> Node? {
+ guard let node = lookup[value] else {
+ return nil
+ }
+
+ promote(node: node)
+
+ return node
+ }
+
+ private func promote(node: Node) {
+ let nextNode = node.next
+ node.prev?.next = nextNode
+ nextNode?.prev = node.prev
+
+ node.next = nil
+ node.prev = cache.tail
+ cache.tail?.next = node
+
+ cache.tail = node
+ }
+
+ private func removeHead() {
+ guard let node = cache.head else {
+ return
+ }
+
+ lookup.removeValue(forKey: node.val)
+
+ let newHead = cache.head?.next
+ newHead?.prev = nil
+ cache.head?.next = nil
+ cache.head = newHead
+
+ currentCount -= 1
+ }
+
+ private func updateCache(with node: Node) {
+ if currentCount == 0 {
+ cache.head = node
+ cache.tail = node
+ } else if currentCount == 1 {
+ cache.tail = node
+ node.prev = cache.head
+ cache.head?.next = node
+ } else {
+ cache.tail?.next = node
+ node.prev = cache.tail
+ cache.tail = node
+ }
+
+ lookup[node.val] = node
+ }
+
+ private func isFull() -> Bool {
+ return currentCount == cacheSize
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/DataStructures/MaxHeap.swift b/SPM/Sources/DataStructuresAlgorithms/DataStructures/MaxHeap.swift
new file mode 100644
index 0000000..4ec944d
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/DataStructures/MaxHeap.swift
@@ -0,0 +1,78 @@
+//
+// MaxHeap.swift
+//
+//
+// Created by Stefan Jaindl on 11.12.20.
+//
+
+import Foundation
+
+open class MaxHeap {
+ private var array = [T] ()
+
+ public init() { }
+
+ open func insert(val: T) {
+ array.append(val)
+ swim(key: array.count - 1)
+ }
+
+ open func peekMax() throws -> T {
+ if array.count < 1 {
+ throw NSError(domain: "Heap: no elements in heap", code: 0, userInfo: nil)
+ }
+
+ return array[0]
+ }
+
+ @discardableResult
+ open func extractMax() throws -> T {
+ let max = try peekMax()
+ array[0] = array[array.count - 1]
+ array.removeLast()
+ sink(key: 0)
+
+ return max
+ }
+
+ open func isEmpty() -> Bool {
+ return array.isEmpty
+ }
+
+ open func numberOfElements() -> Int {
+ return array.count
+ }
+
+ private func swim(key: Int) {
+ if array[key] > array[(key-1) / 2] {
+ exchange(index1: key, index2: ((key - 1) / 2))
+ swim(key: (key - 1) / 2)
+ }
+ }
+
+ private func sink(key: Int) {
+ let key1Index = 2 * key + 1
+ let key2Index = 2 * key + 2
+
+ if array.count - 1 >= key2Index &&
+ array[key] < max(array[key1Index], array[key2Index]) {
+ if array[key1Index] < array[key2Index] {
+ exchange(index1: key, index2: key2Index)
+ sink(key: key2Index)
+ } else {
+ exchange(index1: key, index2: key1Index)
+ sink(key: key1Index)
+ }
+ } else if array.count - 1 >= key1Index &&
+ array[key] < array[key1Index] {
+ exchange(index1: key, index2: key1Index)
+ sink(key: key1Index)
+ }
+ }
+
+ private func exchange(index1: Int, index2: Int) {
+ let temp = array[index1]
+ array[index1] = array[index2]
+ array[index2] = temp
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/DataStructures/MinHeap.swift b/SPM/Sources/DataStructuresAlgorithms/DataStructures/MinHeap.swift
new file mode 100644
index 0000000..d84e7c5
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/DataStructures/MinHeap.swift
@@ -0,0 +1,79 @@
+//
+// MinHeap.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 25.03.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+open class MinHeap {
+ private var array = [T] ()
+
+ public init() { }
+
+ open func insert(val: T) {
+ array.append(val)
+ swim(key: array.count - 1)
+ }
+
+ open func peekMin() throws -> T {
+ if array.count < 1 {
+ throw NSError(domain: "Heap: no elements in heap", code: 0, userInfo: nil)
+ }
+
+ return array[0]
+ }
+
+ @discardableResult
+ open func extractMin() throws -> T {
+ let min = try peekMin()
+ array[0] = array[array.count - 1]
+ array.removeLast()
+ sink(key: 0)
+
+ return min
+ }
+
+ open func isEmpty() -> Bool {
+ return array.isEmpty
+ }
+
+ open func numberOfElements() -> Int {
+ return array.count
+ }
+
+ private func swim(key: Int) {
+ if array[key] < array[(key-1) / 2] {
+ exchange(index1: key, index2: ((key - 1) / 2))
+ swim(key: (key - 1) / 2)
+ }
+ }
+
+ private func sink(key: Int) {
+ let key1Index = 2 * key + 1
+ let key2Index = 2 * key + 2
+
+ if array.count - 1 >= key2Index &&
+ array[key] > min(array[key1Index], array[key2Index]) {
+ if array[key1Index] > array[key2Index] {
+ exchange(index1: key, index2: key2Index)
+ sink(key: key2Index)
+ } else {
+ exchange(index1: key, index2: key1Index)
+ sink(key: key1Index)
+ }
+ } else if array.count - 1 >= key1Index &&
+ array[key] > array[key1Index] {
+ exchange(index1: key, index2: key1Index)
+ sink(key: key1Index)
+ }
+ }
+
+ private func exchange(index1: Int, index2: Int) {
+ let temp = array[index1]
+ array[index1] = array[index2]
+ array[index2] = temp
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/DataStructures/Queue.swift b/SPM/Sources/DataStructuresAlgorithms/DataStructures/Queue.swift
new file mode 100644
index 0000000..4e50b87
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/DataStructures/Queue.swift
@@ -0,0 +1,77 @@
+//
+// Queue.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 23.03.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+open class Queue {
+ private var items: [Node?]
+ private var capacity: Int = 10
+ private var nextPos: Int = 0
+ private var frontPos: Int = 0
+ public var size: Int = 0
+
+ public init() {
+ items = [Node?](repeating: nil, count: capacity)
+ }
+
+ open func enqueue(val: T) {
+ if size == items.count {
+ resizeArray(newSize: size * 2)
+ }
+
+ if nextPos == items.count {
+ rebuildArray()
+ }
+
+ let node = Node(val: val)
+ items[nextPos] = node
+ size += 1
+ nextPos += 1
+ }
+
+ open func dequeue() throws -> T {
+ if size == 0 {
+ throw NSError(domain: "No element in queue", code: 0, userInfo: nil)
+ }
+
+ if items.count < size / 4 {
+ resizeArray(newSize: size / 4)
+ }
+
+ let item = items[frontPos]
+ frontPos += 1
+ size -= 1
+
+ return item!.val
+ }
+
+ open func isEmpty() -> Bool {
+ return size == 0
+ }
+
+ private func rebuildArray() {
+ var newArr = [Node?] (repeating: nil, count: items.count)
+ for n in frontPos ... nextPos {
+ newArr.append(items[n])
+ }
+ items = newArr
+ nextPos -= frontPos
+ frontPos = 0
+ }
+
+ private func resizeArray(newSize: Int) {
+ var newArr = [Node?] (repeating: nil, count: newSize)
+ for n in frontPos ... nextPos {
+ newArr.append(items[n])
+ }
+ items = newArr
+ nextPos -= frontPos
+ frontPos = 0
+ size = newSize
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/DataStructures/RedBlackTree.swift b/SPM/Sources/DataStructuresAlgorithms/DataStructures/RedBlackTree.swift
new file mode 100644
index 0000000..8dff5fd
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/DataStructures/RedBlackTree.swift
@@ -0,0 +1,159 @@
+import Foundation
+
+open class RedBlackTreeNode {
+
+ public enum TreeColor {
+ case red
+ case black
+ }
+
+ public var left: RedBlackTreeNode?
+ public var right: RedBlackTreeNode?
+ public var parent: RedBlackTreeNode?
+ public var value: T
+ public var color = TreeColor.red
+
+ public init(parent: RedBlackTreeNode?, value: T) {
+ self.parent = parent
+ self.value = value
+ }
+
+ open func isRoot() -> Bool {
+ return parent == nil
+ }
+
+ open func uncle() -> RedBlackTreeNode? {
+ if let left = parent?.parent?.left, left.value == parent?.value {
+ return parent?.parent?.right
+ }
+ return parent?.parent?.left
+ }
+}
+
+extension RedBlackTreeNode : Equatable {
+ public static func == (lhs: RedBlackTreeNode, rhs: RedBlackTreeNode) -> Bool {
+ return lhs.value == rhs.value
+ }
+}
+
+open class RedBlackTree {
+ public var root: RedBlackTreeNode?
+ public var count = 0
+
+ public init() { }
+
+ open func insert(value: T) {
+ if root == nil {
+ root = RedBlackTreeNode(parent: nil, value: value)
+ root?.color = .black
+ return
+ }
+
+ count += 1
+
+ let node = bstInsert(value: value)
+
+ if node.parent?.color == .black {
+ return //everything ok, no double red violation
+ }
+
+ //else: Double red violation!
+
+ if let uncle = node.uncle(), uncle.color == .red {
+ //try to recolor: parent and uncle are both red!
+ recolor(node: node)
+ } else {
+ let nIsLeft = node.parent?.left == node
+ let pIsLeft = node.parent?.parent?.left == node.parent
+
+ if nIsLeft && pIsLeft {
+ rightRotate(n: node.parent)
+ } else if !nIsLeft && pIsLeft {
+ leftRotate(n: node)
+ rightRotate(n: node)
+ } else if nIsLeft && !pIsLeft {
+ leftRotate(n: node)
+ } else { //both right
+ leftRotate(n: node.parent)
+ }
+ }
+ }
+
+ private func bstInsert(value: T) -> RedBlackTreeNode { //assumption: no equal value nodes, root exists
+ var curNode = root
+
+ while true {
+ if curNode!.value > value {
+ if curNode?.left != nil {
+ curNode = curNode?.left
+ } else {
+ curNode?.left = RedBlackTreeNode(parent: curNode, value: value)
+ curNode = curNode?.left
+ break
+ }
+ } else {
+ if curNode?.right != nil {
+ curNode = curNode?.right
+ } else {
+ curNode?.right = RedBlackTreeNode(parent: curNode, value: value)
+ curNode = curNode?.right
+ break
+ }
+ }
+ }
+
+ return curNode!
+ }
+
+ private func recolor(node: RedBlackTreeNode?) {
+ guard node != nil else {
+ return
+ }
+
+ let p = node?.parent
+ let u = node?.uncle()
+ let g = p?.parent
+
+ p?.color = .black
+ u?.color = .black
+ g?.color = .red
+
+ if g?.parent == nil {
+ g?.color = .black //paint root always black
+ }
+
+ recolor(node: g)
+ }
+
+ private func rightRotate(n: RedBlackTreeNode?) {
+ let p = n?.parent
+ p?.left = n?.right
+ p?.left?.parent = p
+
+ n?.right = p
+ n?.parent = p?.parent
+ p?.parent = n
+ if n?.parent == nil {
+ root = n
+ }
+
+ p?.color = .red
+ n?.color = .black
+ }
+
+ private func leftRotate(n: RedBlackTreeNode?) {
+ let p = n?.parent
+ p?.right = n?.left
+ p?.right?.parent = p
+
+ n?.left = p
+ n?.parent = p?.parent
+ p?.parent = n
+ if n?.parent == nil {
+ root = n
+ }
+
+ n?.color = .black
+ p?.color = .red
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/DataStructures/SingleLinkedList.swift b/SPM/Sources/DataStructuresAlgorithms/DataStructures/SingleLinkedList.swift
new file mode 100644
index 0000000..26906b3
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/DataStructures/SingleLinkedList.swift
@@ -0,0 +1,67 @@
+import Foundation
+
+open class SingleNode {
+ var next: SingleNode?
+ var val: T
+
+ init(val: T, next: SingleNode? = nil) {
+ self.val = val
+ self.next = next
+ }
+}
+
+open class SingleLinkedList {
+ public var head: SingleNode?
+ public var count: Int = 0
+
+ public init() { }
+
+ open func add(node: SingleNode) {
+ if count == 0 {
+ head = node
+ } else {
+ var current = head
+ while current?.next != nil {
+ current = current?.next
+ }
+ current?.next = node
+ }
+
+ count += 1
+ }
+
+ open func prepend(node: SingleNode) {
+ node.next = head
+ head = node
+
+ count += 1
+ }
+
+ open func removeLast() throws -> SingleNode? {
+ if count == 0 {
+ throw MyError.runtimeError("Invalid call")
+ }
+
+ var node: SingleNode?
+ if count == 1 {
+ node = head
+ head = nil
+ } else {
+ var current = head
+ while current?.next != nil {
+ node = current
+ current = current?.next
+ }
+ node?.next = nil
+ node = current
+ }
+
+ count -= 1
+
+ return node
+ }
+
+ open func isEmpty() -> Bool {
+ return count == 0
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/DataStructures/Stack.swift b/SPM/Sources/DataStructuresAlgorithms/DataStructures/Stack.swift
new file mode 100644
index 0000000..0299996
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/DataStructures/Stack.swift
@@ -0,0 +1,42 @@
+//
+// Stack.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 23.03.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+open class Stack {
+ public var head: Node?
+ public var size: Int = 0
+
+ open func push(val: T) {
+ let newHead = Node(val: val, next: head)
+ head = newHead
+ size += 1
+ }
+
+ open func pop() throws -> T {
+ guard let node = head else {
+ throw NSError(domain: "Stack: Invalid call", code: 0, userInfo: nil)
+ }
+
+ head = node.next
+ size -= 1
+ return node.val
+ }
+
+ open func peek() throws -> T {
+ guard let node = head else {
+ throw NSError(domain: "Stack: Invalid call", code: 0, userInfo: nil)
+ }
+
+ return node.val
+ }
+
+ open func isEmpty() -> Bool {
+ return size == 0
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/DataStructures/TreeNodes.swift b/SPM/Sources/DataStructuresAlgorithms/DataStructures/TreeNodes.swift
new file mode 100644
index 0000000..3e4b661
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/DataStructures/TreeNodes.swift
@@ -0,0 +1,55 @@
+//
+// SimpleTreeNode.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 23.06.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+open class SimpleTreeNode {
+
+ public var left: SimpleTreeNode?
+ public var right: SimpleTreeNode?
+ public var value: T
+ public var numElements = 0
+
+ public init(value: T) {
+ self.value = value
+ }
+
+ public init(value: T, numElements: Int) {
+ self.value = value
+ self.numElements = numElements
+ }
+
+ public func isLeaveNode() -> Bool {
+ return left == nil && right == nil
+ }
+}
+
+open class TreeNode: Equatable {
+
+ public var left: TreeNode?
+ public var right: TreeNode?
+ public var parent: TreeNode?
+ public var value: T
+
+ public init(value: T) {
+ self.value = value
+ }
+
+ public init(value: T, parent: TreeNode?) {
+ self.value = value
+ self.parent = parent
+ }
+
+ public static func == (lhs: TreeNode, rhs: TreeNode) -> Bool {
+ return lhs.value == rhs.value
+ }
+
+ public func isLeaveNode() -> Bool {
+ return left == nil && right == nil
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/DataStructures/Trie.swift b/SPM/Sources/DataStructuresAlgorithms/DataStructures/Trie.swift
new file mode 100644
index 0000000..a46cc16
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/DataStructures/Trie.swift
@@ -0,0 +1,64 @@
+import Foundation
+
+open class TrieNode {
+ public let value: Character
+ public var terminates: Bool
+ public var childNodes: Dictionary = Dictionary()
+
+ public init(value: Character, terminates: Bool = false) {
+ self.value = value
+ self.terminates = terminates
+ }
+}
+
+open class Trie {
+ public let root: TrieNode = TrieNode(value: " ")
+
+ public init() { }
+
+ open func insert(word: String) {
+ insert(word: Array(word), node: root)
+ }
+
+ private func insert(word: [Character], node: TrieNode) {
+ if word.isEmpty {
+ return
+ }
+
+ var nextNode: TrieNode
+ if let nextChildNode = node.childNodes[word[0]] {
+ nextNode = nextChildNode
+ } else {
+ nextNode = TrieNode(value: word[0])
+ node.childNodes[word[0]] = nextNode
+ }
+
+ if word.count == 1 {
+ nextNode.terminates = true
+ } else {
+ let slice = word[1...]
+ insert(word: Array(slice), node: nextNode)
+ }
+ }
+
+ open func search(word: String) -> Bool {
+ var curNode: TrieNode? = root
+
+ var chars = Array(word)
+
+ if chars.count < 1 {
+ return false
+ }
+
+ while curNode != nil && chars.count > 0 {
+ let char = chars[0]
+ curNode = curNode?.childNodes[char]
+ chars = Array(chars[1...])
+ if chars.isEmpty, let curNode = curNode, curNode.terminates {
+ return true
+ }
+ }
+
+ return false
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/DataStructures/UndirectedGraph.swift b/SPM/Sources/DataStructuresAlgorithms/DataStructures/UndirectedGraph.swift
new file mode 100644
index 0000000..b9a703b
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/DataStructures/UndirectedGraph.swift
@@ -0,0 +1,31 @@
+//
+// UndirectedGraph.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 27.03.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+open class UndirectedGraph {
+ public let vertices: [Vertice]
+ private var adjList: [DoubleLinkedList] = []
+
+ public init(vertices: [Vertice]) {
+ self.vertices = vertices
+
+ for _ in vertices {
+ adjList.append(DoubleLinkedList())
+ }
+ }
+
+ open func addEdge(v1: Vertice, v2: Vertice) {
+ adjList[v1.id].add(node: Node(val: v2))
+ adjList[v2.id].add(node: Node(val: v1))
+ }
+
+ open func neighbours(v: Vertice) -> DoubleLinkedList {
+ return adjList[v.id]
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/DataStructures/UndirectedGraphWithAdjMatrix.swift b/SPM/Sources/DataStructuresAlgorithms/DataStructures/UndirectedGraphWithAdjMatrix.swift
new file mode 100644
index 0000000..5c6c9ea
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/DataStructures/UndirectedGraphWithAdjMatrix.swift
@@ -0,0 +1,28 @@
+//
+// UndirectedGraphWithAdjMatrix.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 27.04.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+open class WeightedUndirectedGraphWithAdjMatrix {
+ public let vertices: [Vertice]
+ public var adjMatrix: [[Int]]
+
+ public init(vertices: [Vertice]) {
+ self.vertices = vertices
+ adjMatrix = [[Int]] (repeating: [Int] (repeating: Int.max, count: vertices.count), count: vertices.count)
+ }
+
+ open func addEdge(v1: Vertice, v2: Vertice, weight: Int) {
+ adjMatrix[v1.id][v2.id] = weight
+ adjMatrix[v2.id][v1.id] = weight
+ }
+
+ open func neighbours(v: Vertice) -> [Int] {
+ return adjMatrix[v.id]
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/DataStructures/UnionFind.swift b/SPM/Sources/DataStructuresAlgorithms/DataStructures/UnionFind.swift
new file mode 100644
index 0000000..5d0314b
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/DataStructures/UnionFind.swift
@@ -0,0 +1,65 @@
+//
+// UnionFind.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 12.04.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+public struct UnionFindElement {
+ public var parent: Int
+ public var size: Int
+}
+
+open class UnionFind {
+ //union find with path compression and rank by size
+ private var components: [UnionFindElement]
+ private(set) var numberOfComponents: Int
+
+ public init(numberOfElements: Int) {
+ components = [UnionFindElement] (repeating: UnionFindElement(parent: -1, size: 0), count: numberOfElements)
+ numberOfComponents = numberOfElements
+ }
+
+ public convenience init(graph: WeightedUndirectedGraph) {
+ self.init(numberOfElements: graph.vertices.count)
+
+ for vertice in graph.vertices {
+ components[vertice.id] = UnionFindElement(parent: vertice.id, size: 1)
+ }
+ }
+
+ open func find(index: Int) -> Int {
+ if components[index].parent != index {
+ //path compression
+ components[index].parent = find(index: components[index].parent)
+ }
+
+ return components[index].parent
+ }
+
+ open func union(firstIndex: Int, secondIndex: Int) {
+ let firstElement = find(index: firstIndex)
+ let secondElement = find(index: secondIndex)
+
+ if firstElement == secondElement {
+ //cycle detected!
+ //throw NSError(domain: "UnionFind - Cycle detected!", code: 0, userInfo: nil)
+ } else {
+ //weight by rank (size)
+ if components[firstElement].size > components[secondElement].size {
+ components[secondElement].parent = firstElement
+ } else if components[firstElement].size < components[secondElement].size {
+ components[firstElement].parent = secondElement
+ } else {
+ components[secondElement].parent = firstElement
+ components[firstElement].size += 1
+ }
+
+ numberOfComponents -= 1
+ }
+ }
+
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/DataStructures/Vertice.swift b/SPM/Sources/DataStructuresAlgorithms/DataStructures/Vertice.swift
new file mode 100644
index 0000000..e4e53d5
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/DataStructures/Vertice.swift
@@ -0,0 +1,53 @@
+//
+// Vertice.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 01.04.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+open class Vertice: NSObject, Comparable {
+
+ public static func < (lhs: Vertice, rhs: Vertice) -> Bool {
+ return lhs.distanceTo < rhs.distanceTo
+ }
+
+ static func == (lhs: Vertice, rhs: Vertice) -> Bool {
+ return lhs.id == rhs.id
+ }
+
+ public var id: Int
+
+ public var name: String
+
+ //Needed for topological sort:
+ public var inboundCount: Int = 0
+
+ //Needed for Djikstra + Prim's MST (weight):
+ public var distanceTo: Int = 0
+
+ //Needed for Prim's MST:
+ public var minIngoingEdge: Edge?
+
+ public var weight: Int {
+ get {
+ return distanceTo
+ }
+ set (weight) {
+ distanceTo = weight
+ }
+ }
+
+ public var visited: Bool = false
+
+ public init(id: Int, name: String = "") {
+ self.id = id
+ self.name = name
+ }
+
+// public override static func == (lhs: Vertice, rhs: Vertice) -> Bool {
+// return lhs.id == rhs.id
+// }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/DataStructures/WeightedDirectedGraph.swift b/SPM/Sources/DataStructuresAlgorithms/DataStructures/WeightedDirectedGraph.swift
new file mode 100644
index 0000000..f23551e
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/DataStructures/WeightedDirectedGraph.swift
@@ -0,0 +1,44 @@
+//
+// WeightedDirectedGraph.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 02.04.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+open class WeightedDirectedGraph {
+ public let vertices: [Vertice]
+ private var adjList: [DoubleLinkedList] = []
+
+ public init(vertices: [Vertice]) {
+ self.vertices = vertices
+
+ for _ in vertices {
+ adjList.append(DoubleLinkedList())
+ }
+ }
+
+ open func addEdge(v1: Vertice, v2: Vertice, weight: Int) {
+ let edge = Edge(from: v1, to: v2, weight: weight)
+ adjList[v1.id].add(node: Node(val: edge))
+ }
+
+ open func neighbours(v: Vertice) -> DoubleLinkedList {
+ return adjList[v.id]
+ }
+
+ open func edges() -> [Edge] {
+ var edges: [Edge] = []
+ for edgeList in adjList {
+ var current = edgeList.head
+ while let cur = current {
+ edges.append(cur.val)
+ current = cur.next
+ }
+ }
+
+ return edges
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/DataStructures/WeightedDirectedGraphWithAjdMatrix.swift b/SPM/Sources/DataStructuresAlgorithms/DataStructures/WeightedDirectedGraphWithAjdMatrix.swift
new file mode 100644
index 0000000..d151425
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/DataStructures/WeightedDirectedGraphWithAjdMatrix.swift
@@ -0,0 +1,28 @@
+//
+// WeightedDirectedGraphWithAjdMatrix.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 11.04.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+open class WeightedDirectedGraphWithAdjMatrix {
+ public let vertices: [Vertice]
+ public var adjMatrix: [[Int]]
+
+ public init(vertices: [Vertice]) {
+ self.vertices = vertices
+
+ adjMatrix = Array(repeating: Array(repeating: Int.max, count: vertices.count), count: vertices.count)
+
+ for index in 0 ... vertices.count - 1 {
+ adjMatrix[index][index] = 0
+ }
+ }
+
+ open func addEdge(v1: Vertice, v2: Vertice, weight: Int) {
+ adjMatrix[v1.id][v2.id] = weight
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/DataStructures/WeightedUndirectedGraph.swift b/SPM/Sources/DataStructuresAlgorithms/DataStructures/WeightedUndirectedGraph.swift
new file mode 100644
index 0000000..1a1c00e
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/DataStructures/WeightedUndirectedGraph.swift
@@ -0,0 +1,41 @@
+//
+// WeightedUndirectedGraph.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 12.04.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+open class WeightedUndirectedGraph {
+ public let vertices: [Vertice]
+ private var adjList: [DoubleLinkedList] = []
+ private var edgesOfGraph: [Edge] = []
+
+ public init(vertices: [Vertice]) {
+ self.vertices = vertices
+
+ for _ in vertices {
+ adjList.append(DoubleLinkedList())
+ }
+ }
+
+ open func addEdge(v1: Vertice, v2: Vertice, weight: Int) {
+ let edge = Edge(from: v1, to: v2, weight: weight)
+ adjList[v1.id].add(node: Node(val: edge))
+ edgesOfGraph.append(edge)
+
+ let edge2 = Edge(from: v2, to: v1, weight: weight)
+ adjList[v2.id].add(node: Node(val: edge2))
+ edgesOfGraph.append(edge2)
+ }
+
+ open func neighbours(v: Vertice) -> DoubleLinkedList {
+ return adjList[v.id]
+ }
+
+ open func edges() -> [Edge] {
+ return edgesOfGraph
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/ArrayPairsWithSum.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/ArrayPairsWithSum.swift
new file mode 100644
index 0000000..bf5f73a
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/ArrayPairsWithSum.swift
@@ -0,0 +1,38 @@
+//
+// ArrayPairsWithSum.swift
+//
+//
+// Created by Stefan Jaindl on 01.12.20.
+//
+
+import Foundation
+
+open class ArrayPairsWithSum {
+ public init() { }
+
+ open func pairsWithSum(array: [Int], targetSum: Int) -> Set {
+ guard array.count > 1 else {
+ return []
+ }
+
+ var lookupTable = Set()
+
+ var pairs = Set()
+
+ array.forEach { element in
+ let diffToTarget = targetSum - element
+ if lookupTable.contains(where: { $0 == diffToTarget }) {
+ pairs.insert(TargetSumPair(first: diffToTarget, second: element))
+ }
+
+ lookupTable.insert(element)
+ }
+
+ return pairs
+ }
+
+ public struct TargetSumPair: Hashable {
+ let first: Int
+ let second: Int
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/CircularArray.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/CircularArray.swift
new file mode 100644
index 0000000..3935abc
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/CircularArray.swift
@@ -0,0 +1,71 @@
+//
+// CircularArray.swift
+//
+//
+// Created by Stefan Jaindl on 10.08.20.
+//
+
+import Foundation
+
+open class CircularArray {
+ public init (array: [T]) {
+ self.array = array
+ }
+
+ let array: [T]
+ var startIndex = 0
+ var endIndex: Int {
+ return startIndex == 0 ? array.count : startIndex - 1
+ }
+
+ open func isEmpty() -> Bool {
+ return array.count == 0
+ }
+
+ open func rightRotate(by: Int) {
+ startIndex = (startIndex - by) % array.count
+ if startIndex < 0 {
+ startIndex += array.count
+ }
+ }
+
+ open func leftRotate(by: Int) {
+ startIndex = (startIndex + by) % array.count
+ }
+}
+
+extension CircularArray: Sequence {
+ public func makeIterator() -> CircularArrayIterator {
+ return CircularArrayIterator(array: array, startIndex: startIndex)
+ }
+}
+
+open class CircularArrayIterator: IteratorProtocol {
+ let array: [T]
+ var startIndex: Int
+ var currentIndex: Int
+ var previousIndex: Int
+
+ init(array: [T], startIndex: Int) {
+ self.array = array
+ self.startIndex = startIndex
+ currentIndex = startIndex
+ previousIndex = -1
+ }
+
+ open func next() -> T? {
+ guard hasNext() else {
+ return nil
+ }
+
+ let element = array[currentIndex]
+ previousIndex = currentIndex
+ currentIndex = (currentIndex + 1) % array.count
+
+ return element
+ }
+
+ private func hasNext() -> Bool {
+ return previousIndex == -1 || currentIndex != startIndex
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/IntToEnglishString.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/IntToEnglishString.swift
new file mode 100644
index 0000000..713d9a2
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/IntToEnglishString.swift
@@ -0,0 +1,170 @@
+//
+// IntToEnglishString.swift
+//
+//
+// Created by Stefan Jaindl on 19.11.20.
+//
+
+import Foundation
+
+open class IntToEnglishString {
+
+ public init() { }
+
+ private enum Config: CaseIterable {
+ case ones
+ case tens
+ case hundred
+ case thousand
+ case tenthousand
+ case hundredthousand
+ case million
+ case tenmillion
+ case hundredmillion
+ case billion
+ }
+
+ private let ones: [Int: String] = [
+ 0: "",
+ 1: "One",
+ 2: "Two",
+ 3: "Three",
+ 4: "Four",
+ 5: "Five",
+ 6: "Six",
+ 7: "Seven",
+ 8: "Eight",
+ 9: "Nine"
+ ]
+
+ private let tens: [Int: String] = [
+ 0: "",
+ 1: "Ten",
+ 2: "Twenty",
+ 3: "Thirty",
+ 4: "Fourty",
+ 5: "Fifty",
+ 6: "Sixty",
+ 7: "Seventy",
+ 8: "Eighty",
+ 9: "Ninety"
+ ]
+
+ private let specialTens: [Int: String] = [
+ 0: "Ten",
+ 1: "Eleven",
+ 2: "Twelve",
+ 3: "Thirteen",
+ 4: "Fourteen",
+ 5: "Fifteen",
+ 6: "Sixteen",
+ 7: "Seventeen",
+ 8: "Eighteen",
+ 9: "Nineteen"
+ ]
+
+ private let zero = "Zero"
+ private let hundred = "Hundred"
+ private let thousand = "Thousand"
+ private let million = "Million"
+ private let billion = "Billion"
+
+ open func convertToEnglishString(number: Int) throws -> String {
+ let stack = Stack()
+
+ var convertedString = ""
+ var curNumber = number
+ let order = Config.allCases
+ var orderIndex = 0
+ var thousandAppended = false
+ var millionAppended = false
+
+ while curNumber > 0 {
+ let currentDigit = curNumber % 10
+ let place = order[orderIndex]
+ var valueOfPlace: String
+
+ switch place {
+ case .ones:
+ valueOfPlace = ones[currentDigit] ?? ""
+ case .tens:
+ valueOfPlace = try tens(with: "", stack: stack, currentDigit: currentDigit)
+ case .hundred:
+ valueOfPlace = digit(with: hundred, stack: stack, currentDigit: currentDigit)
+ case .thousand:
+ valueOfPlace = digit(with: thousand, stack: stack, currentDigit: currentDigit)
+ if !valueOfPlace.isEmpty {
+ thousandAppended = true
+ }
+ case .tenthousand:
+ valueOfPlace = try tens(with: thousandAppended ? "" : thousand, stack: stack, currentDigit: currentDigit)
+ if !valueOfPlace.isEmpty {
+ thousandAppended = true
+ }
+ case .hundredthousand:
+ valueOfPlace = digit(with: hundred, stack: stack, currentDigit: currentDigit)
+ if !valueOfPlace.isEmpty, !thousandAppended {
+ valueOfPlace.append(" \(thousand)")
+ }
+ case .million:
+ valueOfPlace = digit(with: million, stack: stack, currentDigit: currentDigit)
+ if !valueOfPlace.isEmpty {
+ millionAppended = true
+ }
+ case .tenmillion:
+ valueOfPlace = try tens(with: millionAppended ? "" : million, stack: stack, currentDigit: currentDigit)
+ if !valueOfPlace.isEmpty {
+ millionAppended = true
+ }
+ case .hundredmillion:
+ valueOfPlace = digit(with: hundred, stack: stack, currentDigit: currentDigit)
+ if !valueOfPlace.isEmpty, !millionAppended {
+ valueOfPlace.append(" \(million)")
+ }
+ case .billion:
+ valueOfPlace = digit(with: billion, stack: stack, currentDigit: currentDigit)
+ }
+
+ stack.push(val: valueOfPlace)
+
+ orderIndex += 1
+ curNumber /= 10
+ }
+
+ while !stack.isEmpty() {
+ convertedString = "\(convertedString) \(try stack.pop())".trimmingCharacters(in: CharacterSet(arrayLiteral: " "))
+ }
+
+ return convertedString.isEmpty ? zero : convertedString
+ }
+
+ private func tens(with appended: String, stack: Stack, currentDigit: Int) throws -> String {
+ guard var valueOfPlace = tens[currentDigit] else {
+ return ""
+ }
+
+ if valueOfPlace == tens[1] {
+ let onesPlace = try stack.pop()
+ if !onesPlace.isEmpty, let value = ones.filter({ $0.value == onesPlace }).first {
+ valueOfPlace = specialTens[value.key] ?? ""
+ } else {
+ valueOfPlace = valueOfPlace.trimmingCharacters(in: CharacterSet(arrayLiteral: " "))
+ valueOfPlace.append(" \(appended)")
+ }
+ }
+
+ return valueOfPlace
+ }
+
+ private func digit(with appended: String, stack: Stack, currentDigit: Int) -> String {
+ guard var valueOfPlace = ones[currentDigit] else {
+ return ""
+ }
+
+ if !valueOfPlace.isEmpty, !appended.isEmpty {
+ valueOfPlace.append(" \(appended)")
+ }
+
+ return valueOfPlace
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/LettersAndNumbersLargestSubsequence.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/LettersAndNumbersLargestSubsequence.swift
new file mode 100644
index 0000000..34b218e
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/LettersAndNumbersLargestSubsequence.swift
@@ -0,0 +1,84 @@
+//
+// LettersAndNumbersLargestSubsequence.swift
+//
+//
+// Created by Stefan Jaindl on 05.12.20.
+//
+
+import Foundation
+
+//Computes largest subsequence of equal numbers of letters and numbers in O(N) time
+open class LettersAndNumbersLargestSubsequence {
+ public init() { }
+
+ open func findLargestSubSequence(of array: [String]) -> [String] {
+ guard !array.isEmpty else {
+ return []
+ }
+
+ let difference = computeDifferences(of: array)
+ if let submatch = findLargestSubmatch(of: difference) {
+ return Array(array[submatch.start ... submatch.end])
+ }
+
+ return []
+
+ }
+
+ private func computeDifferences(of array: [String]) -> Difference {
+ var differenceArray: [Int] = []
+ var zeroDifference: (start: Int, end: Int)?
+ var diff = 0
+ for (index, element) in array.enumerated() {
+ if isNumber(element: element) {
+ diff += 1
+ } else {
+ diff -= 1
+ }
+ differenceArray.append(diff)
+
+ if diff == 0 {
+ zeroDifference = (start: 0, end: index)
+ }
+ }
+
+ return Difference(differences: differenceArray, largestZeroDifference: zeroDifference)
+ }
+
+ private func findLargestSubmatch(of difference: Difference) -> (start: Int, end: Int)? {
+ var checkedDiffs: [Int: Int] = [:] //maps difference to index
+
+ var biggestDiffIndices: (start: Int, end: Int)?
+ var biggestDiff = 0
+
+ if let zeroDiff = difference.largestZeroDifference {
+ biggestDiffIndices = zeroDiff
+ biggestDiff = zeroDiff.end - zeroDiff.start + 1
+ }
+
+ let differences = difference.differences
+
+ for (index, diff) in differences.enumerated() {
+ if let previousIndexOfDiff = checkedDiffs[diff] {
+ let indexDifference = index - previousIndexOfDiff + 1
+ if indexDifference > biggestDiff {
+ biggestDiff = indexDifference
+ biggestDiffIndices = (start: previousIndexOfDiff + 1, end: index)
+ }
+ } else {
+ checkedDiffs[diff] = index
+ }
+ }
+
+ return biggestDiffIndices
+ }
+
+ private func isNumber(element: String) -> Bool {
+ return Int(element) != nil
+ }
+}
+
+struct Difference {
+ let differences: [Int]
+ let largestZeroDifference: (start: Int, end: Int)?
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/LongestWordFinder.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/LongestWordFinder.swift
new file mode 100644
index 0000000..9de0768
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/LongestWordFinder.swift
@@ -0,0 +1,55 @@
+//
+// LongestWordFinder.swift
+//
+//
+// Created by Stefan Jaindl on 11.12.20.
+//
+
+import Foundation
+
+open class LongestWordFinder {
+
+ public init() { }
+
+ //Finds longest word made up of another words
+ open func findLongestCombinedWord(of words: [String]) -> String? {
+ guard words.count > 1 else {
+ return nil
+ }
+
+ let trie = buildTrie(of: words)
+ let longest = longestWord(trieNode: trie.root, shorterWordFound: false, chars: [])
+
+ return longest.isEmpty ? nil : String(longest)
+ }
+
+ private func longestWord(trieNode: TrieNode, shorterWordFound: Bool, chars: [Character]) -> [Character] {
+ let terminates = trieNode.terminates
+ var longest: [Character] = []
+
+ if terminates && shorterWordFound {
+ longest = chars
+ }
+
+ for child in trieNode.childNodes {
+ var newChars = chars
+ newChars.append(child.key)
+
+ let longestChild = longestWord(trieNode: child.value, shorterWordFound: shorterWordFound || terminates, chars: newChars)
+ if longestChild.count > longest.count {
+ longest = longestChild
+ }
+ }
+
+ return longest
+ }
+
+ private func buildTrie(of words: [String]) -> Trie {
+ let trie = Trie()
+ for word in words {
+ trie.insert(word: word)
+ }
+
+ return trie
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/MajorityElement.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/MajorityElement.swift
new file mode 100644
index 0000000..cb1347e
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/MajorityElement.swift
@@ -0,0 +1,52 @@
+//
+// MajorityElement.swift
+//
+//
+// Created by Stefan Jaindl on 08.12.20.
+//
+
+import Foundation
+
+open class MajorityElement {
+ public init() { }
+
+ private let minSubarrayElementsToCheck = 2
+ private let matchPercentageTreshold = 0.5
+
+ open func find(array: [Int]) -> Int? {
+ var index = 0
+ while index < array.count {
+ if let matched = checkSubarray(array: array, startIndex: index) {
+ return matched
+ }
+
+ index += 2
+ }
+
+ return nil
+ }
+
+ private func checkSubarray(array: [Int], startIndex: Int) -> Int? {
+ var matches = 0
+ var checked = 0
+ var index = startIndex
+
+ let elementToMatch = array[index]
+
+ while checked < minSubarrayElementsToCheck || Double(Double(matches) / Double(checked)) > matchPercentageTreshold {
+ if index == startIndex && matches > 0 {
+ //found majority element!
+ return elementToMatch
+ }
+
+ if array[index] == elementToMatch {
+ matches += 1
+ }
+
+ index = (index + 1) % array.count
+ checked += 1
+ }
+
+ return nil
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/MatrixRotation.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/MatrixRotation.swift
new file mode 100644
index 0000000..7e64199
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/MatrixRotation.swift
@@ -0,0 +1,32 @@
+// MatrixRotation.swift
+// DataStructuresAlgorithms
+//
+// Created by Stefan Jaindl on 16.05.20.
+//
+
+import Foundation
+
+open class MatrixRotation {
+
+ public init() { }
+
+ open func rotateRight(array: inout [[Int]]) {
+ for offset in 0 ..< array.count / 2 {
+ rotateRight(array: &array, offset: offset)
+ }
+ }
+
+ open func rotateRight(array: inout [[Int]], offset: Int) {
+ for pos in 0 ..< array.count - 1 - offset * 2 {
+ let top = array[offset][offset + pos]
+ let right = array[offset + pos][array.count - 1 - offset]
+ let bottom = array[array.count - 1 - offset][array.count - 1 - offset - pos]
+ let left = array[array.count - 1 - offset - pos][offset]
+
+ array[offset][offset + pos] = left //left -> top
+ array[offset + pos][array.count - 1 - offset] = top //top -> right
+ array[array.count - 1 - offset][array.count - 1 - offset - pos] = right //right -> bottom
+ array[array.count - 1 - offset - pos][offset] = bottom //bottom -> left
+ }
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/MaxBlack.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/MaxBlack.swift
new file mode 100644
index 0000000..a9d5e09
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/MaxBlack.swift
@@ -0,0 +1,200 @@
+//
+// MaxBlack.swift
+//
+//
+// Created by Stefan Jaindl on 19.12.20.
+//
+
+import Foundation
+
+open class MaxBlack {
+ public init() { }
+
+ open func maxBorder(of square: BlackWhiteSquare) -> SubSquare? {
+ var len = square.cells.count
+ let count = square.cells.count
+ let blackRowCounts = blackRightRowCounts(of: square)
+ let blackColCounts = blackBottomColCounts(of: square)
+
+ while len > 0 {
+ for row in 0 ... count - len {
+ for col in 0 ... count - len {
+ let cell = SubSquare(topLeft: CellIndex(row: row, col: col), bottomRight: CellIndex(row: row + len - 1, col: col + len - 1))
+ if isAllBlackBorder(square: square, cell: cell, blackRowCounts: blackRowCounts, blackColCounts: blackColCounts, len: len) {
+ return cell
+ }
+ }
+ }
+
+ len -= 1
+ }
+
+ return nil
+ }
+
+ private func blackRightRowCounts(of square: BlackWhiteSquare) -> [CellIndex: Int] {
+ var rowIndex = square.cells.count - 1
+ var rowRightCounts: [CellIndex: Int] = [:]
+
+ while rowIndex >= 0 {
+ var blackCount = 0
+ var colIndex = square.cells.count - 1
+
+ while colIndex >= 0 {
+ rowRightCounts[CellIndex(row: rowIndex, col: colIndex)] = blackCount
+ if square.cells[rowIndex][colIndex].color == .black {
+ blackCount += 1
+ }
+ colIndex -= 1
+ }
+
+ rowIndex -= 1
+ }
+
+ return rowRightCounts
+ }
+
+ private func blackBottomColCounts(of square: BlackWhiteSquare) -> [CellIndex: Int] {
+ var colIndex = square.cells.count - 1
+ var colBottomCounts: [CellIndex: Int] = [:]
+
+ while colIndex >= 0 {
+ var blackCount = 0
+ var rowIndex = square.cells.count - 1
+
+ while rowIndex >= 0 {
+ colBottomCounts[CellIndex(row: rowIndex, col: colIndex)] = blackCount
+ if square.cells[rowIndex][colIndex].color == .black {
+ blackCount += 1
+ }
+ rowIndex -= 1
+ }
+
+ colIndex -= 1
+ }
+
+ return colBottomCounts
+ }
+
+ private func isAllBlackBorder(square: BlackWhiteSquare, cell: SubSquare, blackRowCounts: [CellIndex: Int], blackColCounts: [CellIndex: Int], len: Int) -> Bool {
+ let minRow = cell.topLeft.row
+ let maxRow = cell.bottomRight.row
+ let minCol = cell.topLeft.col
+ let maxCol = cell.bottomRight.col
+
+ let topLeftCell = CellIndex(row: minRow, col: minCol)
+ let topRightCell = CellIndex(row: minRow, col: maxCol)
+ let bottomLeftCell = CellIndex(row: maxRow, col: minCol)
+ let bottomRightCell = CellIndex(row: maxRow, col: maxCol)
+
+ guard let topLeftRowCount = blackRowCounts[topLeftCell],
+ let topRightRowCount = blackRowCounts[topRightCell],
+ let bottomLeftRowCount = blackRowCounts[bottomLeftCell],
+ let bottomRightRowCount = blackRowCounts[bottomRightCell],
+
+ let topLeftColCount = blackColCounts[topLeftCell],
+ let topRightColCount = blackColCounts[topRightCell],
+ let bottomLeftColCount = blackColCounts[bottomLeftCell],
+ let bottomRightColCount = blackColCounts[bottomRightCell] else {
+ return false
+ }
+
+ let blackTopRowCount = topLeftRowCount - topRightRowCount + (square.cells[minRow][minCol].color == .black ? 1 : 0)
+ let blackBottomRowCount = bottomLeftRowCount - bottomRightRowCount + (square.cells[maxRow][minCol].color == .black ? 1 : 0)
+
+ let blackLeftColCount = topLeftColCount - bottomLeftColCount + (square.cells[minRow][minCol].color == .black ? 1 : 0)
+ let blackRightColCount = topRightColCount - bottomRightColCount + (square.cells[minRow][maxCol].color == .black ? 1 : 0)
+
+ return blackLeftColCount == len && blackRightColCount == len && blackTopRowCount == len && blackBottomRowCount == len
+ }
+
+ //Given an NxN matrix of black & white cells, return the max sized black-only square (in O(n^4))
+ open func maxBlackFilled(of square: BlackWhiteSquare) -> SubSquare? {
+ let count = square.cells.count
+ for size in sizes(count: count) {
+ let rowSize = size.rowSize
+ let colSize = size.colSize
+ for row in 0 ... count - rowSize {
+ for col in 0 ... count - colSize {
+ let cell = SubSquare(topLeft: CellIndex(row: row, col: col), bottomRight: CellIndex(row: row + rowSize - 1, col: col + colSize - 1))
+ if isAllBlack(square: square, cell: cell) {
+ return cell
+ }
+ }
+ }
+ }
+
+ return nil
+ }
+
+ private func isAllBlack(square: BlackWhiteSquare, cell: SubSquare) -> Bool {
+ for row in cell.rowRange {
+ for col in cell.colRange {
+ if square.cells[row][col].color == .white {
+ return false
+ }
+ }
+ }
+
+ return true
+ }
+
+ private func sizes(count: Int) -> [(rowSize: Int, colSize: Int)] {
+ guard count > 0 else {
+ return []
+ }
+
+ var sizes: [(rowSize: Int, colSize: Int)] = []
+ for row in 1 ... count {
+ for col in 1 ... count {
+ sizes.append((rowSize: row, colSize: col))
+ }
+ }
+
+ return sizes.sorted(by: {
+ $0.rowSize * $0.colSize > $1.rowSize * $1.colSize
+ })
+ }
+}
+
+public struct BlackWhiteSquare {
+ let cells: [[SquareCell]]
+}
+
+
+public struct SquareCell {
+ let color: SquareCellColor
+}
+
+public struct SubRectangle: Equatable, Hashable {
+ let topLeft: CellIndex
+ let bottomRight: CellIndex
+
+ var width: Int {
+ return bottomRight.row - topLeft.row
+ }
+
+ var height: Int {
+ return topLeft.col - bottomRight.col
+ }
+
+ var rowRange: ClosedRange {
+ return topLeft.row ... bottomRight.row
+ }
+
+ var colRange: ClosedRange {
+ return topLeft.col ... bottomRight.col
+ }
+}
+
+public typealias SubSquare = SubRectangle
+
+public enum SquareCellColor {
+ case black
+ case white
+}
+
+public struct CellIndex: Hashable, Equatable {
+ let row: Int
+ let col: Int
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/MaxMatrixSum.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/MaxMatrixSum.swift
new file mode 100644
index 0000000..627f1eb
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/MaxMatrixSum.swift
@@ -0,0 +1,86 @@
+//
+// MaxMatrixSum.swift
+//
+//
+// Created by Stefan Jaindl on 20.12.20.
+//
+
+import Foundation
+
+open class MaxMatrixSum {
+
+ public init() { }
+
+ //Finds submatrix of given matrix with positive and negative int's in O(n^4) time & O(n^2) space
+ open func maxSum(of matrix: [[Int]]) -> SubRectangle? {
+ guard !matrix.isEmpty, matrix.count == matrix[0].count else {
+ return nil
+ }
+
+ let subsumsFromOrigin: [[Int]] = computeSumsFromTopLeft(of: matrix)
+ var maxSum = Int.min
+ var maxRectangle: SubRectangle? = nil
+
+ for rowSize in 1 ... matrix.count {
+ let maxValidStartRow = matrix.count - rowSize
+ for colSize in 1 ... matrix[0].count {
+ let maxValidStartColumn = matrix[0].count - colSize
+ for topRow in 0 ... maxValidStartRow {
+ for leftCol in 0 ... maxValidStartColumn {
+ let bottomRow = topRow + rowSize - 1
+ let rightCol = leftCol + colSize - 1
+
+ let fromIndex = CellIndex(row: topRow, col: leftCol)
+ let toIndex = CellIndex(row: bottomRow, col: rightCol)
+ let sum = subsum(from: fromIndex, to: toIndex, subsumsFromOrigin: subsumsFromOrigin)
+
+ if sum > maxSum {
+ maxSum = sum
+ maxRectangle = SubRectangle(topLeft: fromIndex, bottomRight: toIndex)
+ }
+ }
+ }
+ }
+ }
+
+ return maxRectangle
+ }
+
+ private func subsum(from: CellIndex, to: CellIndex, subsumsFromOrigin: [[Int]]) -> Int {
+ var sum = subsumsFromOrigin[to.row][to.col]
+
+ if from.row > 0 {
+ sum -= subsumsFromOrigin[from.row - 1][to.col]
+ }
+ if from.col > 0 {
+ sum -= subsumsFromOrigin[to.row][from.col - 1]
+ }
+ if from.row > 0, from.col > 0 {
+ sum += subsumsFromOrigin[from.row - 1][from.col - 1]
+ }
+
+ return sum
+ }
+
+ private func computeSumsFromTopLeft(of matrix: [[Int]]) -> [[Int]] {
+ var subsums: [[Int]] = [[Int]](repeating: [Int](repeating: 0, count: matrix[0].count), count: matrix.count)
+
+ for row in 0 ..< matrix.count {
+ for col in 0 ..< matrix[0].count {
+ var sum = matrix[row][col]
+ if row > 0, col > 0 {
+ sum -= subsums[row - 1][col - 1]
+ }
+ if row > 0 {
+ sum += subsums[row - 1][col]
+ }
+ if col > 0 {
+ sum += subsums[row][col - 1]
+ }
+ subsums[row][col] = sum
+ }
+ }
+
+ return subsums
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/MinElementsFinder.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/MinElementsFinder.swift
new file mode 100644
index 0000000..e911785
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/MinElementsFinder.swift
@@ -0,0 +1,117 @@
+//
+// MinElementsFinder.swift
+//
+//
+// Created by Stefan Jaindl on 11.12.20.
+//
+
+import Foundation
+
+open class MinElementsFinder {
+ public init() { }
+
+ //Finds smallest numberOfElements elements and returns them sorted in O(N log N) time using a heap.
+ open func findMinElementsSorted(numberOfElements: Int, array: [Int]) throws -> [Int] {
+ guard !array.isEmpty else {
+ return []
+ }
+
+ if numberOfElements >= array.count {
+ return array
+ }
+
+ let priorityQueue = MaxHeap()
+
+ for element in array {
+ if priorityQueue.numberOfElements() < numberOfElements {
+ priorityQueue.insert(val: element)
+ } else {
+ if element < (try priorityQueue.peekMax()) {
+ try priorityQueue.extractMax()
+ priorityQueue.insert(val: element)
+ }
+ }
+ }
+
+ var minElements: [Int] = []
+ while !priorityQueue.isEmpty() {
+ try minElements.append(priorityQueue.extractMax())
+ }
+
+ return minElements.reversed()
+ }
+
+ //Finds smallest numberOfElements elements and returns them unsorted in O(N log N) time using an adapted quicksort partition method
+ open func findMinElementsUnique(numberOfElements: Int, array: [Int]) -> [Int] {
+ guard !array.isEmpty else {
+ return []
+ }
+
+ if numberOfElements >= array.count {
+ return array
+ }
+
+ var finalIndex = -1
+ var minIndex = 0
+ var maxIndex = array.count - 1
+ var searchedArray = array
+
+ while finalIndex != numberOfElements - 1 {
+ finalIndex = partition(array: &searchedArray, min: minIndex, max: maxIndex)
+ if finalIndex == numberOfElements - 1 {
+ break
+ } else if finalIndex < numberOfElements - 1 {
+ //go right
+ minIndex = finalIndex + 1
+ } else {
+ //go left
+ maxIndex = finalIndex - 1
+ }
+ }
+
+ var minElements: [Int] = []
+ var index = 0
+ while index < numberOfElements {
+ minElements.append(searchedArray[index])
+ index += 1
+ }
+
+ return minElements
+ }
+
+ private func partition(array: inout [Int], min: Int, max: Int) -> Int {
+ let pivot = array[medianOfThree(array: array, min: min, max: max)]
+ var left = min
+ var right = max
+ while left <= right {
+ if array[left] > pivot {
+ array.swapAt(left, right)
+ right -= 1
+ } else if array[right] <= pivot {
+ array.swapAt(left, right)
+ left += 1
+ } else {
+ left += 1
+ right -= 1
+ }
+ }
+
+ return left - 1
+ }
+
+ private func medianOfThree(array: [Int], min: Int, max: Int) -> Int {
+ let middle = min + (max - min) / 2
+
+ if array[min] < array[middle] && array[min] > array[max]
+ || array[min] > array[middle] && array[min] < array[max] {
+ return min
+ }
+
+ if array[max] < array[middle] && array[max] > array[min]
+ || array[max] > array[middle] && array[max] < array[min] {
+ return max
+ }
+
+ return middle
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/MissingNumber.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/MissingNumber.swift
new file mode 100644
index 0000000..0973ea0
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/MissingNumber.swift
@@ -0,0 +1,67 @@
+//
+// MissingNumber.swift
+//
+//
+// Created by Stefan Jaindl on 04.12.20.
+//
+
+import Foundation
+
+open class MissingNumber {
+ public init() { }
+
+ //Array has non-negative numbers without duplicates in the range 0 ... n, where one number is missing.
+ //Runtime: ~ O(2N) = ~ O(N): checking O(N) -> O(N/2) -> O(N/4) ...
+ open func findMissingNumber(of array: [Int], lenght: Int) -> Int? {
+ guard !array.isEmpty, lenght == array.count else {
+ return nil
+ }
+
+ var numbersInArray = array
+ var currentBit = 0 //start with LSB
+ var missingNumber = 0
+
+ while currentBit < 64 {
+ let counts = bitCounts(bitIndex: currentBit, zero: true, of: numbersInArray)
+
+ let isZeroBit = counts.zeroes.count <= counts.ones.count
+ let min = isZeroBit ? counts.zeroes : counts.ones
+
+ numbersInArray = min
+ if !isZeroBit {
+ missingNumber |= (1 << currentBit)
+ }
+
+ if numbersInArray.count == 1 {
+ if numbersInArray[0] == missingNumber {
+ missingNumber |= 1 << (currentBit + 1)
+ }
+
+ return missingNumber
+ }
+
+ currentBit += 1
+ }
+
+ return nil
+ }
+
+ private func bitCounts(bitIndex: Int, zero: Bool, of numbers: [Int]) -> (zeroes: [Int], ones: [Int]) {
+ var zeroes: [Int] = []
+ var ones: [Int] = []
+ for number in numbers {
+ if isBitSet(bitIndex: bitIndex, of: number) {
+ ones.append(number)
+ } else {
+ zeroes.append(number)
+ }
+ }
+
+ return (zeroes: zeroes, ones: ones)
+ }
+
+ private func isBitSet(bitIndex: Int, of number: Int) -> Bool {
+ let mask = 1 << bitIndex
+ return (number & mask) != 0
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/MissingTwo.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/MissingTwo.swift
new file mode 100644
index 0000000..ab9deb5
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/MissingTwo.swift
@@ -0,0 +1,125 @@
+//
+// MissingTwo.swift
+//
+//
+// Created by Stefan Jaindl on 13.12.20.
+//
+
+import Foundation
+
+open class MissingTwo {
+ public init() { }
+
+ //Finds missing number in array from 1 ... N
+ open func findMissingNumber(in array: [Int]) -> Int? {
+ guard !array.isEmpty else {
+ return nil
+ }
+
+ let arraySum = sum(of: array)
+ let expectedSum = expected(totalCount: array.count + 1) //includes missing int
+
+ return expectedSum - arraySum
+ }
+
+ open func findMissingTwoNumbers(in array: [Int]) -> [Int] {
+ guard !array.isEmpty else {
+ return []
+ }
+
+ let totalCount = array.count + 2
+ let arraySum = sum(of: array)
+ let expectedSum = expected(totalCount: totalCount) //includes 2 missing ints
+ let lookup = buildLookupTable(of: array)
+
+ let diff = expectedSum - arraySum
+
+ //Search only possible diffs
+ let max = totalCount % 2 == 0 ? diff / 2 - 1 : diff / 2
+ for current in 1 ... max {
+ if !lookup.contains(current) {
+ //found!
+ let other = diff - current
+ return [current, other]
+ }
+ }
+
+ return []
+ }
+
+ open func findMissingTwoNumbersWithLessSpace(in array: [Int]) -> [Int] {
+ guard !array.isEmpty else {
+ return []
+ }
+
+ let totalCount = array.count + 2
+ let arraySum = sum(of: array)
+ let arrayQuadraticSum = quadraticSum(of: array)
+ let expectedArraySum = expected(totalCount: totalCount) //includes 2 missing ints
+ let expectedArrayQuadraticSum = expectedQuadraticSum(totalCount: totalCount)
+
+ let missingQuadraticSum = expectedArrayQuadraticSum - arrayQuadraticSum //the missing 2 ints are the 2 quadratics sums of this sum!
+ let missingSum = expectedArraySum - arraySum //this is the sum of the 2 missing ints
+
+ for number in 1 ... Int(missingSum / 2) {
+ let other = missingSum - number
+ let numberQuadr = Int(pow(Double(number), 2))
+ let otherQuadr = Int(pow(Double(other), 2))
+
+ if numberQuadr + otherQuadr == missingQuadraticSum {
+ return [number, other]
+ }
+ }
+
+ return []
+ }
+
+ private func sum(of array: [Int]) -> Int {
+ var arraySum = 0
+ for number in array {
+ arraySum += number
+ }
+
+ return arraySum
+ }
+
+ private func quadraticSum(of array: [Int]) -> Int {
+ var arrayQuadraticSum = 0
+ for number in array {
+ arrayQuadraticSum += Int(pow(Double(number), 2))
+ }
+
+ return arrayQuadraticSum
+ }
+
+ private func expected(totalCount: Int) -> Int {
+ let expected: Int
+
+ if totalCount % 2 == 1 {
+ expected = (totalCount / 2 + 1) * totalCount //odd
+ } else {
+ expected = (totalCount / 2) * totalCount + totalCount / 2
+ }
+
+ return expected
+ }
+
+ private func expectedQuadraticSum(totalCount: Int) -> Int {
+ var expected = 0
+
+ for number in 1 ... totalCount {
+ expected += Int(pow(Double(number), 2))
+ }
+
+ return expected
+ }
+
+ private func buildLookupTable(of array: [Int]) -> Set {
+ var set = Set()
+ for element in array {
+ set.insert(element)
+ }
+
+ return set
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/NamesMerger.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/NamesMerger.swift
new file mode 100644
index 0000000..2483ad5
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/NamesMerger.swift
@@ -0,0 +1,146 @@
+//
+// NamesMerger.swift
+//
+//
+// Created by Stefan Jaindl on 06.12.20.
+//
+
+import Foundation
+
+open class NamesMerger {
+ public init() { }
+
+ private var vertices: [Vertice] = []
+ private var nameToMergedIndexDict: [String:Int] = [:]
+ private var nameToVerticeIndexDict: [String:Int] = [:]
+
+ open func mergeLists(nameFrequencies: [NameFrequency], nameMappings: [(String, String)]) throws -> [NameFrequency] {
+ var mergedFrequency: [NameFrequency] = []
+
+ // 1: Convert nameMappings array to directed graph
+ /*
+ E.g. nameMappings = [(Jon, John), (John, Johnny), (Chris, Kris), (Chris, Christopher)]
+ --> mappingsGraph components = (Jon, John, Johnny), (Chris, Kris, Christopher)
+ */
+
+ let mappingGraph = buildNameMappingGraph(nameFrequencies: nameFrequencies, nameMappings: nameMappings)
+
+ // 2: Associate already found indices for names
+ /*
+ E.g. nameFrequencies = [John: 15, Jon: 12, Chris: 13, Kris: 4, Christopher: 19]
+ Check entries in connected graph components:
+ --> no entry in index dict: Append to mergedFrequency and store index in nameToIndexDict
+ --> entry in index dict: Sum up in mergedFrequency at index, store index in nameToIndexDict
+ */
+
+ try nameFrequencies.forEach { nameFrequency in
+ let connectedComponents = try connectedNames(graph: mappingGraph, for: nameFrequency.name)
+
+ if let index = findIndex(mapping: connectedComponents, nameToIndexDict: nameToMergedIndexDict) {
+ let frequency = mergedFrequency[index]
+ frequency.frequency += nameFrequency.frequency
+ nameToMergedIndexDict[nameFrequency.name] = index
+ } else {
+ mergedFrequency.append(nameFrequency)
+ nameToMergedIndexDict[nameFrequency.name] = mergedFrequency.count - 1
+ }
+ }
+
+ return mergedFrequency
+ }
+
+ private func findIndex(mapping: Set, nameToIndexDict: [String: Int]) -> Int? {
+ var index: Int?
+
+ mapping.forEach { name in
+ if let nameIndex = nameToIndexDict[name] {
+ index = nameIndex
+ return
+ }
+ }
+
+ return index
+ }
+
+ private func buildNameMappingGraph(nameFrequencies: [NameFrequency], nameMappings: [(String, String)]) -> UndirectedGraph {
+ for (index, nameFrequency) in nameFrequencies.enumerated() {
+ nameToVerticeIndexDict[nameFrequency.name] = index
+ vertices.append(Vertice(id: index, name: nameFrequency.name))
+ }
+
+ nameMappings.forEach { mapping in
+ if vertice(for: mapping.0) == nil {
+ let index = nameToVerticeIndexDict.count
+ nameToVerticeIndexDict[mapping.0] = index
+ vertices.append(Vertice(id: index, name: mapping.0))
+ }
+
+ if vertice(for: mapping.1) == nil {
+ let index = nameToVerticeIndexDict.count
+ nameToVerticeIndexDict[mapping.1] = index
+ vertices.append(Vertice(id: index, name: mapping.1))
+ }
+ }
+
+ let graph = UndirectedGraph(vertices: vertices)
+
+ nameMappings.forEach { mapping in
+ if let firstVertice = vertice(for: mapping.0), let secondVertice = vertice(for: mapping.1) {
+ graph.addEdge(v1: firstVertice, v2: secondVertice)
+ }
+ }
+
+ return graph
+ }
+
+ private func connectedNames(graph: UndirectedGraph, for name: String) throws -> Set {
+ var connected = Set()
+
+ guard let startVertice = vertice(for: name) else {
+ return connected
+ }
+
+ let nameQueue = Queue()
+ nameQueue.enqueue(val: startVertice)
+ while !nameQueue.isEmpty() {
+ let currentVertice = try nameQueue.dequeue()
+ connected.insert(currentVertice.name)
+
+ let neighbours = graph.neighbours(v: currentVertice)
+ var currentHead = neighbours.head
+ while let curHead = currentHead {
+ let curNeighbour = curHead.val
+
+ if !connected.contains(curNeighbour.name) {
+ nameQueue.enqueue(val: curNeighbour)
+ }
+
+ currentHead = currentHead?.next
+ }
+ }
+
+ return connected
+ }
+
+ private func vertice(for name: String) -> Vertice? {
+ guard let index = nameToVerticeIndexDict[name] else {
+ return nil
+ }
+
+ return vertices[index]
+ }
+}
+
+open class NameFrequency: Equatable {
+ let name: String
+ var frequency: Int
+
+ init(name: String, frequency: Int) {
+ self.name = name
+ self.frequency = frequency
+ }
+
+ public static func == (lhs: NameFrequency, rhs: NameFrequency) -> Bool {
+ lhs.name == rhs.name && lhs.frequency == rhs.frequency
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/OneAwayChecker.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/OneAwayChecker.swift
new file mode 100644
index 0000000..17bfc19
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/OneAwayChecker.swift
@@ -0,0 +1,75 @@
+//
+// OneAwayChecker.swift
+// DataStructuresAlgorithms
+//
+// Created by Stefan Jaindl on 15.05.20.
+//
+
+import Foundation
+
+open class OneAwayChecker {
+
+ public init() { }
+
+ //Checks whether 2 strings are at most one replace, insert or remove operation away from each other (considering char order)
+ open func isOneAway(string1: String, string2: String) -> Bool {
+ if string1.count <= 1, string2.count <= 1 { //can't be more than one away
+ return true
+ }
+
+ if string1.count == string2.count {
+ return isOneReplaceAway(string1: string1, string2: string2)
+ }
+
+ if abs(string1.count - string2.count) == 1 {
+ return isOneInsertAway(string1: string1, string2: string2)
+ }
+
+ return false
+ }
+
+ private func isOneReplaceAway(string1: String, string2: String) -> Bool {
+ var diffFound = false
+
+ for index in 0 ..< string1.count {
+ let firstIndex = string1.index(string1.startIndex, offsetBy: index)
+ let secondIndex = string2.index(string2.startIndex, offsetBy: index)
+ if string1[firstIndex] != string2[secondIndex] {
+ if diffFound {
+ return false
+ }
+ diffFound = true
+ }
+ }
+
+ return true
+ }
+
+ private func isOneInsertAway(string1: String, string2: String) -> Bool {
+ var diffFound = false
+ var index1 = 0
+ var index2 = 0
+
+ while index1 < string1.count, index2 < string2.count {
+ let firstIndex = string1.index(string1.startIndex, offsetBy: index1)
+ let secondIndex = string2.index(string2.startIndex, offsetBy: index2)
+ if string1[firstIndex] != string2[secondIndex] {
+ if diffFound {
+ return false
+ }
+ diffFound = true
+
+ if string1.count > string2.count {
+ index1 += 1
+ } else {
+ index2 += 1
+ }
+ } else {
+ index1 += 1
+ index2 += 1
+ }
+ }
+
+ return true
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/PalindromePermutation.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/PalindromePermutation.swift
new file mode 100644
index 0000000..81084ad
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/PalindromePermutation.swift
@@ -0,0 +1,50 @@
+//
+// PalindromePermutation.swift
+// DataStructuresAlgorithms
+//
+// Created by Stefan Jaindl on 14.05.20.
+//
+
+import Foundation
+
+open class PalindromePermutation {
+ private let alphabetSize: Int
+
+ public init(alphabetSize: Int) {
+ self.alphabetSize = alphabetSize
+ }
+
+ open func isPalindromePermutation(input: String) -> Bool {
+ if input.count < 2 {
+ return true
+ }
+
+ var oddCounter = 0
+ let bitVector = BitVector(numberOfBits: alphabetSize)
+
+ for char in input {
+ guard let asciiValue = char.asciiValue else {
+ continue //disregard non ASCII chars..
+ }
+
+ if bitVector.isBitSet(index: Int(asciiValue)) {
+ bitVector.unsetBit(index: Int(asciiValue))
+ oddCounter -= 1
+ } else {
+ bitVector.setBit(index: Int(asciiValue))
+ oddCounter += 1
+ }
+ }
+
+ if oddCounter <= 1 {
+ //For odd strings there must be exactly 1 odd char (center char) and for even strings no odd char
+ return true
+ }
+
+ //Alternative with bit manipulation - It's a palindrome permuation, if:
+ //1. no bit is set (= no unique chars) --> bitvector Int == 0
+ //2. or not more than 1 bit is set (middle one for odd strings) --> bitVector Int at pos - 1. pos - 1 & pos
+
+ return false
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/PatternMatcher.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/PatternMatcher.swift
new file mode 100644
index 0000000..aca3952
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/PatternMatcher.swift
@@ -0,0 +1,110 @@
+//
+// PatternMatcher.swift
+//
+//
+// Created by Stefan Jaindl on 28.11.20.
+//
+
+import Foundation
+
+//Checks whether string matches patterns in O(n^2) time. n for iterating through possible lenghts and n for building strings each
+//Notice that in most cases early returns are done .. e.g. if one substring doesn't match or we there are impossible counts for a length.
+open class PatternMatcher {
+ public init() { }
+
+ open func matches(value: String, pattern: [PatternValue]) -> Bool {
+ guard !pattern.isEmpty, !value.isEmpty else {
+ return false
+ }
+
+ //Count a's & b's in pattern
+ let aCount = pattern.filter { $0 == .a }.count
+ let bCount = pattern.filter { $0 == .b }.count
+
+ if !basicChecks(value: value, aCount: aCount, bCount: bCount) {
+ return false
+ }
+
+ //check increasing lengths (min len = 1)
+ let minLen = 1
+ let maxLen = value.count - bCount
+
+ PatternCheck:
+ for aLenght in minLen ..< maxLen {
+ let bLenght = (value.count - (aLenght * aCount)) / bCount
+
+ if bLenght * bCount + aLenght * aCount != value.count {
+ //impossible pattern match
+ continue PatternCheck
+ }
+
+ if checkPattern(aLenght: aLenght, bLength: bLenght, value: value, pattern: pattern) {
+ return true
+ }
+ }
+
+ return false
+ }
+
+ private func basicChecks(value: String, aCount: Int, bCount: Int) -> Bool {
+ if value.count < aCount + bCount {
+ return false
+ }
+
+ if aCount == 0 {
+ return value.count % bCount == 0
+ }
+
+ if bCount == 0 {
+ return value.count % aCount == 0
+ }
+
+ return true
+ }
+
+ private func checkPattern(aLenght: Int, bLength: Int, value: String, pattern: [PatternValue]) -> Bool {
+ var aPatternCount = 0
+ var bPatternCount = 0
+ var expectedA: String?
+ var expectedB: String?
+ for patternValue in pattern {
+ let offset = aPatternCount * aLenght + bPatternCount * bLength
+
+ switch patternValue {
+ case .a:
+ if !patternValueIsValid(value: value, offset: offset, lenght: aLenght, expected: &expectedA) {
+ return false
+ }
+ aPatternCount += 1
+ case .b:
+ if !patternValueIsValid(value: value, offset: offset, lenght: bLength, expected: &expectedB) {
+ return false
+ }
+ bPatternCount += 1
+ }
+ }
+
+ return true
+ }
+
+ private func patternValueIsValid(value: String, offset: Int, lenght: Int, expected: inout String?) -> Bool {
+ let substring = String(value[value.index(pos: offset) ..< value.index(pos: offset + lenght)])
+ if let expectedValue = expected, expectedValue != substring {
+ return false
+ }
+ expected = substring
+
+ return true
+ }
+}
+
+public extension String {
+ func index(pos: Int) -> String.Index {
+ return index(startIndex, offsetBy: pos)
+ }
+}
+
+public enum PatternValue {
+ case a
+ case b
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/PondSizes.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/PondSizes.swift
new file mode 100644
index 0000000..132bf84
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/PondSizes.swift
@@ -0,0 +1,80 @@
+//
+// PondSizes.swift
+//
+//
+// Created by Stefan Jaindl on 29.11.20.
+//
+
+import Foundation
+
+open class PondSizes {
+ public init() { }
+
+ //Input is a RxC matrix, where 0 indicates water and everything > 0 is above sea level.
+ //Water can be horizontally, vertically and diagonally connected.
+ //Returns sizes of connected ponds (water)
+ open func sizes(matrix: [[Int]]) -> [Int] {
+ guard !matrix.isEmpty, !matrix[0].isEmpty else {
+ return []
+ }
+
+ var marked = [[Bool]](repeating: [Bool](repeating: false, count: matrix[0].count), count: matrix.count)
+ var ponds: [Int] = []
+
+ for row in 0 ..< matrix.count {
+ for column in 0 ..< matrix[0].count {
+ if marked[row][column] {
+ continue
+ }
+
+ if matrix[row][column] == 0 { //Water!
+ ponds.append(pondCountDfs(matrix: matrix, marked: &marked, row: row, column: column))
+ }
+
+ marked[row][column] = true
+ }
+ }
+
+ return ponds
+ }
+
+ private func pondCountDfs(matrix: [[Int]], marked: inout [[Bool]], row: Int, column: Int) -> Int {
+ guard !marked[row][column] else {
+ return 0
+ }
+
+ marked[row][column] = true
+
+ if matrix[row][column] != 0 { //no water here
+ return 0
+ }
+
+ var pondCount = 1
+ for neighbour in neighbours(matrix: matrix, row: row, column: column) {
+ if !marked[neighbour.row][neighbour.column] {
+ pondCount += pondCountDfs(matrix: matrix, marked: &marked, row: neighbour.row, column: neighbour.column)
+ }
+ }
+
+ return pondCount
+ }
+
+ private func neighbours(matrix: [[Int]], row: Int, column: Int) -> [(row: Int, column: Int)] {
+ let rowIndices = [-1, 0, 1]
+ let columnIndices = [-1, 0, 1]
+
+ var neighbourCells: [(row: Int, column: Int)] = []
+ for rowIndex in rowIndices {
+ for columnIndex in columnIndices {
+ let neighbourColumn = column + columnIndex
+ let neighbourRow = row + rowIndex
+ if row + rowIndex >= 0, neighbourRow < matrix.count, neighbourColumn >= 0, neighbourColumn < matrix[0].count,
+ !(rowIndex == 0 && columnIndex == 0) {
+ neighbourCells.append((row: neighbourRow, column: neighbourColumn))
+ }
+ }
+ }
+
+ return neighbourCells
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/ShortestSuperSequence.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/ShortestSuperSequence.swift
new file mode 100644
index 0000000..772b73a
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/ShortestSuperSequence.swift
@@ -0,0 +1,115 @@
+//
+// ShortestSuperSequence.swift
+//
+//
+// Created by Stefan Jaindl on 12.12.20.
+//
+
+import Foundation
+
+open class ShortestSuperSequence {
+ public init() { }
+
+ open func findShortestSuperSequence(of smaller: [T], in bigger: [T]) -> SuperSequenceIndexPair? {
+ guard !smaller.isEmpty, !bigger.isEmpty, smaller.count < bigger.count else {
+ return nil
+ }
+
+ let searchedCounts = buildSearchedTable(of: smaller)
+
+ //Search in increasing slider ranges:
+ for arraySearchRange in smaller.count ... bigger.count {
+ var runningCounts = buildRunningCounts(of: bigger, with: searchedCounts, range: arraySearchRange, elementCount: smaller.count)
+ if runningCounts.matches {
+ return SuperSequenceIndexPair(start: 0, end: arraySearchRange - 1)
+ }
+
+ //Iterate through array in current range:
+ for index in 0 ..< bigger.count - arraySearchRange {
+ let nextToBeRemoved = bigger[index]
+ let nextToBeAdded = bigger[index + arraySearchRange]
+
+ updateRunningCounts(add: nextToBeAdded, remove: nextToBeRemoved, runningCounts: &runningCounts)
+ if runningCounts.matches {
+ return SuperSequenceIndexPair(start: index + 1, end: index + arraySearchRange)
+ }
+ }
+ }
+
+ return nil
+ }
+
+ private func updateRunningCounts(add: T, remove: T, runningCounts: inout SequenceResult) {
+ let removedMatching = addOrChangeExisting(table: &runningCounts.counts, element: remove, changeValue: 1) >= 0
+ let addedMatching = addOrChangeExisting(table: &runningCounts.counts, element: add, changeValue: -1) >= 0
+
+ if removedMatching {
+ runningCounts.diffToTarget += 1
+ }
+
+ if addedMatching {
+ runningCounts.diffToTarget -= 1
+ }
+ }
+
+ private func buildSearchedTable(of array: [T]) -> [T: Int] {
+ //building table: value -> count
+ var table: [T: Int] = [:]
+ for element in array {
+ addOrIncrease(table: &table, element: element, increaseValue: 1)
+ }
+
+ return table
+ }
+
+ private func addOrChangeExisting(table: inout [T: Int], element: T, changeValue: Int) -> Int {
+ if let count = table[element] {
+ table[element] = count + changeValue
+ return count + changeValue
+ }
+
+ return -1
+ }
+
+ private func addOrIncrease(table: inout [T: Int], element: T, increaseValue: Int) {
+ if let count = table[element] {
+ table[element] = count + increaseValue
+ } else {
+ table[element] = increaseValue
+ }
+ }
+
+ private func buildRunningCounts(of array: [T], with searched: [T: Int], range: Int, elementCount: Int) -> SequenceResult {
+ var diffToTarget = elementCount
+ var counts = searched
+
+ for curIndex in 0 ..< range {
+ let curElement = array[curIndex]
+ if let matched = searched[curElement] {
+ counts[curElement] = matched - 1
+ diffToTarget = max(0, diffToTarget - 1)
+ }
+ }
+
+ return SequenceResult(counts: counts, diffToTarget: diffToTarget)
+ }
+}
+
+public struct SuperSequenceIndexPair: Equatable {
+ let start: Int
+ let end: Int
+}
+
+open class SequenceResult {
+ var counts: [T: Int]
+ var diffToTarget: Int
+
+ init(counts: [T: Int], diffToTarget: Int) {
+ self.counts = counts
+ self.diffToTarget = diffToTarget
+ }
+
+ var matches: Bool {
+ return diffToTarget == 0
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/SmallestDifference.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/SmallestDifference.swift
new file mode 100644
index 0000000..68a6e03
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/SmallestDifference.swift
@@ -0,0 +1,41 @@
+//
+// SmallestDifference.swift
+//
+//
+// Created by Stefan Jaindl on 17.11.20.
+//
+
+import Foundation
+
+open class SmallestDifference {
+ public init() { }
+
+ open func smallestDifference(first: [Int], second: [Int]) -> Int? {
+ guard !first.isEmpty, !second.isEmpty else {
+ return nil
+ }
+
+ let firstSorted = first.sorted(by: { $0 < $1 } )
+ let secondSorted = second.sorted(by: { $0 < $1 } )
+
+ var firstIndex = 0
+ var secondIndex = 0
+ var smallestDifference = Int.max
+
+ while firstIndex < firstSorted.count, secondIndex < secondSorted.count {
+ let difference = firstSorted[firstIndex] - secondSorted[secondIndex]
+
+ if difference >= 0, difference < smallestDifference {
+ smallestDifference = difference
+ }
+
+ if firstSorted[firstIndex] < secondSorted[secondIndex] {
+ firstIndex += 1
+ } else {
+ secondIndex += 1
+ }
+ }
+
+ return smallestDifference
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/SpaceInserter.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/SpaceInserter.swift
new file mode 100644
index 0000000..b0491f6
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/SpaceInserter.swift
@@ -0,0 +1,72 @@
+//
+// SpaceInserter.swift
+//
+//
+// Created by Stefan Jaindl on 10.12.20.
+//
+
+import Foundation
+
+open class SpaceInserter {
+ public init() { }
+
+ open func insertSpaces(into string: String, wordsDict: [String]) -> String {
+ guard !wordsDict.isEmpty, !string.isEmpty else {
+ return string
+ }
+
+ let characters = Array(string)
+ var spacedString: [Character] = []
+ let trie = buildTrie(wordsDict: wordsDict)
+
+ var index = 0
+ while index < characters.count {
+ let remainder = Array(characters[index ..< characters.count])
+ let word = findWord(string: remainder, trie: trie)
+ if !word.isEmpty {
+ if !spacedString.isEmpty, spacedString[spacedString.count - 1] != " " {
+ spacedString += " "
+ }
+ spacedString.append(contentsOf: "\(String(word))")
+ if index != characters.count - 1 {
+ spacedString.append(" ")
+ }
+ index += word.count
+ } else {
+ spacedString.append(characters[index])
+ index += 1
+ }
+ }
+
+ return String(spacedString).trimmingCharacters(in: CharacterSet(arrayLiteral: " "))
+ }
+
+ private func findWord(string: [Character], trie: Trie) -> [Character] {
+ var trieNode: TrieNode? = trie.root
+ var found: [Character] = []
+ var curIndex = 0
+
+ while curIndex < string.count, let node = trieNode {
+ let char = string[curIndex]
+ trieNode = node.childNodes[char]
+
+ if trieNode?.terminates == true {
+ found = Array(string[0 ... curIndex])
+ }
+
+ curIndex += 1
+ }
+
+ return found
+ }
+
+ private func buildTrie(wordsDict: [String]) -> Trie {
+ let trie = Trie()
+
+ for word in wordsDict {
+ trie.insert(word: word)
+ }
+
+ return trie
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/SparseMatrix.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/SparseMatrix.swift
new file mode 100644
index 0000000..65868ac
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/SparseMatrix.swift
@@ -0,0 +1,123 @@
+//
+// SparseMatrix.swift
+//
+//
+// Created by Stefan Jaindl on 23.12.20.
+//
+
+import Foundation
+
+open class SparseMatrix {
+
+ public init() { }
+
+ open func similarity(of documents: [SparseDocument]) -> [Similarity] {
+ guard !documents.isEmpty else {
+ return []
+ }
+
+ //map from words to documents:
+ let mapping = buildIntToDocumentMapping(documents: documents)
+
+ //intersection count for each document pair:
+ let intersections = intersectionCounts(of: mapping)
+
+ //calculate union and intersection counts of documents where an intersection exists
+ let documentDict = buildDocumentIdDict(documents: documents)
+
+ return calculateSimilarities(documentDict: documentDict, intersectionCounts: intersections)
+ }
+
+ private func intersectionCounts(of mapping: [Int: [DocumentId]]) -> [DocumentPair: Int] {
+ var counts = [DocumentPair: Int]()
+
+ for documents in mapping.values {
+ for (index, firstDoc) in documents.enumerated() {
+ var secondIndex = index + 1
+ while secondIndex < documents.count {
+ let pair = DocumentPair(firstId: firstDoc, secondId: documents[secondIndex])
+
+ if let count = counts[pair] {
+ counts[pair] = count + 1
+ } else {
+ counts[pair] = 1
+ }
+
+ secondIndex += 1
+ }
+ }
+ }
+
+ return counts
+ }
+
+ private func buildIntToDocumentMapping(documents: [SparseDocument]) -> [Int: [DocumentId]] {
+ var mapping = [Int: [Int]]() //dict from word to docId's
+
+ for document in documents {
+ for word in document.words {
+ if var docs = mapping[word] {
+ docs.append(document.id)
+ mapping[word] = docs
+ } else {
+ let docs = [document.id]
+ mapping[word] = docs
+ }
+ }
+ }
+
+ return mapping
+ }
+
+ private func buildDocumentIdDict(documents: [SparseDocument]) -> [DocumentId: SparseDocument] {
+ var documentDict = [DocumentId: SparseDocument]()
+
+ for document in documents {
+ documentDict[document.id] = document
+ }
+
+ return documentDict
+ }
+
+ private func calculateSimilarities(documentDict: [DocumentId: SparseDocument], intersectionCounts: [DocumentPair: Int]) -> [Similarity] {
+ var similarities = [Similarity]()
+
+ for (documentPair, intersectionCount) in intersectionCounts {
+ guard let firstTotal = documentDict[documentPair.firstId]?.words.count,
+ let secondTotal = documentDict[documentPair.secondId]?.words.count else {
+ continue
+ }
+
+ let totalCount = firstTotal + secondTotal
+ let unionCount = totalCount - intersectionCount //intersection counted twice
+ let similarity = Similarity(documents: documentPair, similarity: Double(Double(intersectionCount) / Double(unionCount)))
+
+ similarities.append(similarity)
+ }
+
+ return similarities
+ }
+}
+
+public struct SparseDocument {
+ let id: DocumentId
+ let words: [Int]
+}
+
+public struct Similarity: Equatable {
+ let documents: DocumentPair
+ let similarity: Double
+
+ public static func == (lhs: Similarity, rhs: Similarity) -> Bool {
+ return lhs.documents.firstId == rhs.documents.firstId &&
+ lhs.documents.secondId == rhs.documents.secondId &&
+ lhs.similarity == rhs.similarity
+ }
+}
+
+public struct DocumentPair: Hashable {
+ let firstId: DocumentId
+ let secondId: DocumentId
+}
+
+typealias DocumentId = Int
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/StringCompresser.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/StringCompresser.swift
new file mode 100644
index 0000000..ff2221f
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/StringCompresser.swift
@@ -0,0 +1,75 @@
+//
+// OneAwayChecker.swift
+// DataStructuresAlgorithms
+//
+// Created by Stefan Jaindl on 15.05.20.
+//
+
+import Foundation
+
+open class StringCompresser {
+
+ public init() { }
+
+ //Performs simple string compression
+ open func compress(string: String) -> String {
+ if string.count <= 2 {
+ return string
+ }
+
+ let compressedStringCount = compressedCount(string: string)
+
+ if compressedStringCount >= string.count {
+ return string
+ }
+
+ var compressed: [Character] = []
+ compressed.reserveCapacity(compressedStringCount)
+
+ var currentCharCount = 0
+ var currentChar: Character?
+
+ for char in string {
+ guard let current = currentChar else {
+ currentChar = char
+ currentCharCount += 1
+ continue
+ }
+
+ if current == char {
+ currentCharCount += 1
+ } else {
+ compressed.append(current)
+ compressed.append(contentsOf: String(currentCharCount))
+ currentChar = char
+ currentCharCount = 1
+ }
+ }
+
+ if currentCharCount > 0, let currentChar = currentChar {
+ compressed.append(currentChar)
+ compressed.append(contentsOf: String(currentCharCount))
+ }
+
+ return String(compressed)
+ }
+
+ func compressedCount(string: String) -> Int {
+ var count = 0
+ var currentChar: Character?
+ for char in string {
+ guard let current = currentChar else {
+ count += 1
+ currentChar = char
+ continue
+ }
+
+ if char != current {
+ count += 1
+ currentChar = char
+ }
+ }
+
+ return count * 2
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/StringPermutationChecker.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/StringPermutationChecker.swift
new file mode 100644
index 0000000..e286cc6
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/StringPermutationChecker.swift
@@ -0,0 +1,59 @@
+//
+// StringPermuationChecker.swift
+//
+//
+// Created by Stefan Jaindl on 09.05.20.
+//
+
+import Foundation
+
+open class StringPermuationChecker {
+ private let alphabetSize: Int
+
+ init(alphabetSize: Int) {
+ self.alphabetSize = alphabetSize
+ }
+
+ open func isPermutationOfByCharArray(first: String, second: String) -> Bool {
+ if first.count != second.count {
+ //Permutations must have same size
+ return false
+ }
+
+ //Check for same character count:
+ var array = [Int] (repeating: 0, count: alphabetSize)
+ for char in Array(first) {
+ guard let ascii = char.asciiValue else {
+ return false
+ }
+
+ array[Int(ascii)] += 1
+ }
+
+ for char in Array(second) {
+ guard let ascii = char.asciiValue else {
+ return false
+ }
+
+ array[Int(ascii)] -= 1
+ if array[Int(ascii)] < 0 {
+ return false
+ }
+ }
+
+ return true
+ }
+
+ open func isPermutationOfBySorting(first: String, second: String) -> Bool {
+ if first.count != second.count {
+ //Permutations must have same size
+ return false
+ }
+
+ //Sort strings
+ let firstSorted = first.sorted()
+ let secondSorted = second.sorted()
+
+ return firstSorted == secondSorted
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/StringRotation.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/StringRotation.swift
new file mode 100644
index 0000000..7f2540d
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/StringRotation.swift
@@ -0,0 +1,29 @@
+// StringRotation.swift
+// DataStructuresAlgorithms
+//
+// Created by Stefan Jaindl on 20.05.20.
+//
+
+import Foundation
+
+open class StringRotation {
+
+ public init() { }
+
+ open func isRotation(firstString: String, secondString: String) -> Bool {
+ if firstString.count != secondString.count {
+ return false
+ }
+
+ if firstString == secondString {
+ return false
+ }
+
+ if firstString.count <= 1 {
+ return true
+ }
+
+ let appendedString = secondString + secondString
+ return appendedString.contains(firstString)
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/SumSwapper.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/SumSwapper.swift
new file mode 100644
index 0000000..028a905
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/SumSwapper.swift
@@ -0,0 +1,54 @@
+//
+// SumSwapper.swift
+//
+//
+// Created by Stefan Jaindl on 30.11.20.
+//
+
+import Foundation
+
+open class SumSwapper {
+ public init() { }
+
+ open func swap(first: [Int], second: [Int]) -> Swappable? {
+ let firstSum = sum(of: first)
+ let secondSum = sum(of: second)
+ let diff = secondSum - firstSum
+
+ guard diff % 2 == 0 else {
+ return nil //not possible to have same sum with odd and even counts
+ }
+
+ let searchedSwapDiff = diff / 2
+
+ let firstSet = buildSet(from: first)
+ let secondSet = buildSet(from: second)
+
+ for number in firstSet {
+ let searched = number + searchedSwapDiff
+ if secondSet.contains(where: { $0 == searched }) {
+ return Swappable(first: number, second: searched)
+ }
+ }
+
+ return nil
+ }
+
+ private func sum(of array: [Int]) -> Int {
+ return array.reduce(0) { $0 + $1 }
+ }
+
+ private func buildSet(from array: [Int]) -> Set {
+ var set = Set()
+ array.forEach {
+ set.insert($0)
+ }
+
+ return set
+ }
+}
+
+public struct Swappable: Equatable {
+ let first: Int
+ let second: Int
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/T9Keyboard.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/T9Keyboard.swift
new file mode 100644
index 0000000..f6929e6
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/T9Keyboard.swift
@@ -0,0 +1,92 @@
+//
+// T9Keyboard.swift
+//
+//
+// Created by Stefan Jaindl on 30.11.20.
+//
+
+import Foundation
+
+public struct KeyMapping {
+ let mapping: [Int: [Character]]
+}
+
+open class T9Keyboard {
+ let keyMapping: KeyMapping?
+ let validWords: Trie //trie with root node
+
+ let defaultKeyMapping = KeyMapping(mapping: [1: [],
+ 2: ["a", "b", "c"],
+ 3: ["d", "e", "f"],
+ 4: ["g", "h", "i"],
+ 5: ["j", "k", "l"],
+ 6: ["m", "n", "o"],
+ 7: ["p", "q", "r", "s"],
+ 8: ["t", "u", "v"],
+ 9: ["w", "x", "y", "z"]])
+
+ public init(validWords: Trie, keyMapping: KeyMapping? = nil) {
+ self.validWords = validWords
+ self.keyMapping = keyMapping
+ }
+
+ private func getMapping() -> [Int: [Character]] {
+ let mapping = keyMapping ?? defaultKeyMapping
+ return mapping.mapping
+ }
+
+ //given: Mapping, digits, valid words
+ //returns: Possible valid words (autocomplete)
+ open func autocomplete(for digits: [Int]) throws -> [String] {
+ guard !digits.isEmpty else {
+ return []
+ }
+
+ return try autocomplete(for: digits, mapping: getMapping(), wordSoFar: [], currentTrieNode: validWords.root)
+ }
+
+ private func autocomplete(for digits: [Int], mapping: [Int: [Character]], wordSoFar: [Character], currentTrieNode: TrieNode?) throws -> [String] {
+ guard let currentTrieNode = currentTrieNode else {
+ return []
+ }
+
+ if digits.isEmpty {
+ return completeWords(wordSoFar: wordSoFar, currentTrieNode: currentTrieNode)
+ }
+
+ var validWords: [String] = []
+
+ let firstDigit = digits[0]
+ let remainingDigits = Array(digits[1 ..< digits.count])
+
+ guard firstDigit >= 0, firstDigit <= 9, let chars = mapping[firstDigit] else {
+ throw NSError(domain: "T9Keyboard: Invalid mapping", code: 0, userInfo: nil)
+ }
+
+ for char in chars {
+ let node = currentTrieNode.childNodes[char]
+ var newWord = wordSoFar
+ newWord.append(char)
+ validWords.append(contentsOf: try autocomplete(for: remainingDigits, mapping: mapping, wordSoFar: newWord, currentTrieNode: node))
+ }
+
+ return validWords
+ }
+
+ private func completeWords(wordSoFar: [Character], currentTrieNode: TrieNode) -> [String] {
+ var validWords: [String] = []
+
+ if currentTrieNode.terminates {
+ validWords.append(String(wordSoFar))
+ }
+
+ currentTrieNode.childNodes.forEach { child in
+ let node = child.value
+ var newWord = wordSoFar
+ newWord.append(child.key)
+ validWords.append(contentsOf: completeWords(wordSoFar: newWord, currentTrieNode: node))
+ }
+
+ return validWords
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/UniqueStringSearch.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/UniqueStringSearch.swift
new file mode 100644
index 0000000..5702e7a
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/UniqueStringSearch.swift
@@ -0,0 +1,79 @@
+//
+// UniqueStringSearch.swift
+// DataStructuresAlgs
+//
+// Created by Stefan Jaindl on 03.05.20.
+// Copyright © 2020 Stefan Jaindl. All rights reserved.
+//
+
+import Foundation
+
+open class UniqueStringSearch {
+
+ private let alphabetSize: Int
+
+ public init(alphabetSize: Int) {
+ self.alphabetSize = alphabetSize
+ }
+
+ //V1: HashTable/Set
+ open func isUniqueStringWithHash(input: String) -> Bool {
+ if input.count > alphabetSize {
+ return false
+ }
+
+ var charSet = Set()
+
+ for char in Array(input) {
+ if charSet.contains(char) {
+ return false
+ }
+
+ charSet.insert(char)
+ }
+
+ return true
+ }
+
+ //V2: BitVector
+ open func isUniqueStringWithBitVector(input: String) -> Bool {
+ if input.count > alphabetSize {
+ return false
+ }
+
+ let bitVector = BitVector(numberOfBits: alphabetSize)
+
+ for char in Array(input) {
+ guard let ascii = char.asciiValue else {
+ continue
+ }
+
+ if bitVector.isBitSet(index: Int(ascii)) {
+ return false
+ }
+
+ bitVector.setBit(index: Int(ascii))
+ }
+
+ return true
+ }
+
+ //V3: Without additional datastructures
+ open func isUniqueStringWithSorting(input: String) -> Bool {
+ if input.count > alphabetSize {
+ return false
+ }
+
+ let sorted = input.sorted()
+ var char: Character?
+
+ for curChar in Array(sorted) {
+ if let char = char, curChar == char {
+ return false
+ }
+ char = curChar
+ }
+
+ return true
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/Urlify.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/Urlify.swift
new file mode 100644
index 0000000..4af361d
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/Urlify.swift
@@ -0,0 +1,52 @@
+//
+// Urlify.swift
+// DataStructuresAlgorithms
+//
+// Created by Stefan Jaindl on 10.05.20.
+//
+
+import Foundation
+
+open class Urlifier {
+
+ public init() { }
+
+ open func urlify(_ input: inout [Character]) {
+ if input.isEmpty {
+ return
+ }
+
+ var charCount = input.count
+
+ //count nr. of spaces to replace:
+ var spaces = 0
+ for charCount in 0 ..< input.count {
+ if input[charCount] == " " {
+ spaces += 1
+ }
+ }
+
+ //count incl. replaced spaces (%20)
+ var finalCount = input.count + spaces * (3 - 1)
+
+ //resize array, if necessary:
+ while input.count < finalCount {
+ input.append(" ")
+ }
+
+ //We can optimize here: if charCount == finalCount, we already have replaced all blanks
+ while charCount != finalCount {
+ let char = input[charCount - 1]
+ if char == " " {
+ input[finalCount - 3] = "%"
+ input[finalCount - 2] = "2"
+ input[finalCount - 1] = "0"
+ finalCount -= 3
+ } else {
+ input[finalCount - 1] = char
+ finalCount -= 1
+ }
+ charCount -= 1
+ }
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/WordFrequencyCounter.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/WordFrequencyCounter.swift
new file mode 100644
index 0000000..678cbe4
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/WordFrequencyCounter.swift
@@ -0,0 +1,30 @@
+//
+// WordFrequencyCounter.swift
+//
+//
+// Created by Stefan Jaindl on 15.11.20.
+//
+
+import Foundation
+
+open class WordFrequencyCounter {
+ private var wordCounts: [String: Int] = [:]
+
+ public init(words: [String]) {
+ for word in words {
+ let adjusted = word.lowercased().trimmingCharacters(in: CharacterSet(charactersIn: " "))
+ let count: Int
+ if let currentCount = wordCounts[adjusted] {
+ count = currentCount + 1
+ } else {
+ count = 1
+ }
+
+ wordCounts[adjusted] = count
+ }
+ }
+
+ open func count(of word: String) -> Int {
+ return wordCounts[word.lowercased().trimmingCharacters(in: CharacterSet(charactersIn: " "))] ?? 0
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/WordRectangle.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/WordRectangle.swift
new file mode 100644
index 0000000..2ffa8a6
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/WordRectangle.swift
@@ -0,0 +1,157 @@
+//
+// WordRectangle.swift
+//
+//
+// Created by Stefan Jaindl on 21.12.20.
+//
+
+import Foundation
+
+open class WordRectangle {
+ public init() { }
+
+ open func maxRectangle(of words: [String]) -> [String] {
+ guard !words.isEmpty else {
+ return []
+ }
+
+ let wordsByLength = words.sorted(by: { $0.count > $1.count })
+ let wordsDict = wordsDictByLen(wordsByLength: wordsByLength)
+ let tries = buildTriesByLen(wordsByLength: wordsByLength)
+ let sizes = decreasingSizes(to: wordsByLength[0].count)
+
+ for size in sizes {
+ guard let columnTrie = tries[size.col],
+ var wordsSet = wordsDict[size.row] else {
+ continue
+ }
+
+ let maxRectangle = buildRows(rowLen: size.row, colLen: size.col, rootTrie: columnTrie, availableRowWords: &wordsSet)
+ if !maxRectangle.isEmpty {
+ return maxRectangle
+ }
+ }
+
+ return []
+ }
+
+ private func buildRows(rowLen: Int, colLen: Int, rootTrie: Trie, availableRowWords: inout Set<[Character]>) -> [String] {
+ var tries = [TrieNode]()
+ for _ in 0 ..< colLen {
+ tries.append(rootTrie.root)
+ }
+
+ var rows = [String]()
+ rows = buildRow(rowLen: rowLen, colLen: colLen, rows: &rows, tries: tries, availableRowWords: &availableRowWords)
+
+ return rows
+ }
+
+ private func buildRow(rowLen: Int, colLen: Int, rows: inout [String], tries: [TrieNode], availableRowWords: inout Set<[Character]>) -> [String] {
+ if rows.count == rowLen {
+ for colIndex in 0 ..< colLen {
+ var colWord = [Character]()
+ for rowIndex in 0 ..< rowLen {
+ let row = Array(rows[rowIndex])
+ let char = row[colIndex]
+ colWord.append(char)
+ }
+ if !availableRowWords.contains(colWord) {
+ return []
+ }
+ }
+
+ return rows
+ }
+
+ var wordsArray = [String]()
+ for word in availableRowWords {
+ wordsArray.append(String(word))
+ }
+
+ let permutations = Permuation().permutations(array: &wordsArray)
+
+ for permutation in permutations {
+
+ var newTrieNodes = [TrieNode]()
+
+ Word:
+ for rowWord in permutation {
+ let rowChars = Array(rowWord)
+ for column in 0 ..< colLen {
+ let trie = tries[column]
+ let charOfRowWord = rowChars[column]
+ if let child = trie.childNodes[charOfRowWord] {
+ newTrieNodes.append(child)
+ } else {
+ continue Word
+ }
+ }
+
+ availableRowWords.remove(rowChars)
+ rows.append(String(rowChars))
+ let buildRows = buildRow(rowLen: rowLen, colLen: colLen, rows: &rows, tries: newTrieNodes, availableRowWords: &availableRowWords)
+ rows.removeLast()
+ availableRowWords.insert(rowChars)
+
+ if !buildRows.isEmpty {
+ return buildRows
+ }
+ }
+ }
+
+ return []
+ }
+
+ private func decreasingSizes(to: Int) -> [(row: Int, col: Int)] {
+ var sizes = [(row: Int, col: Int)]()
+ for row in 1 ... to {
+ for col in 1 ... to {
+ sizes.append((row: row, col: col))
+ }
+ }
+
+ return sizes.sorted(by: { $0.row * $0.col > $1.row * $1.col })
+ }
+
+ private func wordsDictByLen(wordsByLength: [String]) -> [Int: Set<[Character]>] {
+ var dict = [Int: Set<[Character]>]()
+
+ for word in wordsByLength {
+ if word.isEmpty {
+ continue
+ }
+
+ if var curEntry = dict[word.count] {
+ curEntry.insert(Array(word))
+ dict[word.count] = curEntry
+ } else {
+ var set = Set<[Character]>()
+ set.insert(Array(word))
+ dict[word.count] = set
+ }
+ }
+
+ return dict
+ }
+
+ private func buildTriesByLen(wordsByLength: [String]) -> [Int: Trie] {
+ var tries = [Int: Trie]()
+
+ for word in wordsByLength {
+ if word.isEmpty {
+ continue
+ }
+
+ if let curTrie = tries[word.count] {
+ curTrie.insert(word: word)
+ } else {
+ let curTrie = Trie()
+ curTrie.insert(word: word)
+ tries[word.count] = curTrie
+ }
+ }
+
+ return tries
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/WordTransformer.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/WordTransformer.swift
new file mode 100644
index 0000000..76cc3df
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/WordTransformer.swift
@@ -0,0 +1,96 @@
+//
+// WordTransformer.swift
+//
+//
+// Created by Stefan Jaindl on 18.12.20.
+//
+
+import Foundation
+
+private let wildcardChar: Character = "*"
+
+open class WordTransformer {
+
+ let words: Set
+ var oneEditAway: [WildcardMapping: Set<[Character]>] = [:]
+
+ public init(words: Set) {
+ self.words = words
+ buildValidWords(words: words)
+ }
+
+ open func transform(_ first: String, into second: String) -> [String] {
+ guard !first.isEmpty, !second.isEmpty, first.count == second.count else {
+ return []
+ }
+
+ var checked = Set<[Character]>()
+ checked.insert(Array(first))
+ return transform(searched: Array(second), path: [Array(first)], checked: &checked)
+ }
+
+ private func transform(searched: [Character], path: [[Character]], checked: inout Set<[Character]>) -> [String] {
+ let current = Array(path[path.count - 1])
+
+ if current == searched {
+ var stringPath: [String] = []
+ for chars in path {
+ stringPath.append(String(chars))
+ }
+
+ return stringPath
+ }
+
+ for index in 0 ..< searched.count {
+ let mapping = WildcardMapping(chars: current, wildcardIndex: index)
+
+ for validChar in oneEditAway[mapping] ?? [] {
+ let changedWord = validChar
+
+ if !checked.contains(changedWord) {
+ checked.insert(changedWord)
+ var newPath = path
+ newPath.append(changedWord)
+
+ let subPath = transform(searched: searched, path: newPath, checked: &checked)
+ if !subPath.isEmpty {
+ return subPath
+ }
+ }
+ }
+ }
+
+ return []
+ }
+
+ private func buildValidWords(words: Set) {
+ for word in words {
+ for (index, _) in word.enumerated() {
+ let mapping = WildcardMapping(chars: Array(word), wildcardIndex: index)
+ if var oneAway = oneEditAway[mapping] {
+ oneAway.insert(Array(word))
+ oneEditAway[mapping] = oneAway
+ } else {
+ oneEditAway[mapping] = [Array(word)]
+ }
+ }
+ }
+ }
+}
+
+public struct WildcardMapping: Hashable, Equatable {
+ let chars: [Character]
+ let wildcardIndex: Int
+
+ init(chars: [Character], wildcardIndex: Int) {
+ var adaptedChars = chars
+ adaptedChars[wildcardIndex] = wildcardChar
+
+ self.chars = adaptedChars
+ self.wildcardIndex = wildcardIndex
+ }
+
+ public static func == (lhs: WildcardMapping, rhs: WildcardMapping) -> Bool {
+ return lhs.chars == rhs.chars && lhs.wildcardIndex == rhs.wildcardIndex
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/XMLEncoder.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/XMLEncoder.swift
new file mode 100644
index 0000000..edf65f8
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/XMLEncoder.swift
@@ -0,0 +1,106 @@
+//
+// XMLEncoder.swift
+//
+//
+// Created by Stefan Jaindl on 23.11.20.
+//
+
+import Foundation
+
+public enum XMLElement {
+ case tag(encoded: Int)
+ case end
+ case value(value: String)
+}
+
+open class XMLEncoder {
+ public init() { }
+
+ private let endEncoding = "0"
+
+ open func encode(xml: String, attributesMapping: [String: Int]) throws -> String {
+ guard !xml.isEmpty else {
+ return ""
+ }
+
+ let elements = try buildElements(xml: xml, attributesMapping: attributesMapping)
+ let encoded = encode(elements: elements)
+
+ return encoded
+ }
+
+ private func buildElements(xml: String, attributesMapping: [String: Int]) throws -> [XMLElement] {
+ var remainingXml = xml
+ var elements: [XMLElement] = []
+
+ while !remainingXml.isEmpty {
+ //First, search for string enclosed in < .. >
+ guard let elementOpenIndex = remainingXml.firstIndex(of: "<"), let closeIndex = remainingXml.firstIndex(of: ">") else {
+ throw NSError(domain: "XMLEncoder: Invalid XML", code: 0, userInfo: nil)
+ }
+
+ let elementCloseIndex = remainingXml.index(after: closeIndex)
+ let element = String(remainingXml[elementOpenIndex ..< elementCloseIndex])
+ remainingXml = String(remainingXml[elementCloseIndex ..< remainingXml.endIndex])
+
+ let subElements = element.split(separator: " ")
+ try subElements.forEach { subElement in
+ let endsWithClosing = subElement[subElement.index(before: subElement.endIndex)] == ">"
+
+ if subElement.starts(with: ""), endsWithClosing {
+ elements.append(.end)
+ } else if subElement.starts(with: "<") {
+ let startAttribute = String(subElement[subElement.index(after: subElement.startIndex) ..< subElement.endIndex])
+ guard let encoding = attributesMapping[startAttribute] else {
+ throw NSError(domain: "XMLEncoder: Missing mapping for \(startAttribute)", code: 0, userInfo: nil)
+ }
+
+ elements.append(.tag(encoded: encoding))
+ }
+
+ if subElement.contains("=") {
+ let attribute = subElement.split(separator: "=")
+ guard attribute.count == 2 else {
+ throw NSError(domain: "XMLEncoder: Invalid XML attribute", code: 0, userInfo: nil)
+ }
+
+ let tag = String(attribute[0])
+ let tagValue = String(attribute[1].trimmingCharacters(in: CharacterSet(arrayLiteral: ">")).trimmingCharacters(in: CharacterSet(arrayLiteral: "\"")))
+
+ guard let encoding = attributesMapping[tag] else {
+ throw NSError(domain: "XMLEncoder: Missing mapping for \(tag)", code: 0, userInfo: nil)
+ }
+
+ elements.append(.tag(encoded: encoding))
+ elements.append(.value(value: tagValue))
+ }
+
+ if endsWithClosing, let possibleValueIndex = remainingXml.firstIndex(of: "<") {
+ let value = remainingXml[remainingXml.startIndex ..< possibleValueIndex].trimmingCharacters(in: CharacterSet(arrayLiteral: " "))
+ if !value.isEmpty {
+ elements.append(.value(value: value))
+ }
+ }
+ }
+ }
+
+ return elements
+ }
+
+ private func encode(elements: [XMLElement]) -> String {
+ var encodedString = ""
+
+ elements.forEach { element in
+ switch element {
+ case .tag(let encoded):
+ encodedString.append(" \(encoded)")
+ case .end:
+ encodedString.append(" \(endEncoding)")
+ case .value(value: let value):
+ encodedString.append(" \(value)")
+ }
+ }
+
+ return encodedString.trimmingCharacters(in: CharacterSet(arrayLiteral: " "))
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/ZeroMatrix.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/ZeroMatrix.swift
new file mode 100644
index 0000000..efc011f
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/ArraysAndStrings/ZeroMatrix.swift
@@ -0,0 +1,84 @@
+// ZeroMatrix.swift
+// DataStructuresAlgorithms
+//
+// Created by Stefan Jaindl on 19.05.20.
+//
+
+import Foundation
+
+open class ZeroMatrix {
+
+ public init() { }
+
+ open func zeroMatrix(matrix: inout [[Int]]) {
+ guard !matrix.isEmpty, !matrix[0].isEmpty else {
+ return
+ }
+
+ //We use the first row and column to zero the matrix in place
+
+ //So, first remember whether we have to nullify first row and column
+ let nullifyFirstRow = checkNullifyFirstRow(matrix: matrix)
+ let nullifyFirstColumn = checkNullifyFirstColumn(matrix: matrix)
+
+ //Check remaining cols/rows
+ for row in 1 ..< matrix.count {
+ for column in 1 ..< matrix[0].count {
+ if matrix[row][column] == 0 {
+ matrix[0][column] = 0
+ matrix[row][0] = 0
+ }
+ }
+ }
+
+ //Nullify remaining columns
+ for column in 1 ..< matrix[0].count {
+ if matrix[0][column] == 0 {
+ for row in 1 ..< matrix.count {
+ matrix[row][column] = 0
+ }
+ }
+ }
+
+ //Nullify remaining rows
+ for row in 1 ..< matrix.count {
+ if matrix[row][0] == 0 {
+ for column in 1 ..< matrix[0].count {
+ matrix[row][column] = 0
+ }
+ }
+ }
+
+ if nullifyFirstRow {
+ for column in 0 ..< matrix[0].count {
+ matrix[0][column] = 0
+ }
+ }
+
+ if nullifyFirstColumn {
+ for row in 0 ..< matrix.count {
+ matrix[row][0] = 0
+ }
+ }
+ }
+
+ private func checkNullifyFirstRow(matrix: [[Int]]) -> Bool {
+ for col in 0 ..< matrix[0].count {
+ if matrix[0][col] == 0 {
+ return true
+ }
+ }
+
+ return false
+ }
+
+ private func checkNullifyFirstColumn(matrix: [[Int]]) -> Bool {
+ for row in 0 ..< matrix.count {
+ if matrix[row][0] == 0 {
+ return true
+ }
+ }
+
+ return false
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/BitManipulation/Adder.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/BitManipulation/Adder.swift
new file mode 100644
index 0000000..56ec286
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/BitManipulation/Adder.swift
@@ -0,0 +1,73 @@
+//
+// Adder.swift
+//
+//
+// Created by Stefan Jaindl on 03.12.20.
+//
+
+import Foundation
+
+open class Adder {
+ public init() { }
+
+ open func addWithoutPlus(first: Int, second: Int) -> Int {
+ var currentFirst = first
+ var currentSecond = second
+ var shiftIndex = 0
+ var result = 0
+ var carry = 0
+
+ while currentFirst != 0 || currentSecond != 0 || carry != 0 {
+ let firstDigit = currentFirst & 1
+ let secondDigit = currentSecond & 1
+ var bit = firstDigit ^ secondDigit
+ if carry == 1 {
+ bit = bit == 1 ? 0 : 1
+ }
+
+ carry = firstDigit & secondDigit == 1 || carry > 0 && firstDigit | secondDigit > 0 ? 1 : 0
+ result |= (bit << shiftIndex)
+ currentFirst >>= 1
+ currentSecond >>= 1
+ shiftIndex = incrementByOne(bit: shiftIndex)
+ }
+
+ return result
+ }
+
+ open func incrementByOne(bit: Int) -> Int {
+ //1. Find rightmost 0 bit & Toggle all trailing 1's to 0 (right of index)
+ //2. toggle index place to 1
+ let zeroIndex = rightmostZeroIndex(of: bit)
+ let temp = setRangeToZero(bit: bit, at: zeroIndex)
+ return setBitToOne(of: temp, until: zeroIndex)
+ }
+
+ private func rightmostZeroIndex(of bit: Int) -> Int {
+ var index = 0
+ var shiftedBit = bit
+
+ while shiftedBit & 1 != 0 {
+ shiftedBit >>= 1
+ index += 1
+ }
+
+ return index
+ }
+
+ private func setRangeToZero(bit: Int, at index: Int) -> Int {
+ //mask format: e.g.: 111111111111111111111111111111111111111111111111111111111111100 (for index 2)
+ let mask = Int.max & ((Int.max >> index) << index)
+
+ return bit & mask
+
+ //alternative: let mask = (1 << index) - 1; return bit ^ mask
+ }
+
+ private func setBitToOne(of bit: Int, until index: Int) -> Int {
+ //mask format: e.g.: 100 (for index 2)
+ let mask = 1 << index
+
+ return bit | mask
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/BitManipulation/BinaryNearbySearcher.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/BitManipulation/BinaryNearbySearcher.swift
new file mode 100644
index 0000000..77b8086
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/BitManipulation/BinaryNearbySearcher.swift
@@ -0,0 +1,103 @@
+//
+// BinaryNearbySearcher.swift
+//
+//
+// Created by Stefan Jaindl on 29.07.20.
+//
+
+import Foundation
+
+open class BinaryNearbySearcher {
+ public init() { }
+
+ private enum SearchType {
+ case smaller, bigger
+ }
+
+ //Returns next smaller (if existing) and next bigger number with the same amount of 1 bits in its binary representation
+ public func nearestBinaryNumbers(number: Int) -> (Int?, Int?) {
+ let smaller = nearest(number: number, type: .smaller)
+ let bigger = nearest(number: number, type: .bigger)
+
+ return (bigger, smaller)
+ }
+
+ private func nearest(number: Int, type: SearchType) -> Int? {
+ var runningMask = 0b1
+ var lastRight = 0b0
+ var right = 0b0
+ var shiftedCount = 0
+ var nonTrailingFound = false
+ var nonTrailingCount = 0
+ var found = false
+
+ if number == 0 {
+ //nearest not existing
+ return nil
+ }
+
+ while !found {
+ if runningMask > (number << 1) {
+ //nearest not existing
+ return nil
+ }
+
+ let result = number & runningMask
+
+ switch type {
+ case .smaller:
+ if result == 0 {
+ if nonTrailingFound {
+ nonTrailingCount += 1
+ }
+ nonTrailingFound = true
+ } else if nonTrailingFound {
+ found = true
+ }
+ case .bigger:
+ if result > 0 {
+ if nonTrailingFound {
+ nonTrailingCount += 1
+ }
+ nonTrailingFound = true
+ } else if nonTrailingFound {
+ found = true
+ }
+ }
+
+ shiftedCount += 1
+ runningMask <<= 1
+
+ if !found {
+ lastRight = right
+ right |= result
+ } else {
+ right = lastRight
+ }
+ }
+
+ var result = number >> shiftedCount
+
+ result <<= 1
+ if type == .bigger {
+ result |= 0b1
+ }
+
+ result <<= 1
+ if type == .smaller {
+ result |= 0b1
+ }
+
+ result <<= shiftedCount - 2
+
+ if type == .bigger {
+ while right > 0, right & 0b1 == 0 {
+ right >>= 1
+ }
+ } else if type == .smaller {
+ right <<= nonTrailingCount
+ }
+
+ return result | right
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/BitManipulation/BinaryNumberConverter.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/BitManipulation/BinaryNumberConverter.swift
new file mode 100644
index 0000000..34a227c
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/BitManipulation/BinaryNumberConverter.swift
@@ -0,0 +1,34 @@
+//
+// BinaryNumberConverter.swift
+//
+//
+// Created by Stefan Jaindl on 31.07.20.
+//
+
+import Foundation
+
+open class BinaryNumberConverter {
+
+ public init() { }
+
+ open func binaryConversionCount(from first: Int, to second: Int) -> Int {
+ var result = first ^ second
+ var bitsDifferentCount = 0
+
+ while result > 0 {
+ if result & 0b1 == 1 {
+ bitsDifferentCount += 1
+ }
+ result >>= 1
+ }
+
+ /* Alternative:
+ while result > 0 {
+ bitsDifferentCount += 1
+ result = result & (result - 1)
+ }
+ */
+
+ return bitsDifferentCount
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/BitManipulation/BinaryToStringConverter.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/BitManipulation/BinaryToStringConverter.swift
new file mode 100644
index 0000000..2bce7b1
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/BitManipulation/BinaryToStringConverter.swift
@@ -0,0 +1,40 @@
+//
+// BinaryToStringConverter.swift
+//
+//
+// Created by Stefan Jaindl on 27.07.20.
+//
+
+import Foundation
+
+
+open class BinaryToStringConverter {
+
+ private let errorString = "ERROR"
+
+ public init() { }
+
+ //Converts a real number between 0 and 1 to its binary representation
+ //x1 * 1 / 2^1 + x2 * 1 / 2^2 + x3 * 1 / 2^3 + ..
+
+ func binaryRepresentation(of number: Double) -> String {
+ var binary = "."
+ var currentNumber = number
+
+ if currentNumber <= 0 || currentNumber >= 1 {
+ return errorString
+ }
+
+ while currentNumber > 0 {
+ if binary.count >= 32 {
+ return errorString
+ }
+
+ let digit = currentNumber * 2 //Same as shift left by 1
+ binary.append(digit >= 1 ? "1" : "0")
+ currentNumber = digit >= 1 ? digit - 1 : digit
+ }
+
+ return binary
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/BitManipulation/BitFlipper.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/BitManipulation/BitFlipper.swift
new file mode 100644
index 0000000..49d6bf5
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/BitManipulation/BitFlipper.swift
@@ -0,0 +1,35 @@
+//
+// BitFlipper.swift
+//
+//
+// Created by Stefan Jaindl on 27.07.20.
+//
+
+import Foundation
+
+open class BitFlipper {
+ public init() { }
+
+ open func findLongestOneBitSequenceByFlippingMaxOneBit(input: Int) -> Int {
+ var maxi = 0
+ var countWithZero = 0
+ var countWithoutZero = 0
+ var current = input
+
+ while current != 0 {
+ let bit = current & 1
+ if bit == 1 {
+ countWithZero += 1
+ countWithoutZero += 1
+ } else {
+ countWithZero = countWithoutZero + 1
+ countWithoutZero = 0
+ }
+
+ maxi = max(maxi, countWithZero)
+ current >>= 1
+ }
+
+ return maxi
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/BitManipulation/BitInserter.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/BitManipulation/BitInserter.swift
new file mode 100644
index 0000000..4be2d6b
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/BitManipulation/BitInserter.swift
@@ -0,0 +1,31 @@
+//
+// BitInserter.swift
+//
+//
+// Created by Stefan Jaindl on 23.07.20.
+//
+
+import Foundation
+
+open class BitInserter {
+ //Inserts bits of numberToInsert into baseNumber at given positions
+ public init() { }
+
+ open func insert(_ numberToInsert: Int, into baseNumber: Int, fromBitIndex: Int, toBitIndex: Int) -> Int {
+ let cleared = clearBits(number: baseNumber, fromBitIndex: fromBitIndex, toBitIndex: toBitIndex)
+ return insert(numberToInsert: numberToInsert, cleared: cleared, fromBitIndex: fromBitIndex)
+ }
+
+ private func clearBits(number: Int, fromBitIndex: Int, toBitIndex: Int) -> Int {
+ var bitMask = -1 << (fromBitIndex + toBitIndex - 1)
+ for index in 0 ..< fromBitIndex {
+ bitMask |= 1 << index
+ }
+
+ return number & bitMask
+ }
+
+ private func insert(numberToInsert: Int, cleared: Int, fromBitIndex: Int) -> Int {
+ return (numberToInsert << fromBitIndex) | cleared
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/BitManipulation/NumberMax.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/BitManipulation/NumberMax.swift
new file mode 100644
index 0000000..5547380
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/BitManipulation/NumberMax.swift
@@ -0,0 +1,36 @@
+//
+// NumberMax.swift
+//
+//
+// Created by Stefan Jaindl on 18.11.20.
+//
+
+import Foundation
+
+open class NumberMax {
+ public init() { }
+
+ //Finding max element without if-else and comparison operators
+ open func max(first: Int, second: Int) -> Int {
+ var firstShifted = first
+ var secondShifted = second
+ var diff = first ^ second
+
+ if diff == 0 {
+ //first == second, return any
+ return first
+ }
+
+ while diff != 1 {
+ diff >>= 1
+ firstShifted >>= 1
+ secondShifted >>= 1
+ }
+
+ let firstBigger = (firstShifted & 0b1) == 1
+ let firstValue = Int(truncating: NSNumber(value: firstBigger))
+ let secondValue = Int(truncating: NSNumber(value: !firstBigger))
+
+ return firstValue * first + secondValue * second
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/BitManipulation/Operations.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/BitManipulation/Operations.swift
new file mode 100644
index 0000000..77d739e
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/BitManipulation/Operations.swift
@@ -0,0 +1,87 @@
+//
+// Operations.swift
+//
+//
+// Created by Stefan Jaindl on 20.11.20.
+//
+
+import Foundation
+
+//Implements basic operations only using + operator and bit manipulation
+open class Operations {
+ public init() { }
+
+ open func add(first: Int, second: Int) -> Int {
+ return first + second
+ }
+
+ open func subtract(first: Int, second: Int) -> Int {
+ // first - second = -second + first (-> flipping sign of second)
+ // 10 - 4 = -4 + 10 = 6
+ let secondFlipped = negate(number: second)
+ return first + secondFlipped
+ }
+
+ open func multiply(first: Int, second: Int) -> Int {
+ //Find out smaller value, will be faster in loop
+ let smaller = first < second ? first : second
+ let bigger = first < second ? second : first
+
+ let smallerMSB = signBit(of: smaller)
+ let biggerMSB = signBit(of: bigger)
+
+ let smallerToMultiply = smallerMSB == 1 ? negate(number: smaller) : smaller
+ let biggerToMultiply = biggerMSB == 1 ? negate(number: bigger) : bigger
+
+ var result = 0
+ var count = 0
+ while count < smallerToMultiply {
+ result += biggerToMultiply
+ count += 1
+ }
+
+ if smallerMSB != biggerMSB {
+ //If one of both numbers are negative, result will be negative
+ result = negate(number: result)
+ }
+
+ return result
+ }
+
+ open func divide(first: Int, second: Int) -> Int {
+ let firstMSB = signBit(of: first)
+ let secondMSB = signBit(of: second)
+
+ let firstToDivide = firstMSB == 1 ? negate(number: first) : first
+ let secondToDivide = secondMSB == 1 ? negate(number: second) : second
+
+ var result = 0
+ var temp = 0
+ while temp <= firstToDivide {
+ result += 1
+ temp += secondToDivide
+ }
+
+ if temp > first {
+ //Truncate result, if division is with a remainder
+ result -= 1
+ }
+
+ if firstMSB != secondMSB {
+ //If one of both numbers are negative, result will be negative
+ result = negate(number: result)
+ }
+
+ return result
+ }
+
+ private func signBit(of number: Int) -> Int {
+ let mask = 1 << (Int.bitWidth - 1) //bitWidth = 64
+ return number & mask == 0 ? 0 : 1
+ }
+
+
+ private func negate(number: Int) -> Int {
+ return ~number + 1
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/BitManipulation/PairwiseSwap.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/BitManipulation/PairwiseSwap.swift
new file mode 100644
index 0000000..52c37e9
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/BitManipulation/PairwiseSwap.swift
@@ -0,0 +1,19 @@
+//
+// PairwiseSwap.swift
+//
+//
+// Created by Stefan Jaindl on 03.08.20.
+//
+
+import Foundation
+
+open class PairwiseSwap {
+ public init() { }
+
+ private let oddMask = 0x5555
+ private let evenMask = 0xAAAA
+
+ open func swapOddEven(number: Int) -> Int {
+ return (number >> 1 & oddMask) | (number << 1 & evenMask)
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/BitManipulation/ScreenManipulator.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/BitManipulation/ScreenManipulator.swift
new file mode 100644
index 0000000..a752e52
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/BitManipulation/ScreenManipulator.swift
@@ -0,0 +1,51 @@
+//
+// ScreenManipulator.swift
+//
+//
+// Created by Stefan Jaindl on 03.08.20.
+//
+
+import Foundation
+
+open class ScreenManipulator {
+ public init() { }
+
+ //width + coordinates in bits. Screen is stored in whole bytes.
+ //screen width is divisible by 8.
+ open func drawLine(screen: inout [UInt8], width: Int, x1: Int, x2: Int, y: Int) {
+ let height = screen.count / (width / 8)
+ if y >= height {
+ return
+ }
+
+ let startByte = y * width / 8 + x1 / 8
+ let endByte = startByte + (x2 - x1) / 8
+
+ if startByte == endByte {
+ //horizontal line within same byte
+ var ones = x2 - x1
+ var mask: UInt8 = 0b1
+ while ones > 0 {
+ mask = mask << 1 | 1
+ ones -= 1
+ }
+ mask <<= 8 - 1 - x2
+ screen[startByte] = mask
+ } else {
+ var start: UInt8 = 0xFF
+ let startRemainder = x1 % 8
+ start >>= startRemainder
+
+ var end: UInt8 = 0xFF
+ let endRemainder = x2 % 8
+ end >>= 8 - endRemainder
+ end <<= 8 - endRemainder
+
+ screen[startByte] = start
+ for index in startByte + 1 ..< endByte {
+ screen[index] = 0xFF
+ }
+ screen[endByte] = end
+ }
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/BitManipulation/Swapper.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/BitManipulation/Swapper.swift
new file mode 100644
index 0000000..dadd332
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/BitManipulation/Swapper.swift
@@ -0,0 +1,18 @@
+//
+// Swapper.swift
+//
+//
+// Created by Stefan Jaindl on 15.11.20.
+//
+
+import Foundation
+
+open class Swapper {
+ public init() { }
+
+ open func swapInline(_ first: inout T, _ second: inout T) {
+ first = first ^ second //bit difference
+ second = first ^ second //= original first
+ first = first ^ second //= original second
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/GraphsAndTrees/BSTSequence.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/GraphsAndTrees/BSTSequence.swift
new file mode 100644
index 0000000..4889c03
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/GraphsAndTrees/BSTSequence.swift
@@ -0,0 +1,64 @@
+//
+// BSTSequence.swift
+//
+//
+// Created by Stefan Jaindl on 06.07.20.
+//
+
+import Foundation
+
+open class BSTSequence {
+
+ public init() { }
+
+ //Returns all possible arrays from which the given BST could result (no self-balancing tree)
+ open func BSTSequences(root: SimpleTreeNode?) -> [[SimpleTreeNode]] {
+ guard let root = root else {
+ return []
+ }
+
+ let leftSequences = BSTSequences(root: root.left)
+ let rightSequences = BSTSequences(root: root.right)
+
+ if leftSequences.isEmpty, rightSequences.isEmpty {
+ return [[root]]
+ } else if leftSequences.isEmpty {
+ return rightSequences
+ } else if rightSequences.isEmpty {
+ return leftSequences
+ }
+
+ var sequences: [[SimpleTreeNode]] = []
+
+ leftSequences.forEach { left in
+ rightSequences.forEach { right in
+ sequences.append(contentsOf: weave(left: left, right: right, prefix: [root]))
+ }
+ }
+
+ return sequences
+ }
+
+ private func weave(left: [SimpleTreeNode], right: [SimpleTreeNode], prefix: [SimpleTreeNode]) -> [[SimpleTreeNode]] {
+ var newPrefix = prefix
+
+ if left.isEmpty {
+ newPrefix.append(contentsOf: right)
+ return [newPrefix]
+ } else if right.isEmpty {
+ newPrefix.append(contentsOf: left)
+ return [newPrefix]
+ }
+
+ newPrefix.append(left[0])
+ var result = weave(left: Array(left[1.. {
+
+ public init() { }
+
+ //Given: Checks whether a Binary Tree is balanced (= height of left and right child of any node doesn't differ more than one)
+ open func isBalanced(root: SimpleTreeNode) -> Bool {
+ return isBalancedRecursive(root: root).valid
+ }
+
+ private func isBalancedRecursive(root: SimpleTreeNode?) -> ResultWrapper {
+ guard let root = root else {
+ return ResultWrapper(height: 0, valid: true)
+ }
+
+ var leftResult = isBalancedRecursive(root: root.left)
+ //If balance check for left or right child already failed, just pass invalid result up
+ if !leftResult.valid {
+ return leftResult
+ }
+
+ let rightResult = isBalancedRecursive(root: root.right)
+ if !rightResult.valid {
+ return rightResult
+ }
+
+ if abs(leftResult.height - rightResult.height) > 1 {
+ //height differs more than one = not balanced!
+ //Return any result as invalid
+ leftResult.valid = false
+ return leftResult
+ }
+
+ var maxHeightResult = max(leftResult, rightResult)
+ maxHeightResult.height += 1
+
+ return maxHeightResult
+ }
+}
+
+private struct ResultWrapper: Comparable {
+ var height: Int
+ var valid: Bool
+
+ static func < (lhs: ResultWrapper, rhs: ResultWrapper) -> Bool {
+ return lhs.height < rhs.height
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/GraphsAndTrees/FirstCommonAncestor.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/GraphsAndTrees/FirstCommonAncestor.swift
new file mode 100644
index 0000000..b26d576
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/GraphsAndTrees/FirstCommonAncestor.swift
@@ -0,0 +1,65 @@
+//
+// FirstCommonAncestor.swift
+//
+//
+// Created by Stefan Jaindl on 30.06.20.
+//
+
+import Foundation
+
+open class FirstCommonAncestor {
+
+ public init() { }
+
+ //Return the first common ancestor of two nodes (without parent links)
+ open func firstCommonAncestor(root: SimpleTreeNode, first: SimpleTreeNode, second: SimpleTreeNode) -> SimpleTreeNode? {
+ var parent: SimpleTreeNode? = root
+ var isValidRoot = true
+
+ if first === second {
+ return first
+ }
+
+ while isValidRoot {
+ let firstLeftFound = isDescendant(root: parent?.left, node: first)
+ let secondLeftFound = isDescendant(root: parent?.left, node: second)
+
+ //If both nodes are on the left side, move to left child
+ if firstLeftFound && secondLeftFound {
+ parent = parent?.left
+ continue
+ }
+
+ let firstRightFound = isDescendant(root: parent?.right, node: first)
+ let secondRightFound = isDescendant(root: parent?.right, node: second)
+
+ //If both nodes are on the right side, move to right child
+ if firstRightFound && secondRightFound {
+ parent = parent?.right
+ continue
+ }
+
+ //If both nodes are found on different sides, parent is the FCA
+ if (firstLeftFound || firstRightFound || first === parent) && (secondLeftFound || secondRightFound || second === parent) {
+ return parent
+ }
+
+ //If no node was found, input is an invalid node
+ isValidRoot = false
+ }
+
+ return nil
+ }
+
+ private func isDescendant(root: SimpleTreeNode?, node: SimpleTreeNode) -> Bool {
+ guard let root = root else {
+ return false
+ }
+
+ if root === node {
+ return true
+ }
+
+ return isDescendant(root: root.left, node: node) || isDescendant(root: root.right, node: node)
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/GraphsAndTrees/ListOfDepths.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/GraphsAndTrees/ListOfDepths.swift
new file mode 100644
index 0000000..bc3db7a
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/GraphsAndTrees/ListOfDepths.swift
@@ -0,0 +1,51 @@
+//
+// ListOfDepths.swift
+//
+//
+// Created by Stefan Jaindl on 24.06.20.
+//
+
+import Foundation
+
+open class ListOfDepths {
+
+ public init () { }
+
+ open func listOfDepths(root: SimpleTreeNode) -> Array> {
+ var resultList = Array>()
+ let rootList = SingleLinkedList()
+
+ rootList.add(node: SingleNode(val: root.value))
+ resultList.append(rootList)
+
+ if let left = root.left {
+ listOfDepths(resultList: &resultList, depth: 2, treeNode: left)
+ }
+
+ if let right = root.right {
+ listOfDepths(resultList: &resultList, depth: 2, treeNode: right)
+ }
+
+ return resultList
+ }
+
+ private func listOfDepths(resultList: inout Array>, depth: Int, treeNode: SimpleTreeNode) {
+ var levelList: SingleLinkedList
+ if resultList.count >= depth {
+ levelList = resultList[depth - 1]
+ } else {
+ levelList = SingleLinkedList()
+ resultList.insert(levelList, at: depth - 1)
+ }
+
+ levelList.add(node: SingleNode(val: treeNode.value))
+
+ if let left = treeNode.left {
+ listOfDepths(resultList: &resultList, depth: depth + 1, treeNode: left)
+ }
+
+ if let right = treeNode.right {
+ listOfDepths(resultList: &resultList, depth: depth + 1, treeNode: right)
+ }
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/GraphsAndTrees/MinTree.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/GraphsAndTrees/MinTree.swift
new file mode 100644
index 0000000..3df1796
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/GraphsAndTrees/MinTree.swift
@@ -0,0 +1,43 @@
+//
+// MinTree.swift
+//
+//
+// Created by Stefan Jaindl on 23.06.20.
+//
+
+import Foundation
+
+open class MinTree {
+
+ //Given: Ascendingly sorted array without duplicates
+ //Return: Root of build binary search tree
+ open func minTree(array: [T]) throws -> SimpleTreeNode {
+ guard array.count > 0 else {
+ throw NSError(domain: "MinTree: Empty input", code: 0, userInfo: nil)
+ }
+
+ let minIndex = 0
+ let maxIndex = array.count - 1
+ let middleIndex = minIndex + (maxIndex - minIndex) / 2
+ let root = SimpleTreeNode(value: array[middleIndex])
+
+ root.left = insert(array: array, minIndex: 0, maxIndex: middleIndex - 1, root: root)
+ root.right = insert(array: array, minIndex: middleIndex + 1, maxIndex: maxIndex, root: root)
+
+ return root
+ }
+
+ private func insert(array: [T], minIndex: Int, maxIndex: Int, root: SimpleTreeNode) -> SimpleTreeNode? {
+ if minIndex > maxIndex {
+ return nil
+ }
+
+ let middleIndex = minIndex + (maxIndex - minIndex) / 2
+ let node = SimpleTreeNode(value: array[middleIndex])
+
+ node.left = insert(array: array, minIndex: minIndex, maxIndex: middleIndex - 1, root: node)
+ node.right = insert(array: array, minIndex: middleIndex + 1, maxIndex: maxIndex, root: node)
+
+ return node
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/GraphsAndTrees/NodeSuccessor.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/GraphsAndTrees/NodeSuccessor.swift
new file mode 100644
index 0000000..072f616
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/GraphsAndTrees/NodeSuccessor.swift
@@ -0,0 +1,50 @@
+//
+// BalancedTreeChecker.swift
+//
+//
+// Created by Stefan Jaindl on 28.06.20.
+//
+
+import Foundation
+
+open class NodeSuccessor {
+
+ public init() { }
+
+ //return successor node with in-order-traversal of binary search tree
+ open func successor(root: TreeNode) -> TreeNode? {
+ if let right = root.right {
+ //Case 1: If right child exists, go right, and then until leave node found
+ return traverseLeft(node: right)
+ } else if root == root.parent?.left {
+ //Case 2: If node is left child, parent node is successor
+ return root.parent
+ } else {
+ //Case 3: Node is right child -> traverse up until node which is a left child is found
+ return traverseParent(node: root.parent)
+ }
+ }
+
+ private func traverseLeft(node: TreeNode) -> TreeNode? {
+ var current = node.left
+ while let left = current?.left {
+ current = left
+ }
+
+ return current
+ }
+
+ private func traverseParent(node: TreeNode?) -> TreeNode? {
+ var current = node
+
+ while let parent = current?.parent {
+ if current == parent.left {
+ return parent
+ }
+
+ current = parent
+ }
+
+ return nil
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/GraphsAndTrees/PathChecker.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/GraphsAndTrees/PathChecker.swift
new file mode 100644
index 0000000..84fed4c
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/GraphsAndTrees/PathChecker.swift
@@ -0,0 +1,33 @@
+//
+// PathChecker.swift
+//
+//
+// Created by Stefan Jaindl on 22.06.20.
+//
+
+import Foundation
+
+extension DirectedGraph {
+
+ open func pathExists(from: Vertice, to: Vertice) -> Bool {
+ let queue = Queue()
+
+ queue.enqueue(val: from)
+ while !queue.isEmpty(), let vertice = try? queue.dequeue() {
+ vertice.visited = true
+ if vertice == to {
+ return true
+ }
+
+ var currentNode = neighbours(v: vertice).head
+ while let neighbour = currentNode {
+ if !neighbour.val.visited {
+ queue.enqueue(val: neighbour.val)
+ }
+ currentNode = neighbour.next
+ }
+ }
+
+ return false
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/GraphsAndTrees/PathSum.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/GraphsAndTrees/PathSum.swift
new file mode 100644
index 0000000..441c818
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/GraphsAndTrees/PathSum.swift
@@ -0,0 +1,47 @@
+//
+// PathSum.swift
+//
+//
+// Created by Stefan Jaindl on 15.07.20.
+//
+
+import Foundation
+
+open class PathSum {
+
+ public init() { }
+
+ open func pathSumCount(root: SimpleTreeNode, valueToMatch: Int) -> Int {
+ var sums = [Int: Int]()
+ return sumUp(root: root, sums: &sums, offset: 0, valueToMatch: valueToMatch)
+ }
+
+ //Traverse all nodes and call traverse to check paths from each node
+ private func sumUp(root: SimpleTreeNode?, sums: inout [Int: Int], offset: Int, valueToMatch: Int) -> Int {
+ guard let root = root else {
+ return 0
+ }
+
+ return traverse(root: root, sums: &sums, offset: offset, runningSum: 0, valueToMatch: valueToMatch) + sumUp(root: root.left, sums: &sums, offset: offset + root.value, valueToMatch: valueToMatch) + sumUp(root: root.right, sums: &sums, offset: offset + root.value, valueToMatch: valueToMatch)
+ }
+
+ //Traverse down from a given root
+ private func traverse(root: SimpleTreeNode?, sums: inout [Int: Int], offset: Int, runningSum: Int, valueToMatch: Int) -> Int {
+ guard let root = root else {
+ return 0
+ }
+
+ let currentSum = runningSum + root.value
+
+ //Sums maps from running sum to node count (that sum to that value)
+ if let sumForCount = sums[currentSum] {
+ sums[currentSum] = sumForCount + 1
+ } else {
+ sums[currentSum] = 1
+ }
+
+ let matching = currentSum == valueToMatch ? 1 : 0
+
+ return matching + traverse(root: root.left, sums: &sums, offset: offset, runningSum: currentSum, valueToMatch: valueToMatch) + traverse(root: root.right, sums: &sums, offset: offset, runningSum: currentSum, valueToMatch: valueToMatch)
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/GraphsAndTrees/RandomBinarySearchTree.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/GraphsAndTrees/RandomBinarySearchTree.swift
new file mode 100644
index 0000000..dfa51e9
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/GraphsAndTrees/RandomBinarySearchTree.swift
@@ -0,0 +1,213 @@
+//
+// RandomBinarySearchTree.swift
+//
+//
+// Created by Stefan Jaindl on 12.07.20.
+//
+
+import Foundation
+
+open class RandomBinarySearchTree {
+
+ var root: SimpleTreeNode?
+
+ public init() { }
+
+ open func insert(value: T) {
+ if root == nil {
+ root = SimpleTreeNode(value: value, numElements: 1)
+ } else {
+ var currentNode = root
+ while let current = currentNode {
+ current.numElements += 1
+
+ if value <= current.value {
+ if current.left == nil {
+ current.left = SimpleTreeNode(value: value, numElements: 1)
+ return
+ } else {
+ currentNode = current.left
+ }
+ } else {
+ if current.right == nil {
+ current.right = SimpleTreeNode(value: value, numElements: 1)
+ return
+ } else {
+ currentNode = current.right
+ }
+ }
+ }
+ }
+ }
+
+ open func find(value: T) -> SimpleTreeNode? {
+ var current = root
+
+ while let currentNode = current {
+ if currentNode.value == value {
+ return currentNode
+ }
+
+ current = currentNode.value > value ? currentNode.left : currentNode.right
+ }
+
+ return nil
+ }
+
+ //TODO: Check delete functionality for root
+ open func delete(value: T) {
+ var current = root
+ var previous: SimpleTreeNode? = nil
+
+ while let currentNode = current {
+ if currentNode.value == value {
+ break
+ }
+
+ previous = current
+ previous?.numElements -= 1
+ current = currentNode.value > value ? currentNode.left : currentNode.right
+ }
+
+ //case 1: node has no childs - simply delete
+ if current?.left == nil, current?.right == nil {
+ if previous?.left === current {
+ previous?.left = nil
+ } else {
+ previous?.right = nil
+ }
+ }
+
+ //case 2: node has 1 child: upgrade
+ else if current?.left == nil {
+ if previous?.left === current {
+ previous?.left = current?.right
+ } else {
+ previous?.right = current?.right
+ }
+ previous?.numElements -= 1
+ } else if current?.right == nil {
+ if previous?.left === current {
+ previous?.left = current?.left
+ } else {
+ previous?.right = current?.left
+ }
+ }
+
+ //case 3: node has 2 childs - exchange with inorder successor (or predecessor)
+ else {
+ if let left = current?.left, let right = current?.right, left.numElements > right.numElements {
+ let (previousPredecessor, predecessorNode) = inorderPredecessor(root: current)
+ //Remove last node
+ if previousPredecessor?.left === predecessorNode {
+ previousPredecessor?.left = nil
+ } else {
+ previousPredecessor?.right = nil
+ }
+
+ //replace node with in-order predecessor
+ if previous?.left === current {
+ previous?.left = predecessorNode
+ } else {
+ previous?.right = predecessorNode
+ }
+
+ if previousPredecessor === root {
+ root = predecessorNode
+ }
+ } else {
+ let (previousSuccessor, successorNode) = inorderSuccessor(root: current)
+ //Remove last node
+ if previousSuccessor?.left === successorNode {
+ previousSuccessor?.left = nil
+ } else {
+ previousSuccessor?.right = nil
+ }
+
+ //replace node with in-order predecessor
+ if previous?.left === current {
+ previous?.left = successorNode
+ } else {
+ previous?.right = successorNode
+ }
+
+ if previousSuccessor === root {
+ root = successorNode
+ }
+ }
+ }
+
+ if current === root, current?.numElements == 0 {
+ root = nil
+ return
+ }
+ }
+
+ open func getRandomNode() -> SimpleTreeNode? {
+ guard let root = root else {
+ return nil
+ }
+
+ var random = Int.random(in: 0..? = root
+
+ while let current = currentNode {
+
+ var rootId = 0
+ if let left = current.left {
+ rootId += left.numElements
+ }
+
+ if random == rootId {
+ return currentNode
+ } else if random < rootId {
+ currentNode = current.left
+ } else {
+ random -= rootId + 1
+ currentNode = current.right
+ }
+ }
+
+ return currentNode
+ }
+
+ private func inorderSuccessor(root: SimpleTreeNode?) -> (SimpleTreeNode?, SimpleTreeNode?) {
+ var node = root?.right
+ var previous: SimpleTreeNode? = root
+
+ if let left = node?.left, let right = node?.right, left.numElements > right.numElements {
+ node?.numElements -= 1
+ }
+
+ while let leftNode = node?.left {
+ if let left = leftNode.left, let right = leftNode.right, left.numElements < right.numElements {
+ leftNode.numElements -= 1
+ }
+
+ previous = node
+ node = leftNode
+ }
+
+ return (previous, node)
+ }
+
+ private func inorderPredecessor(root: SimpleTreeNode?) -> (SimpleTreeNode?, SimpleTreeNode?) {
+ var node = root?.left
+ var previous: SimpleTreeNode? = root
+
+ if let left = node?.left, let right = node?.right, left.numElements < right.numElements {
+ node?.numElements -= 1
+ }
+
+ while let rightNode = node?.right {
+ if let left = rightNode.left, let right = rightNode.right, left.numElements > right.numElements {
+ rightNode.numElements -= 1
+ }
+
+ previous = node
+ node = rightNode
+ }
+
+ return (previous, node)
+ }
+}
diff --git a/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/GraphsAndTrees/SubtreeChecker.swift b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/GraphsAndTrees/SubtreeChecker.swift
new file mode 100644
index 0000000..a250ed9
--- /dev/null
+++ b/SPM/Sources/DataStructuresAlgorithms/SpecificAlgorithms/GraphsAndTrees/SubtreeChecker.swift
@@ -0,0 +1,62 @@
+//
+// SubTreeChecker.swift
+//
+//
+// Created by Stefan Jaindl on 12.07.20.
+//
+
+import Foundation
+
+open class SubTreeChecker {
+
+ private let nilNodeValue: T
+
+ public init(nilNodeValue: T) {
+ self.nilNodeValue = nilNodeValue
+ }
+
+ //Given: Checks whether subtree is really a subtree of tree
+ //This can be checked by whether it is an array subsequence with preorder traversal and nil node values at leave nodes
+ open func isSubtree(tree: SimpleTreeNode, subtree: SimpleTreeNode