数据结构笔记

Chapter 1 简介

在这里插入图片描述
在这里插入图片描述

Chapter 2 数组

三种初始化方法:
1.int[] a = new int[100];
2.int[] a = new int[]{1, 2, 3};
3.int[] a = {1, 2, 3};

动态数组

private void resize(int newCapacity) {
   
    E[] newData = (E[])new Object[newCapacity];
    for (int i = 0; i < size; i++)
        newData[i] = data[i];
    data = newData;//指向重定义尺寸的数组
}

时间复杂度分析

在这里插入图片描述
均摊情况下,resize的复杂度为O(1),addLast时间复杂度O(1),removeLast时间复杂度O(1)

复杂度震荡

在这里插入图片描述
解决:Lazy

if (size == data.length / 4 && data.length / 2 != 0)
    resize(data.length / 2);
return result;

Chapter 3 栈和队列

线性结构,只能在栈顶进行添加和删除——Last In First Out
应用:Undo、程序调用的系统栈
栈的实现

interface Stack<E>
void push(E)
E pop()
E peek()
int getSize()
boolean isEmpty()

在这里插入图片描述

括号匹配

栈顶元素反应了在嵌套的层次关系中,最近的需要匹配的元素

public boolean isValid(String s){
   
    
    Stack<Character> stack = new Stack<>();
    for (int i = 0; i < s.length(); i ++){
   
        char c = s.charAt(i);
        if (c == '(' || c == '[' || c == '{')
            stack.push(c);
        else {
   
            if (stack.isEmpty())
                return false;
            
            char topChar = stack.pop();
            if (c == ')' && topChar != '(')
                return false;
            if (c == ']' && topChar != '[')
                return false;
            if (c == '}' && topChar != '{')
                return false;
        }
    }
    
    return stack.isEmpty();
    
}

队列

线性结构,只能在队尾添加元素,在队首取出元素——First In First Out
队列的实现

interface Queue<E>
void enqueue(E)
E dequeue()
E getFront()
int getSize()
boolean isEmpty()

在这里插入图片描述

循环队列

front指向队首,tail指向队尾元素后一个位置
front == tail, 队列为空;
(tail + 1) % c == front, 队列满
注:capacity中,浪费一个空间
在这里插入图片描述

public class LoopQueue<E> implements Queue<E> {
   

    private E[] data;
    private int front, tail;
    private int size;

    public LoopQueue(int capacity){
   
        data = (E[])new Object[capacity + 1];
        front = 0;
        tail = 0;
        size = 0;
    }

    public LoopQueue(){
   
        this(10);
    }

    public int getCapacity(){
   
        return data.length - 1;
    }

    @Override
    public int getSize() {
   
        return size;
    }

    @Override
    public boolean isEmpty() {
   
        return front == tail;
    }

    private void resize(int newCapacity){
   
        E[] newData = (E[])new Object[newCapacity + 1];
        for (int i = 0; i < size; i++)
            newData[i] = data[(front + i) % data.length];

        data = newData;
        front = 0;
        tail = size;
    }

    @Override
    public void enqueue(E e) {
   

        if ((tail + 1) % data.length == front)
            resize(getCapacity() * 2);//不用length,因为天然浪费一个位置

        data[tail] = e;
        tail = (tail + 1) % data.length;
        size ++;

    }

    @Override
    public E dequeue() {
   

        if (isEmpty())
            throw new IllegalArgumentException("cannot dequeue from an empty queue!");

        E ret = data[front];
        data[front] = null;
        front = (front + 1) % data.length;
        size --;
        if (size == getCapacity() / 4 && getCapacity() / 2 != 0)
            resize(getCapacity() / 2);

        return ret;
    }

    @Override
    public E getFront() {
   
        if (isEmpty())
            throw new IllegalArgumentException("queue is empty!");

        return data[front];
    }

    @Override
    public String toString(){
   

        StringBuilder res = new StringBuilder();
        res.append(String.format("Queue: size = %d, capacity = %d\n", size, getCapacity()));
        res.append("front [");
        for (int i = front; i != tail; i = (i + 1) % data.length){
   
            res.append(data[i]);
            if ((i + 1) % data.length != tail)
                res.append(", ");
        }
        res.append("] tail");
        return res.toString();

    }
}

在这里插入图片描述

数组队列和循环队列的比较

在这里插入图片描述

Chapter 4 链表

线性数据结构

在这里插入图片描述
在这里插入图片描述
优点:真正动态,不需要处理固定容量的问题
缺点:丧失了随机访问的能力
在这里插入图片描述

链表的节点

private class Node{
   
    public E e;
    public Node next;

    public Node(E e, Node next){
   
        this.e = e;
        this.next = next;
    }

    public Node(E e){
   
        this(e, null);
    }

    public Node(){
   
        this(null, null);
    }

    @Override
    public String toString(){
   
        return e.toString();
    }
}

为链表添加元素

//在链表中间index(0-based)位置添加元素e
    public void add(int index, E e){
   
        if (index < 0 || index > size)
            throw new IllegalArgumentException("add failed, illegal index");

            Node prev = dummyHead;
            for (int i = 0; i < index; i++)
                prev = prev.next;

//            Node node = new Node(e);
//            node.next = prev.next;
//            prev.next = node;
            prev.next = new Node(e, prev.next);
            size ++;
    }

    //在链表头添加元素e
    public void addFirst(E e){
   
//        Node node = new Node(e);
//        node.next = head;
//        head = node;
        add(0, e);
    }

    //在链表末尾添加元素e
    public void addLast(E e){
   
        add(size, e);
    }

在这里插入图片描述
在这里插入图片描述
:顺序不能颠倒

为链表设立虚拟头结点

在这里插入图片描述

从链表中删除元素

//从链表中删除index(0-based)位置的元素,返回删除的元素
public E remove(int index){
   
    if (index < 0 || index > size)
        throw new IllegalArgumentException("remove failed, illegal index");

    Node prev = dummyHead;
    for (int i = 0; i < index; i++){
   
        prev = prev.next;
    }
    Node retNode = prev.next;

    prev.next = retNode.next;
    retNode.next = null;
    size --;

    return retNode.e;
}

public E removeFirst(){
   
    return remove(0);
}
public E removeLast(){
   
    return remove(size - 1);
}

在这里插入图片描述

其他操作

//获得链表第index(0-based)个位置的元素
public E get(int index){
   
    if (index < 0 || index > size)
        throw new IllegalArgumentException("add failed, illegal index");

    Node cur = dummyHead.next;
    for (int i = 0; i < index; i++)
        cur = cur.next;
    return cur.e;
}

//获得链表第一个元素
public E getFirst(){
   
    return get(0);
}

//获得链表最后一个元素
public E getLast(){
   
    return get(size - 1);
}

//修改链表第index(0-based)个位置的元素为e
public void set(int index, E e){
   
    if (index < 0 || index > size)
        throw new IllegalArgumentException("set failed, illegal index");

    Node cur = dummyHead.next;
    for (int i = 0; i < index; i++)
        cur = cur.next;
    cur.e = e;
}

//查找链表中是否有元素e
public boolean contains(E e){
   
    Node cur = dummyHead.next;
    while (cur != null){
   
        if (cur.e.equals(e))
            return true;
        cur = cur.next;
    }
    return false;
}

时间复杂度分析

增删改查:O(n)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

使用链表实现栈

将链表头做为栈顶

public class LinkedListStack<E> implements Stack<E> {
   

    private LinkedList<E> list;

    public LinkedListStack(){
   
        list = new LinkedList<E>();
    }

    @Override
    public int getSize() {
   
        return list.getSize();
    }

    @Override
    public boolean isEmpty() {
   
        return list.isEmpty();
    }

    @Override
    public E pop() {
   
        return list.removeFirst();
    }

    @Override
    public void push(E e) {
   
        list.addFirst(e);
    }

    @Override
    public E peek() {
   
        return list.getFirst();
    }
 }

带有尾指针的链表:使用链表实现队列

在这里插入图片描述
注:由于没有dummyHead,要注意链表为空的情况

public class LinkedListQueue<E> implements Queue<E> {
   

    private class Node{
   
        public E e;
        public Node next;

        public Node(E e, Node next){
   
            this.e = e;
            this.next = next;
        }

        public Node(E e){
   
            this(e, null);
        }

        public Node(){
   
            this(null, null);
        }

        @Override
        public String toString(){
   
            return e.toString();
        }
    }

    private Node head, tail;
    private int size;

    public LinkedListQueue(){
   
        head = null;
        tail = null;
        size = 0;
    }

    @Override
    public int getSize() {
   
        return size;
    }

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

    @Override
    public void enqueue(E e) {
   
        if (tail == null){
   
            tail = new Node(e);
            head = tail;
        }else {
   
            tail.next = new Node(e);
            tail = tail.next;
        }
        size ++;
    }

    @Override
    public E dequeue() {
   
        if (isEmpty())
            throw new IllegalArgumentException("cannot dequeue from a empty queue");

        Node retNode = head;
        head = head.next;
        retNode.next = null;

        if (head == null)//队列中只有一个元素的情况
            tail = null;
        size --;

        return retNode.e;
    }

    @Override
    public E getFront() {
   
        if (isEmpty())
            throw new IllegalArgumentException("queue is empty");
        return head.e;
    }

    @Override
    public String toString(){
   
        StringBuilder res = new StringBuilder();
        res.append("Queue: front");

        Node cur = head;
        while (cur != null){
   
            res.append(cur + "->");
            cur = cur.next;
        }

        res.append("null tail");
        return res.toString();
    }

}

Chapter 5 链表与递归

删除单链表中所有val元素

解法一

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */

public class Solution {
   

    public ListNode removeElements(ListNode head, int val){
   

        while (head != null && head.val == val){
   
            //head = head.next;
            ListNode delNode = head;
            head = head.next;
            delNode.next = null;
        }

        if (head == null)
            return null;

        ListNode prev = head;
        while (prev.next != null){
   

            if (prev.next.val == val){
   
                //prev.next = prev.next.next;
                ListNode delNode = prev.next;
                prev.next = delNode.next;
                delNode.next = null;
            }else {
   
                prev = prev.next;
            }

        }

        return head;

    }

}

解法二——使用虚拟头结点

public class Solution2 {
   

    public ListNode removeElements(ListNode head, int val){
   

        //创建虚拟头结点
        ListNode dummyHead = new ListNode(-1);
        dummyHead.next = head;
        
        ListNode prev = dummyHead;
        while (prev.next != null){
   
            if (prev.next.val == val){
   
                //prev.next = prev.next.next;
                ListNode delNode = prev.next;
                prev.next = delNode.next;
                delNode.next = null;
            } else {
   
                prev = prev.next;
            }
        }
        
        return dummyHead.next;

    }
}

链表和递归

本质:将原来的问题,转化为更小的同一问题
例:

public class Sum {
   

    public static int sum(int[] arr){
   
        return sum(arr, 0);
    }

    private static int sum(int[] arr, int l){
   
        //求解基本问题
        if (l == arr.length)
            return 0;
        //把原问题转化成更小的问题
        return arr[l] + sum(arr, l + 1);
    }

    public static void main(String[] args) {
   

        int[] nums = {
   1, 2, 3, 4, 5, 6, 7, 8};
        System.out.println(sum(nums));

    }

}

在这里插入图片描述
解法三——删除链表中所有val

public class Solution3 {
   

    public ListNode removeElements(ListNode head, int val){
   

        if (head == null)
            return null;

        //res是head后跟的链表删除val后的结果
        head.next = removeElements(head.next, val);
//        if (head.val == val){
   
//            //head需要删除,返回head后跟的链表删除val后的结果
//            return head.next;
//        }else {
   
//            //head不需要删除
//            return head;
//        }
        return head.val == val ? head.next : head;

    }

递归运行机制

在这里插入图片描述
递归调用是有代价的:函数调用+系统栈空间

递归算法的调试

在这里插入图片描述

更多问题

双链表

class Node{
   
	E e;
	Node next, prev;
}

在这里插入图片描述
循环链表

class Node{
   
	E e;
	Node next, prev;
}

在这里插入图片描述
数组链表

class Node{
   
	E e;
	int next;
}

在这里插入图片描述

Chapter 6 二分搜索树

二叉树

动态数据结构具有天然递归结构(左子树,右子树)

class Node {
   
	E e;
	Node left;
	Node right;
}

二叉树是递归定义的,逻辑上二叉树有5中基本形态:

·空二叉树
·只有一个根节点的二叉树
·只有左子树
·只有右子树
·完全二叉树

在这里插入图片描述
满二叉树完全二叉树

二分搜索树(Binary Search Tree)

·二分搜索树是二叉树
·二分搜索树的每个节点的值:
   ·大于其左子树所有节点的值
   ·小于其右子树所有节点的值
·二分搜索树的每一棵子树也是二分搜索树

注:存储的元素必须有可比较性: BST<E extends Comparable>

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;
    }
    
}

1.BST添加新元素

//向BST添加新元素e
public void add(E e){
   

    if (root == null){
   
        root = new Node(e);
        size ++;
    }else {
   
        add(root, e);
    }

}

//向以node为根的BST插入元素e,递归算法
private void add(Node node, E e){
   

    //递归终止条件
    if (e.equals(node.e)) 
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值