Rotate.swift 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. //===----------------------------------------------------------------------===//
  2. //
  3. // This source file is part of the Swift Algorithms open source project
  4. //
  5. // Copyright (c) 2020 Apple Inc. and the Swift project authors
  6. // Licensed under Apache License v2.0 with Runtime Library Exception
  7. //
  8. // See https://swift.org/LICENSE.txt for license information
  9. //
  10. //===----------------------------------------------------------------------===//
  11. //===----------------------------------------------------------------------===//
  12. // reverse(subrange:)
  13. //===----------------------------------------------------------------------===//
  14. extension MutableCollection where Self: BidirectionalCollection {
  15. /// Reverses the elements of the collection, moving from each end until
  16. /// `limit` is reached from either direction. The returned indices are the
  17. /// start and end of the range of unreversed elements.
  18. ///
  19. /// Input:
  20. /// [a b c d e f g h i j k l m n o p]
  21. /// ^
  22. /// limit
  23. /// Output:
  24. /// [p o n m e f g h i j k l d c b a]
  25. /// ^ ^
  26. /// lower upper
  27. ///
  28. /// - Postcondition: For returned indices `(lower, upper)`:
  29. /// `lower == limit || upper == limit`
  30. @inlinable
  31. @discardableResult
  32. internal mutating func _reverse(
  33. subrange: Range<Index>, until limit: Index
  34. ) -> (Index, Index) {
  35. var lower = subrange.lowerBound
  36. var upper = subrange.upperBound
  37. while lower != limit && upper != limit {
  38. formIndex(before: &upper)
  39. swapAt(lower, upper)
  40. formIndex(after: &lower)
  41. }
  42. return (lower, upper)
  43. }
  44. /// Reverses the elements within the given subrange.
  45. ///
  46. /// This example reverses the numbers within the subrange at the start of the
  47. /// `numbers` array:
  48. ///
  49. /// var numbers = [10, 20, 30, 40, 50, 60, 70, 80]
  50. /// numbers.reverse(subrange: 0..<4)
  51. /// // numbers == [40, 30, 20, 10, 50, 60, 70, 80]
  52. ///
  53. /// - Parameter subrange: The subrange of this collection to reverse.
  54. ///
  55. /// - Complexity: O(*n*), where *n* is the length of `subrange`.
  56. @inlinable
  57. public mutating func reverse(subrange: Range<Index>) {
  58. if subrange.isEmpty { return }
  59. var lower = subrange.lowerBound
  60. var upper = subrange.upperBound
  61. while lower < upper {
  62. formIndex(before: &upper)
  63. swapAt(lower, upper)
  64. formIndex(after: &lower)
  65. }
  66. }
  67. }
  68. //===----------------------------------------------------------------------===//
  69. // rotate(toStartAt:) / rotate(subrange:toStartAt:)
  70. //===----------------------------------------------------------------------===//
  71. extension MutableCollection {
  72. /// Swaps the elements of the two given subranges, up to the upper bound of
  73. /// the smaller subrange. The returned indices are the ends of the two ranges
  74. /// that were actually swapped.
  75. ///
  76. /// Input:
  77. /// [a b c d e f g h i j k l m n o p]
  78. /// ^^^^^^^ ^^^^^^^^^^^^^
  79. /// lhs rhs
  80. ///
  81. /// Output:
  82. /// [i j k l e f g h a b c d m n o p]
  83. /// ^ ^
  84. /// p q
  85. ///
  86. /// - Precondition: !lhs.isEmpty && !rhs.isEmpty
  87. /// - Postcondition: For returned indices `(p, q)`:
  88. ///
  89. /// - distance(from: lhs.lowerBound, to: p) == distance(from:
  90. /// rhs.lowerBound, to: q)
  91. /// - p == lhs.upperBound || q == rhs.upperBound
  92. @inlinable
  93. internal mutating func _swapNonemptySubrangePrefixes(
  94. _ lhs: Range<Index>, _ rhs: Range<Index>
  95. ) -> (Index, Index) {
  96. assert(!lhs.isEmpty)
  97. assert(!rhs.isEmpty)
  98. var p = lhs.lowerBound
  99. var q = rhs.lowerBound
  100. repeat {
  101. swapAt(p, q)
  102. formIndex(after: &p)
  103. formIndex(after: &q)
  104. }
  105. while p != lhs.upperBound && q != rhs.upperBound
  106. return (p, q)
  107. }
  108. /// Rotates the elements within the given subrange so that the element at the
  109. /// specified index becomes the start of the subrange.
  110. ///
  111. /// Rotating a collection is equivalent to breaking the collection into two
  112. /// sections at the index `newStart`, and then swapping those two sections.
  113. /// In this example, the `numbers` array is rotated so that the element at
  114. /// index `3` (`40`) is first:
  115. ///
  116. /// var numbers = [10, 20, 30, 40, 50, 60, 70, 80]
  117. /// let oldStart = numbers.rotate(subrange: 0..<4, toStartAt: 2)
  118. /// // numbers == [30, 40, 10, 20, 50, 60, 70, 80]
  119. /// // numbers[oldStart] == 10
  120. ///
  121. /// - Parameters:
  122. /// - subrange: The subrange of this collection to rotate.
  123. /// - newStart: The index of the element that should be at the start of
  124. /// `subrange` after rotating.
  125. /// - Returns: The new index of the element that was at the start of
  126. /// `subrange` pre-rotation.
  127. ///
  128. /// - Complexity: O(*n*), where *n* is the length of `subrange`.
  129. @inlinable
  130. @discardableResult
  131. public mutating func rotate(
  132. subrange: Range<Index>,
  133. toStartAt newStart: Index
  134. ) -> Index {
  135. var m = newStart, s = subrange.lowerBound
  136. let e = subrange.upperBound
  137. // Handle the trivial cases
  138. if s == m { return e }
  139. if m == e { return s }
  140. // We have two regions of possibly-unequal length that need to be exchanged.
  141. // The return value of this method is going to be the position following
  142. // that of the element that is currently last (element j).
  143. //
  144. // [a b c d e f g|h i j] or [a b c|d e f g h i j]
  145. // ^ ^ ^ ^ ^ ^
  146. // s m e s m e
  147. //
  148. var ret = e // start with a known incorrect result.
  149. while true {
  150. // Exchange the leading elements of each region (up to the length of the
  151. // shorter region).
  152. //
  153. // [a b c d e f g|h i j] or [a b c|d e f g h i j]
  154. // ^^^^^ ^^^^^ ^^^^^ ^^^^^
  155. // [h i j d e f g|a b c] or [d e f|a b c g h i j]
  156. // ^ ^ ^ ^ ^ ^ ^ ^
  157. // s s1 m m1/e s s1/m m1 e
  158. //
  159. let (s1, m1) = _swapNonemptySubrangePrefixes(s..<m, m..<e)
  160. if m1 == e {
  161. // Left-hand case: we have moved element j into position. If we haven't
  162. // already, we can capture the return value which is in s1.
  163. //
  164. // Note: the STL breaks the loop into two just to avoid this comparison
  165. // once the return value is known. I'm not sure it's a worthwhile
  166. // optimization, though.
  167. if ret == e { ret = s1 }
  168. // If both regions were the same size, we're done.
  169. if s1 == m { break }
  170. }
  171. // Now we have a smaller problem that is also a rotation, so we can adjust
  172. // our bounds and repeat.
  173. //
  174. // h i j[d e f g|a b c] or d e f[a b c|g h i j]
  175. // ^ ^ ^ ^ ^ ^
  176. // s m e s m e
  177. s = s1
  178. if s == m { m = m1 }
  179. }
  180. return ret
  181. }
  182. /// Rotates the elements of this collection so that the element at the
  183. /// specified index becomes the start of the collection.
  184. ///
  185. /// Rotating a collection is equivalent to breaking the collection into two
  186. /// sections at the index `newStart`, and then swapping those two sections.
  187. /// In this example, the `numbers` array is rotated so that the element at
  188. /// index `3` (`40`) is first:
  189. ///
  190. /// var numbers = [10, 20, 30, 40, 50, 60, 70, 80]
  191. /// let oldStart = numbers.rotate(toStartAt: 3)
  192. /// // numbers == [40, 50, 60, 70, 80, 10, 20, 30]
  193. /// // numbers[oldStart] == 10
  194. ///
  195. /// - Parameter newStart: The index of the element that should be first after
  196. /// rotating.
  197. /// - Returns: The new index of the element that was first pre-rotation.
  198. ///
  199. /// - Complexity: O(*n*), where *n* is the length of the collection.
  200. @inlinable
  201. @discardableResult
  202. public mutating func rotate(toStartAt newStart: Index) -> Index {
  203. rotate(subrange: startIndex..<endIndex, toStartAt: newStart)
  204. }
  205. }
  206. extension MutableCollection where Self: BidirectionalCollection {
  207. /// Rotates the elements within the given subrange so that the element at the
  208. /// specified index becomes the start of the subrange.
  209. ///
  210. /// Rotating a collection is equivalent to breaking the collection into two
  211. /// sections at the index `newStart`, and then swapping those two sections.
  212. /// In this example, the `numbers` array is rotated so that the element at
  213. /// index `3` (`40`) is first:
  214. ///
  215. /// var numbers = [10, 20, 30, 40, 50, 60, 70, 80]
  216. /// let oldStart = numbers.rotate(subrange: 0..<4, toStartAt: 2)
  217. /// // numbers == [30, 40, 10, 20, 50, 60, 70, 80]
  218. /// // numbers[oldStart] == 10
  219. ///
  220. /// - Parameters:
  221. /// - subrange: The subrange of this collection to rotate.
  222. /// - newStart: The index of the element that should be at the start of
  223. /// `subrange` after rotating.
  224. /// - Returns: The new index of the element that was at the start of
  225. /// `subrange` pre-rotation.
  226. ///
  227. /// - Complexity: O(*n*), where *n* is the length of `subrange`.
  228. @inlinable
  229. @discardableResult
  230. public mutating func rotate(
  231. subrange: Range<Index>,
  232. toStartAt newStart: Index
  233. ) -> Index {
  234. reverse(subrange: subrange.lowerBound..<newStart)
  235. reverse(subrange: newStart..<subrange.upperBound)
  236. let (p, q) = _reverse(subrange: subrange, until: newStart)
  237. reverse(subrange: p..<q)
  238. return newStart == p ? q : p
  239. }
  240. /// Rotates the elements of this collection so that the element at the
  241. /// specified index becomes the start of the collection.
  242. ///
  243. /// Rotating a collection is equivalent to breaking the collection into two
  244. /// sections at the index `newStart`, and then swapping those two sections. In
  245. /// this example, the `numbers` array is rotated so that the element at index
  246. /// `3` (`40`) is first:
  247. ///
  248. /// var numbers = [10, 20, 30, 40, 50, 60, 70, 80]
  249. /// let oldStart = numbers.rotate(toStartAt: 3)
  250. /// // numbers == [40, 50, 60, 70, 80, 10, 20, 30]
  251. /// // numbers[oldStart] == 10
  252. ///
  253. /// - Parameter newStart: The index of the element that should be first after
  254. /// rotating.
  255. /// - Returns: The new index of the element that was first pre-rotation.
  256. ///
  257. /// - Complexity: O(*n*), where *n* is the length of the collection.
  258. @inlinable
  259. @discardableResult
  260. public mutating func rotate(toStartAt newStart: Index) -> Index {
  261. rotate(subrange: startIndex..<endIndex, toStartAt: newStart)
  262. }
  263. }