基础的数据结构

数组

数组是最基本的数据结构。在Swift 中,以前Obiective-C时代中将NSMutableArtay 和NSArray分开的做法,被统到了唯一 的数据结构Array. 虽然看上去就一种数据结构,其实它的实现有三种:

  • ContiguousArray:效率最高,元素分配在连续的元素上。如果数组是值类型(栈上操作),则Swift会自动调用Array的这种实现,如果注重效率,那么推荐声明这种类型,尤其是在大量元素是类时,这样做效果会很好。

  • Array: 会自动桥接到Objective-C 中的NSArray上,如果是值类型,则其性能与ContiguousArray无差别。

  • ArraySlice: 它不是一一个新的数组,只是一一个片段,在内存上与原数组享用同一区域。

下面是数组一些最基本的运用。
声明一个不可修改的数组

let nums = [1, 2, 3]
let nums = [Int](repeating: 0,count: 5)

//声明一个可以修改的数组var nums=[3,1,2]//增加一个元素
nums.append(4) 

//对原数组进行升序排序
nums.sort()

//对原数组进行降序排序
nums.sort(by: >)

//将原数组除最后一个外的所有元素赋值给另一-个数组
let anotherNums = Array(nums[0 ..< nums. count - 1])

不要小看这些简单的操作:数组可以依靠它们实现更多的数据结构。Swift 虽然不像Java;有现成的队列和栈,但完全可以用数组配合最简单的操作实现这些数据结构,下面就是用数组实现栈的示例代码。
//用数组实现栈

class Stack {

  var stack: [AnyObject]

  var isEmpty: Bool { return stack. isEmpty }

  var peek: AnyObject? {  return stack.last }

  init() {
      stack = [AnyObject]()
  }

  func push(object: AnyObject) {
      stack. append(object)
  }

  func pop() -> Any0bject? {
      if (!isEmpty) {
           return stack. removeLast()
        } else {
             return nil
        }
      }
}

最后要特别强调一个操作: reserveCapacity()。 它用于为原数组预留空间,防止数组在出加或删除元素时反复申请内存空间或是创建新数组,特别适用于创建和removeAll()时进行调用,对于整段代码可以起到提高性能的作用。

字典和集合

字典和集合(这里专指HashSet)经常被使用的原因在于,查找数据的时间复杂度为0(1)。一般字典和集合要求它们的Key都必须遵守Hashable 协议,Cocoa中的基本数据类型都满足这一点:自定义的class需要实现Hashable,而又因为Hashable是对Equable的扩展,所以还要重载==运算符。
下面是关于字典和集合的一此实用操作:

let primeNums: Set = [3, 5, 7,11, 13]
let oddNums: Set = [1, 3, 5, 7, 9]

交集、并集、差集

let primeAndOddNum = primeNums. intersection( oddNums)
let prime0r0ddNum = primeNums.formUnion( oddNums )
let oddNotPrimNum = oddNums.subtracting(primeNums )

用字典和高阶函数计算字符串中每个字符的出现频率,结果为["h":1, "e":1, "l":2, "o":1]

let dict =  Dictionary("hello".map { ($0,1) }, uniquingKeysWith: +)

集合和字典在实际中经常与数组配合使用,请看下面这道算法题:

给出一个整型数组和一个目标值,判断数组中是否有两个数之和等于目标值。

这道题是经典的“2Sum”,即已经有一个数组记为nums,也有一个目标值记为 target,最后要返回一个Bool值。
最粗暴的方法就是每次选中一个数,然后遍历整个数组,判断是否有另一个数使两者之和为target。这种方法的时间复杂度为0(n2)。

采用集合可以优化时间复杂度,即在遍历数组的过程中,用集合每次保存当前值。假如集合中已经有了一个数等于目标值减去当前值,则证明在之前的遍历中一定有一个数与当前值之和等于目标值。这种方法的时间复杂度为0(n),代码如下。

func twoSumSet(nums : [Int], target : Int) -> Bool
    {
        var set = Set()
        for num in nums {
            if set.contains(target - num)
            {
                return true
            }else{
                set.insert(num)
            }
        }
        return false
    }

如果把这道题目稍微修改一下,则变为:

给定一个整型数组中有且仅有两个数之和等于目标值,求这两个数在数组中的序号。

解决思路与上道题基本类似,但是为了方便得到序列号,这里使用字典,而此方法的时间复杂度依然是0(n)。代码如下。

func twoSumDict(nums : [Int],target : Int) -> [Int]
    {
        var dict = [Int:Int]()
        
        for (index,num) in nums.enumerated() {
            
            if let lastIndex = dict[target - num]
            {
                return [lastIndex,index]
            }else{
                dict[num] = index
            }
        }
        fatalError("输入nums错误")
    }

字符串

字符串在算法实战中极其常见。在Swift中,字符串不同于其他语言(包括Objctive-C),它是值类型,而非引用类型。首先列举一下字符串的通常用法。
字符串和数字之间的转换

let str= "3" 
let num = Int(str)
let number = 3

字符串长度

let len = str.count

访问字符串中的单个字符,时间复杂度为0(1)

let char = str[str.index(str.startIndex, offsetBy: n)]

修改字符串

str.remove(at: n)
str.append("c")
str += "hello world"

检测字符串是否是由数字构成

func isStrNum(str: String) -> Bool 
{
  return Int(str) != nil
}

将字符串按字母排序(不考虑大小写)

func sortStr(str: String) -> String {
    return String(str.sorted())
}

关于字符串,下面先看一道以前的Google面试题目。
给出个字符串, 要求将其按照单词顺序进行反转
比如,如果是"the sky is blue",那么反转后的结果就是"blue is sky the".

这道题目乍一看很简单, 不就是类似反转字符串吗?但是这里存在以下两个问题:

  • 每个单词长度不一样。
  • 空格需要特殊处理。

这样一来代码写起来会很烦琐,而且容易出错。不如下面先实现一个字符串反转的方法。

fileprivate func _reverse(_ chars : inout [T] , _ start : Int, _ end : Int)
    {
        var start = start, end = end
        
        while start < end {
            swap(&chars, start, end)
            start = start + 1
            end = end - 1
        }
    }
    
    
fileprivate func swap(_ chars : inout [T] , _ p : Int, _ q : Int)
 {
      (chars[q],chars[p]) = (chars[p],chars[q])
  }

有了这个方法,就可以实行下面两种字符串的反转:

整个字符串反转, "the sky is blue”一“eulb si yks eht”。

每个单词作为一个字符串单独反转,“ eulb si yks eht"” , blue is sky the” 。

整体思路有了,然后就可以解决这道题了。

func reverseWords(s : String?) -> String?
    {
        
        guard let s = s else {
            return nil
        }
        var chars = Array(s.characters)
        _reverse(&chars, 0, chars.count-1)
        var start : Int = 0
        for i  in 0..

你可能感兴趣的:(基础的数据结构)