数据结构课程笔记总结3 -链表结构、栈、队列、递归行为、哈希表和有序表

一 链表

1.链表结构
(1)单向链表节点结构

public class Node{
        private int value;
        private Node next;
        public Node(int data){
            
        }
    }

(2)双向链表节点结构

public class DoubleNode {
        private int data;
        private DoubleNode last;
        private DoubleNode next;

        public DoubleNode(int data) {

        }
    }
  1. 链表反转
    (1)单链表反转
public Node reverseList(Node head) {
        Node pre = null;
        Node next = null;
        while (head != null) {
            next = head.next;
            head.next = pre;
            pre = head;
            head = next;
        }
        return pre;
    }

(2)双链表反转

    public DoubleNode reverseDoubleNode(DoubleNode head){
        DoubleNode pre = null;
        DoubleNode next = null;
        while (head!=null){
            next = head.next;
            head.next = pre;
            head.pre = next;
            pre = head;
            head = next;
        }
        return pre;
    }
  1. 删除给定的值
    示例
    思路:先看头部是否需要删掉,先遍历链表,找到第一个不满足要求的头部。将此头部作为最终的头部。接着遍历链表,去除满足要求的节点。最后返回头部节点。
public Node removeSpecialNode(Node head, int key) {
        while (head != null) {
            if (head.value != key) {
                break;
            } else {
                head = head.next;
            }
        }
        Node pre = head;
        Node cur = head;
        while (cur!=null){
            if(cur.value==key){
                pre.next=cur.next;
            }else{
                pre = cur;
            }
            cur = cur.next;
        }
        return head;
    }

二 栈和队列


  1. 数据先进后出
    栈
    2.队列
    数据先进先出
    队列
    2.链表实现栈和队列
    (1)双向链表实现栈
    头插法,每次新增数据,就在头部加一个节点。从头进,从头出。
    (2)双向链表实现队列
    从头部插入,尾部去除,有个tail指针,永远指向尾部
    3.数组实现栈和队列
    3.1 固定长度数组实现栈
    有一个index,放完数据index++,减少数据就取–index的数据
    3.2 数组实现队列
    环形数组
    两个指针,一个是尾指针,指向在队列里存在时间最长的数据的index。一个头指针,指向新加入的数据的index
public MyQueue(int limit) {
            this.arr = new int[limit];
            this.push = 0;
            this.pop = 0;
            this.limit = limit;
            this.size = 0;
        }

        public void push(int value) {
            if (size == limit) {
                throw new RuntimeException("The Queue is full.");
            }
            arr[push] = value;
            size++;
            push = (push + 1) % limit;
        }

        public int pop() {
            if (size == 0) {
                throw new RuntimeException("The Queue is empty.");
            }
            int value = arr[pop];
            size--;
            pop = (pop + 1) % limit;
            return value;
        }
  1. 常见面试题
    4.1 怎么使用数组实现不超过固定大小的栈和队列?
    栈:正常使用
    队列:循环数组
    4.2 实现一个特殊的栈,在基本功能的基础上,再实现返回栈中最小元素的功能
    (1) pop, push, getMin操作的时间复杂度都是O(1)
    (2) 设计的栈类型可以使用现成的栈结构
    注意:返回栈中最小元素,是指无论栈中有多少个元素,都要返回最小的
public class MyStack {
    private Stack<Integer> dataSatck;
    private Stack<Integer> minStack;

    public MyStack(){
        this.dataSatck = new Stack<>();
        this.minStack = new Stack<>();
    }

    public void push(int value){
        if(minStack.empty() || value<minStack.peek()){
            minStack.push(value);
        }else{
            minStack.push(minStack.peek());
        }
        dataSatck.push(value);
    }

    public int pop(){
        if(dataSatck.empty()){
            throw new RuntimeException("The stack is empty. Can't pop data");
        }
        minStack.pop();
        return dataSatck.pop();
    }

    public int getMinNumber(){
        if(minStack.empty()){
            throw new RuntimeException("The stack is empty. Don't has min number.");
        }
        return minStack.peek();
    }
}

(3) 如何用栈实现队列结构?
pop栈为空,才能将push栈导入pop, push栈导入到pop栈时,必须一次性倒完。
用栈实现队列

public class TwoStackToQueue {
    private Stack<Integer> push;
    private Stack<Integer> pop;

    public TwoStackToQueue(){
        this.pop = new Stack<>();
        this.push = new Stack<>();
    }

    public void push(int value){
        push.push(value);
    }

    public int pop(){
        if(pop.empty()){
            while (!push.empty()){
                pop.push(push.pop());
            }
            return pop.pop();
        }else {
            return pop.pop();
        }
    }
}

(4)如何用队列实现栈结构?
使用两个队列,倒着来,每次留下最后一个数,作为返回值。
假设有两个队列,data与help。此时data里已经按顺序进入了1,2,3,4,5五个数字。第一轮,将1,2,3,4依次出队列进入help队列,5弹出。第二轮help里的1,2,3依次进入data队列,4弹出。
队列实现栈

public class TwoQueueToStack {
    private Queue<Integer> queue1;
    private Queue<Integer> queue2;
    private boolean isQueue1;

    public TwoQueueToStack(){
        this.queue1 = new LinkedList<>();
        this.queue2 = new LinkedList<>();
        isQueue1 = true;
    }

    public void push(int value){
        if(isQueue1){
            queue1.add(value);
        }else{
            queue2.add(value);
        }
    }

    public int pop() {
        int result;
        if (isQueue1) {
            if (queue1.isEmpty()) {
                throw new RuntimeException("The stack is empty, can't pop data");
            }
            result = queue1.poll();
            while (!queue1.isEmpty()) {
                queue2.add(result);
                result = queue1.poll();
            }
            isQueue1 = false;
        } else {
            if (queue2.isEmpty()) {
                throw new RuntimeException("The stack is empty, can't pop data");
            }
            result = queue2.poll();
            while (!queue2.isEmpty()) {
                queue1.add(result);
                result = queue2.poll();
            }
            isQueue1 = true;
        }
        return result;
    }
}

三 递归

示例:用递归方法求一个数组arr[L…R]中的最大值
(1) 将[L…R]范围分为左右两半。左:[L…Mid],右[mid+1…R]
(2) 左部分求最大值,右部分求最大值
(3) [L…R]范围上的最大值,是max{左部分最大值,右部分最大值}
注意: (2) 是个递归过程,当范围上只有一个数,就可以不用再递归了

 public static void main(String[] args) {
        int[] arr = new int[]{2,4,7,5,8,3};
        int value = findMaxNumber(arr,0,arr.length-1);
        System.out.println(value);
    }

    private static int findMaxNumber(int[] arr, int left, int right){
        if(left==right){
            return arr[left];
        }else{
            int mid = left+(right-left)/2;
            int leftMax = findMaxNumber(arr,0,mid);
            int rightMax = findMaxNumber(arr,mid+1,right);
            return Math.max(leftMax,rightMax);
        }
    }



T(N) = a*T(N/b)+O(N^d)
复杂度

数据量为N,b为子问题递归的规模,因此每次都把数据集分为两半,所以b=2。子问题规模一样,调用了子问题a次,如代码中,调用了两次findMaxNumber,所以a=2。子问题其他复杂度为d,比如输出值时,时间复杂度为O(N), 所以d=1。
对于上面的代码,a=2,因为leftMax和rightMa,两次。每次都是求mid,L…R分为两部分,所以b=2
Master公式

四 哈希表

对于哈希表
HashMap, HashSet,认为增删改查操作,都为O(1)
treeMap, treeSet(里面的值按序排序),认为增删改查,都为logN
Note
java基础类型与String按值传递, String传递的是空间地址的值。
除了基础类型之外的类型是按引用传递。对于Integer,当值范围为-127到127时,按值传递。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值