数据结构学习总结

Posted 安卓行动派

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构学习总结相关的知识,希望对你有一定的参考价值。

1.二叉树

数据结构学习总结(二)

二叉树就是每个节点最多有两个叉(子节点),没有子节点的节点叫做叶子节点。

2.二分搜索树

数据结构学习总结(二)

代码实现

public class BST<E extends Comparable<E>> {

    private class Node {
        public E e;
        public Node left, right;

        public Node(E e) {
            this.e = e;
            left = null;
            right = null;
        }
    }

    private Node root;
    private int size;

    public BST(){
        root = null;
        size = 0;
    }

    public int size(){
        return size;
    }

    public boolean isEmpty(){
        return size == 0;
    }

    // 向二分搜索树中添加新的元素e
    public void add(E e){
        root = add(root, e);
    }

    // 向以node为根的二分搜索树中插入元素e,递归算法
    // 返回插入新节点后二分搜索树的根
    private Node add(Node node, E e){
        if(node == null){
            size ++;
            return new Node(e);
        }

        if(e.compareTo(node.e) < 0)
            node.left = add(node.left, e);
        else if(e.compareTo(node.e) > 0)
            node.right = add(node.right, e);

        return node;
    }

    // 看二分搜索树中是否包含元素e
    public boolean contains(E e){
        return contains(root, e);
    }

    // 看以node为根的二分搜索树中是否包含元素e, 递归算法
    private boolean contains(Node node, E e){

        if(node == null)
            return false;

        if(e.compareTo(node.e) == 0)
            return true;
        else if(e.compareTo(node.e) < 0)
            return contains(node.left, e);
        else // e.compareTo(node.e) > 0
            return contains(node.right, e);
    }
}

二分搜索树的遍历

数据结构学习总结(二)

根据是先遍历该节点还是其左子树还是右子树,分为前序遍历,中序遍历和后序遍历,又称为深度优先遍历。

// 二分搜索树的前序遍历
public void preOrder(){
    preOrder(root);
}

// 前序遍历以node为根的二分搜索树, 递归算法
private void preOrder(Node node){
    if(node == null)
        return;

    System.out.println(node.e);
    preOrder(node.left);
    preOrder(node.right);
}

// 二分搜索树的非递归前序遍历
public void preOrderNR(){

    Stack<Node> stack = new Stack<>();
    stack.push(root);
    while(!stack.isEmpty()){
        Node cur = stack.pop();
        System.out.println(cur.e);

        if(cur.right != null)
            stack.push(cur.right);
        if(cur.left != null)
            stack.push(cur.left);
    }
}

// 二分搜索树的中序遍历
public void inOrder(){
    inOrder(root);
}

// 中序遍历以node为根的二分搜索树, 递归算法
private void inOrder(Node node){
    if(node == null)
        return;

    inOrder(node.left);
    System.out.println(node.e);
    inOrder(node.right);
}

// 二分搜索树的后序遍历
public void postOrder(){
    postOrder(root);
}

// 后序遍历以node为根的二分搜索树, 递归算法
private void postOrder(Node node){
    if(node == null)
        return;

    postOrder(node.left);
    postOrder(node.right);
    System.out.println(node.e);
}

层序遍历或广度优先遍历

数据结构学习总结(二)
// 二分搜索树的层序遍历
public void levelOrder(){
    Queue<Node> q = new LinkedList<>();
    q.add(root);
    while(!q.isEmpty()){
        Node cur = q.remove();
        System.out.println(cur.e);

        if(cur.left != null)
            q.add(cur.left);
        if(cur.right != null)
            q.add(cur.right);
    }
}

其他操作

// 寻找二分搜索树的最小元素
public E minimum(){
    if(size == 0)
        throw new IllegalArgumentException("BST is empty!");

    return minimum(root).e;
}

// 返回以node为根的二分搜索树的最小值所在的节点
private Node minimum(Node node){
    if(node.left == null)
        return node;
    return minimum(node.left);
}

// 寻找二分搜索树的最大元素
public E maximum(){
    if(size == 0)
        throw new IllegalArgumentException("BST is empty");

    return maximum(root).e;
}

// 返回以node为根的二分搜索树的最大值所在的节点
private Node maximum(Node node){
    if(node.right == null)
        return node;

    return maximum(node.right);
}

// 从二分搜索树中删除最小值所在节点, 返回最小值
public E removeMin(){
    E ret = minimum();
    root = removeMin(root);
    return ret;
}

// 删除掉以node为根的二分搜索树中的最小节点
// 返回删除节点后新的二分搜索树的根
private Node removeMin(Node node){

    if(node.left == null){
        Node rightNode = node.right;
        node.right = null;
        size --;
        return rightNode;
    }

    node.left = removeMin(node.left);
    return node;
}

// 从二分搜索树中删除最大值所在节点
public E removeMax(){
    E ret = maximum();
    root = removeMax(root);
    return ret;
}

// 删除掉以node为根的二分搜索树中的最大节点
// 返回删除节点后新的二分搜索树的根
private Node removeMax(Node node){

    if(node.right == null){
        Node leftNode = node.left;
        node.left = null;
        size --;
        return leftNode;
    }

    node.right = removeMax(node.right);
    return node;
}

// 从二分搜索树中删除元素为e的节点
public void remove(E e){
    root = remove(root, e);
}

// 删除掉以node为根的二分搜索树中值为e的节点, 递归算法
// 返回删除节点后新的二分搜索树的根
Node remove(Node node, E e){

    if( node == null )
        return null;

    if( e.compareTo(node.e) < 0 ){
        node.left = remove(node.left , e);
        return node;
    }
    else if(e.compareTo(node.e) > 0 ){
        node.right = remove(node.right, e);
        return node;
    }
    else{   // e.compareTo(node.e) == 0

        // 待删除节点左子树为空的情况
        if(node.left == null){
            Node rightNode = node.right;
            node.right = null;
            size --;
            return rightNode;
        }

        // 待删除节点右子树为空的情况
        if(node.right == null){
            Node leftNode = node.left;
            node.left = null;
            size --;
            return leftNode;
        }

        // 待删除节点左右子树均不为空的情况

        // 找到比待删除节点大的最小节点, 即待删除节点右子树的最小节点
        // 用这个节点顶替待删除节点的位置
        Node successor = new Node(minimum(node.right).e);
        size ++;

        successor.right = removeMin(node.right);
        successor.left = node.left;

        node.left = node.right = null;
        size --;
        return successor;
    }
}

3.映射Map

数据结构学习总结(二)

因为Node是一个对象,所以里面存储的内容可以是任意的了,按着需求存储就可以了。通过key找到对应的Node也就能获取对应的value了node.value

时间复杂度

数据结构学习总结(二)
数据结构学习总结(二)

4.集合Set

同理可以使用链表和搜索树来实现,结构保持不变,添加的时候判断一下里面是否有重复的内容。时间复杂度同Map一致。

5.优先队列

数据结构学习总结(二)

实现

数据结构学习总结(二)

线性结构来实现的话是需要根据优先级进行排序是需要遍历的。

6.堆

数据结构学习总结(二)

这里的顺序不是指大小的顺序,是元素从左向右依次一层一层的排列;叶子节点的上一层可能还有叶子节点,但是必须位于该节点的右侧。如果上层没有叶子节点就是满二叉树了,满二叉树也是完全二叉树的一种。

二叉堆的性质(最大堆)

  • 堆中某个节点的值总是不大于其父节点的值,只跟其父节点比较,比如不能拿19跟16比。根节点的值最大。
    28小于41 22小于30

实现

数据结构学习总结(二)

通过父节点的索引可以知道其左子节点和右子节点的索引。

数据结构学习总结(二)

数组0的位置空不空会影响计算公式。

Sift Up(上浮)

数据结构学习总结(二)
1

新添加的元素52,大于其父节点已经不满足性质,要跟其父节点去比较。

数据结构学习总结(二)
2

交换后还不满足,继续比较。

数据结构学习总结(二)
3

直到满足条件。整个过程元素在上浮(Sift Up)

代码实现

public class MaxHeap<E extends Comparable<E>> {

    private Array<E> data;//动态数组

    public MaxHeap(int capacity){
        data = new Array<>(capacity);
    }

    public MaxHeap(){
        data = new Array<>();
    }

    // 返回完全二叉树的数组表示中,一个索引所表示的元素的父亲节点的索引
    private int parent(int index){
        if(index == 0)
            throw new IllegalArgumentException("index-0 doesn't have parent.");
        return (index - 1) / 2;
    }

    // 返回完全二叉树的数组表示中,一个索引所表示的元素的左孩子节点的索引
    private int leftChild(int index){
        return index * 2 + 1;
    }

    // 返回完全二叉树的数组表示中,一个索引所表示的元素的右孩子节点的索引
    private int rightChild(int index){
        return index * 2 + 2;
    }

    // 向堆中添加元素
    public void add(E e){
        data.addLast(e);
        siftUp(data.getSize() - 1);
    }

    private void siftUp(int k){//上浮,添加元素后要满足堆的性质。
        while(k > 0 && data.get(parent(k)).compareTo(data.get(k)) < 0 ){
            data.swap(k, parent(k));//交互索引对应的值
            k = parent(k);
        }
    }
}

Sift Down

数据结构学习总结(二)
1

取出元素的时候,取出根节点(最大),然后将最后一个元素(这里是16)移动到根节点,也就是下标为0的位置,然后下标为10的位置空了。

数据结构学习总结(二)
2

将最后一个元素移动到根节点后,不满足性质时,一次比较它的左子树根节点和右子树根节点,然后一次替换大的元素。

数据结构学习总结(二)
3

替换结束后,52是最大的了放在了根节点没有问题,但是16的位置不满足性质了。继续比较。

数据结构学习总结(二)
4
数据结构学习总结(二)
5

代码实现

// 看堆中的最大元素
public E findMax(){
    if(data.getSize() == 0)
        throw new IllegalArgumentException("Can not findMax when heap is empty.");
    return data.get(0);
}

// 取出堆中最大元素
public E extractMax(){
    E ret = findMax();
    data.swap(0data.getSize() - 1);
    data.removeLast();
    siftDown(0);
    return ret;
}

//下沉
private void siftDown(int k){
    while(leftChild(k) < data.getSize()){
        int j = leftChild(k); // 在此轮循环中,data[k]和data[j]交换位置
        if( j + 1 < data.getSize() &&
                data.get(j + 1).compareTo(data.get(j)) > 0 )
            j ++;//右子树根节点
        // data[j] 是 leftChild 和 rightChild 中的最大值
        if(data.get(k).compareTo(data.get(j)) >= 0 )
            break;
        data.swap(k, j);
        k = j;
    }
}

replace

数据结构学习总结(二)
// 取出堆中的最大元素,并且替换成元素e
public E replace(E e){
    E ret = findMax();
    data.set(0, e);
    siftDown(0);
    return ret;
}

heapify

将任意数组整理成堆的形状

数据结构学习总结(二)
1

首先将数组看成一个完全二叉树,此时可能不满足最大堆的性质,我们从最后一个非叶子节点(蓝色部分为叶子节点)开始执行Sift Down操作。

数据结构学习总结(二)
2
数据结构学习总结(二)
3
数据结构学习总结(二)
4

19和28交换后,28不能Sift Down了然后从17开始

5
public MaxHeap(E[] arr){
    data = new Array<>(arr);
    for(int i = parent(arr.length - 1) ; i >= 0 ; i --) //parent(arr.length - 1) : 最后一个非叶子节点的索引
        siftDown(i);
}

heapify时间复杂度

使用堆实现优先队列

public class PriorityQueue<E extends Comparable<E>> implements Queue<E{

    private MaxHeap<E> maxHeap;

    public PriorityQueue(){
        maxHeap = new MaxHeap<>();
    }

    @Override
    public E getFront(){
        return maxHeap.findMax();
    }

    @Override
    public void enqueue(E e){
        maxHeap.add(e);
    }

    @Override
    public E dequeue(){
        return maxHeap.extractMax();
    }
}


以上是关于数据结构学习总结的主要内容,如果未能解决你的问题,请参考以下文章

java中封装,继承,多态,接口学习总结

Java Web学习总结JSP

201621123054《Java程序设计》第九周学习总结

201621123048《Java程序设计》第九周学习总结

python常用代码片段总结

OpenGL 纹理学习总结