什么是数据结构

数据结构是指相互之间存在着一种或多种关系的数据元素的集合和该集合中数据元素之间的关系组成。分逻辑结构、存储结构、运算结构,在这里主说逻辑结构。

逻辑结构包括:

  • 集合:数据结构中的元素之间除了“同属一个集合” 的相互关系外,别无其他关系
  • 线性结构:数据结构中的元素存在一对一的相互关系
  • 树形结构:数据结构中的元素存在一对多的相互关系
  • 图形结构:数据结构中的元素存在多对多的相互关系

iOS开发现成的数据结构有:数组、字典、集合。

常见的数据结构

  • 是先进后出(FILO)的一种数据结构,你可以想象成堆起来的书,从上往下拿。
  • iOS开发中,navigationControllerpushpop操作就是一种栈的数据结构的体现。
  • 一个简单的栈的操作包括:push(进栈), pop(出栈), isEmpty(栈的元素是否为空), size(栈的大小)

用数组来实现一个栈:

///栈的实现
struct Stack<Element> {
   private var stack = [Element]()
    var isEmpty: Bool{
        return stack.isEmpty
    }
    
    var size: Int {
      return  stack.count
    }
    
    mutating func push(item:Element) -> [Element] {
        stack.append(item)
        return stack
    }
    
    mutating func pop()-> [Element] {
        if stack.count > 0 {
            stack.removeLast()
        }
        return stack
    }
    
}
    
复制代码

队列

  • 队列是一种先进先出(FIFO)的数据结构,像排队买票,前面的先买到票。
  • iOS开发中,GCDNSOperation创建的queue就是一个队列
  • 一个简单的队列的操作包括,enqueue(进队列), dequeue(出队列), isEmpty(队列的元素是否空), size(队列的大小)

同样用数组来实现一个队列:

队列的实现
struct Queue<Element> {
    
    private var queue = [Element]()
  
    var isEmpty: Bool { return queue.isEmpty }
    var size: Int { return queue.count }
    
    //入列
    mutating func enqueue(val:Element) {
        queue.append(val)
    }
    
    //出列
    mutating func dequeue() -> Element? {
        if queue.isEmpty {
            return nil
        }
     return queue.removeFirst()
    }
}

复制代码

链表

  • 链表是一种线性的数据结构,每一个结构包含表元素和指向该元素后继元素结构的指针。
  • 相对数组是有连续地址组成的数据结构,而链表则由有一系列不必在内存中相连的结构组成,避免了在插入和删除操作时的线性开销。
  • 链表的种类:单链表、双链表、循环链表

单链表如图:



  • 每个结点分Data区域和Next指针,Data区域存数值,Next指向其所在结点后继的结点。
  • 单链表中每个结点的存储地址是存放在其前趋结点next域中,而开始结点无前趋,故应设头指针head指向开始结点。链表由头指针唯一确定,单链表可以用头指针的名字来命名。头结点中存放一个地址,该地址指向一个元素,头结点一般不存放具体数据,只是存放第一个结点的地址 终端结点无后继,故终端结点的指针域为空,即NULL。
///带头结点单链表的实现

///结点
class ListNode<Element:Equatable> {
    var val: Element?
    var next: ListNode?
    init(val:Element?) {
        self.val = val
    }
    
}

class List<Element:Equatable> {

    //头结点
    var head = ListNode<Element>(val: nil)
    //第一结点
    var first: ListNode<Element>?
    ///尾结点
    var last: ListNode<Element>?
    
    
    ///尾插法
    func appendToTail(val:Element) {
        if last == nil {
            last = ListNode(val: val)
            first = last
            head.next = first
        }else {
            last!.next = ListNode(val: val)
            last = last!.next
        }
    }
    ///头插法
    func insertToHead(val:Element) {
        if first == nil {
            first = ListNode(val: val)
            last = first
            head.next = first
        }else {
            let node = ListNode(val: val)
            node.next = first
            head = node
        }
        
    }
    ///删除某个结点,如果有多个相同的,移除第一个
    func deletNode(val:Element)  {
        if head.next == nil {
            return
        }
        var node = head.next
        var tempLast: ListNode<Element>?
        while  node != nil {
            
            if node?.val == val {
                //如果的是删除第一个结点
                if first?.val == node?.val {
                    head.next = first?.next
                    first = first?.next
                    break
                }
                 //如果的是删除最后一个结点
                if last?.val == node?.val {
                    tempLast?.next = nil
                    last = tempLast
                    break
                }
                
                tempLast?.next = node?.next
                break
                
            }
            
            tempLast = node
            node = node?.next
        }
    }
}

复制代码

二叉树

  • 二叉树是由节点组成,其中每个节点最多有两个子节点,分左子节点和右子节点,最顶那个叫根节点。如下图:
  • 二叉查找树是一种特殊的二叉树。它的特点就是左子树中节点的值都小于根节点的值,右子树中节点的值都大于根节点的值。



二叉树节点的实现:

class TreeNode {
    var val:Int
    var leftNode: TreeNode?
    var rightNode: TreeNode?
    
    init(val:Int) {
        self.val = val
    }
}

复制代码

二叉树的最大深度:

///最大深度
    func maxDepth(node:TreeNode?) -> Int {
        guard let node = node else{
            return 0
        }

        return max(maxDepth(node: node.leftNode), maxDepth(node: node.rightNode)) + 1
    }

复制代码

判断一个二叉树是否是二叉查找树:

///是否二叉查找树

    func isBST(root: TreeNode?) -> Bool {
        func helper(node: TreeNode?,min: Int? ,max: Int?) -> Bool {
            guard let node = node else {
                return true
            }
            // 所有右子节点都必须大于根节点
            if let min = min, node.val <= min {
                return false
            }
            // 所有左子节点都必须小于根节点
            if let max = max, node.val >= max {
                return false
            }

            return helper(node: node.leftNode, min: min, max: node.val) && helper(node: node.rightNode, min: node.val, max: max)

        }

        return helper(node: root, min: nil, max: nil)
    }

复制代码

二叉树的遍历:

/*先序: 1.访问根结点 2.访问左子树 3.访问右子树
 */
var arr = [Int]()
func traversingTreeNode(node:TreeNode?) -> [Int] {
    
    if let node = node {
        arr.append(node.val)
        traversingTreeNode(node: node.leftNode)
        traversingTreeNode(node: node.rightNode)
    }
    
    return arr
}

/*中序:1.访问左子树

     2.访问根结点

       3.访问右子树*/
arr = [Int]()

func traversingTreeNode(node:TreeNode?) -> [Int] {
    
    if let node = node {
        traversingTreeNode(node: node.leftNode)
        arr.append(node.val)
        traversingTreeNode(node: node.rightNode)
    }
    
    return arr
}

/*后序:1.访问左子树

     2.访问右子树

       3.访问根
 */
 arr = [Int]()

func traversingTreeNode(node:TreeNode?) -> [Int] {
    
    if let node = node {
        traversingTreeNode(node: node.leftNode)
        traversingTreeNode(node: node.rightNode)
        arr.append(node.val)

    }
    
    return arr
}

///层级遍历, 打印树

func levelTraversingTree(node: TreeNode?) -> [[String]] {
    
    var res = [[String]]()
    var queue = [TreeNode]()
    
    if let n = node {
        queue.append(n)
    }
    
    
    while queue.count > 0 {
        let size = queue.count
        var levels = [String]()
        for _ in 0 ..< size {
            let tempNode = queue.removeFirst()
            var leftStr:String = "#"
            var rightStr:String = "#"

            if let left = tempNode.leftNode {
                queue.append(left)
                leftStr = String(left.val)
            }
            if let right = tempNode.rightNode {
                queue.append(right)
                rightStr = String(right.val)
            }
            
            levels.append("\(tempNode.val) -> \(leftStr),\(rightStr)")
            
        }
        
        res.append(levels)
        
    }
   
    return res
}

复制代码