数据结构学习第二天<反转链表><链表删除节点><栈和队列><两个栈实现队列><两个队列实现栈><递归求最大值><哈希表>

反转链表

package Demo02;
​
import java.util.ArrayList;
import java.util.List;
​
public class Code01_ReverseList {
    public static class Node {
        public int value;
        public Node next;
​
        public Node(int data) {
            value = data;
        }
    }
​
    public static class DoubleNode {
        public int value;
        public DoubleNode last;
        public DoubleNode next;
​
        public DoubleNode(int data) {
            value = data;
        }
    }
​
    public static Node reverseLinkedList(Node head) {
        Node pre = null;
        Node next = null;
        while (head != null) {
            next = head.next;
            head.next = pre;//往前指
            pre = head;
            head = next;
        }
        return pre;
    }
​
    public static DoubleNode reverseDoubleList(DoubleNode head) {
        DoubleNode pre = null;
        DoubleNode next = null;
        while (head != null) {
            next = head.next;
            head.next = pre;//往前指
            head.last = next;//往后指
            pre = head;
            head = next;
        }
        return pre;
    }
​
    public static Node testReverseLinkedList(Node head) {
        if (head == null) {
            return null;
        }
        ArrayList<Node> list = new ArrayList<>();
        while (head != null) {
            list.add(head);
            head = head.next;
        }
        list.get(0).next = null;
        int N = list.size();
        for (int i = 1; i < N; i++) {
            list.get(i).next = list.get(i - 1);
        }
        return list.get(N - 1);
    }
​
    public static DoubleNode testReverseDoubleList(DoubleNode head) {
        if (head == null) {
            return null;
        }
        ArrayList<DoubleNode> list = new ArrayList<>();
        while (head != null) {
            list.add(head);
            head = head.next;
        }
        list.get(0).next = null;
        DoubleNode pre = list.get(0);
        int N = list.size();
        for (int i = 1; i < N; i++) {
            DoubleNode cur = list.get(i);
            cur.last = null;
            cur.next = pre;
            pre.last = cur;
            pre = cur;
        }
        return list.get(N - 1);
    }
​
    // for test
    public static Node generateRandomLinkedList(int len, int value) {
        int size = (int) (Math.random() * (len + 1));
        if (size == 0) {
            return null;
        }
        size--;
        Node head = new Node((int) (Math.random() * (value + 1)));
        Node pre = head;
        while (size != 0) {
            Node cur = new Node((int) (Math.random() * (value + 1)));
            pre.next = cur;
            pre = cur;
            size--;
        }
        return head;
    }
​
    // for test
    public static DoubleNode generateRandomDoubleList(int len, int value) {
        int size = (int) (Math.random() * (len + 1));
        if (size == 0) {
            return null;
        }
        size--;
        DoubleNode head = new DoubleNode((int) (Math.random() * (value + 1)));
        DoubleNode pre = head;
        while (size != 0) {
            DoubleNode cur = new DoubleNode((int) (Math.random() * (value + 1)));
            pre.next = cur;
            cur.last = pre;
            pre = cur;
            size--;
        }
        return head;
    }
​
    // for test
    public static List<Integer> getLinkedListOriginOrder(Node head) {
        List<Integer> ans = new ArrayList<>();
        while (head != null) {
            ans.add(head.value);
            head = head.next;
        }
        return ans;
    }
​
    // for test
    public static boolean checkLinkedListReverse(List<Integer> origin, Node head) {
        for (int i = origin.size() - 1; i >= 0; i--) {
            if (!origin.get(i).equals(head.value)) {
                return false;
            }
            head = head.next;
        }
        return true;
    }
​
    // for test
    public static List<Integer> getDoubleListOriginOrder(DoubleNode head) {
        List<Integer> ans = new ArrayList<>();
        while (head != null) {
            ans.add(head.value);
            head = head.next;
        }
        return ans;
    }
​
    // for test
    public static boolean checkDoubleListReverse(List<Integer> origin, DoubleNode head) {
        DoubleNode end = null;
        for (int i = origin.size() - 1; i >= 0; i--) {
            if (!origin.get(i).equals(head.value)) {
                return false;
            }
            end = head;
            head = head.next;
        }
        for (int i = 0; i < origin.size(); i++) {
            if (!origin.get(i).equals(end.value)) {
                return false;
            }
            end = end.last;
        }
        return true;
    }
​
​
    public static void f(Node head) {
        head = head.next;
    }
​
    // for test
    public static void main(String[] args) {
        int len = 50;
        int value = 100;
        int testTime = 100000;
        System.out.println("test begin!");
        for (int i = 0; i < testTime; i++) {
            Node node1 = generateRandomLinkedList(len, value);
            List<Integer> list1 = getLinkedListOriginOrder(node1);
            node1 = reverseLinkedList(node1);
            if (!checkLinkedListReverse(list1, node1)) {
                System.out.println("Oops1!");
            }
​
            Node node2 = generateRandomLinkedList(len, value);
            List<Integer> list2 = getLinkedListOriginOrder(node2);
            node2 = testReverseLinkedList(node2);
            if (!checkLinkedListReverse(list2, node2)) {
                System.out.println("Oops2!");
            }
​
            DoubleNode node3 = generateRandomDoubleList(len, value);
            List<Integer> list3 = getDoubleListOriginOrder(node3);
            node3 = reverseDoubleList(node3);
            if (!checkDoubleListReverse(list3, node3)) {
                System.out.println("Oops3!");
            }
​
            DoubleNode node4 = generateRandomDoubleList(len, value);
            List<Integer> list4 = getDoubleListOriginOrder(node4);
            node4 = reverseDoubleList(node4);
            if (!checkDoubleListReverse(list4, node4)) {
                System.out.println("Oops4!");
            }
​
        }
        System.out.println("test finish!");
​
    }
​
}

链表删除节点

单向链表删除头结点后,head指向第二个时,即便头结点没有断连(只有1指向2,没有2指向1,2顺着能找到3,4...但找不到1),内存也会释放,C++不行(必须调用释放函数),双向链表则不会(2有指向1,能找到1)

package Demo02;
​
public class Code02_DeleteGivenValue {
    public static class Node {
        public int value;
        public Node next;
​
        public Node(int data) {
            this.value = data;
        }
    }
​
    public static Node removeValue(Node head, int num) {
        while (head != null) {
            if (head.value != num) {
                break;
            }
            head = head.next;
        }
        // head来到 第一个不需要删的位置
        Node pre = head;
        Node cur = head;
        //
        while (cur != null) {
            if (cur.value == num) {
                pre.next = cur.next;
            } else {
                pre = cur;
            }
            cur = cur.next;
        }
        return head;
    }
}

栈和队列

栈:先进后出

队列:先进先出

双向链表实现

package Demo02;
​
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;
​
public class Code03_DoubleEndsQueueToStackAndQueue {
    public static class Node<T> {
        public T value;
        public Node<T> last;
        public Node<T> next;
​
        public Node(T data) {
            value = data;
        }
    }
​
    public static class DoubleEndsQueue<T> {
        public Node<T> head;
        public Node<T> tail;
​
        public void addFromHead(T value) {//头部加节点
            Node<T> cur = new Node<T>(value);
            if (head == null) {
                head = cur;
                tail = cur;
            } else {
                cur.next = head;
                head.last = cur;
                head = cur;
            }
        }
​
        public void addFromBottom(T value) {//尾部加节点
            Node<T> cur = new Node<T>(value);
            if (head == null) {
                head = cur;
                tail = cur;
            } else {
                cur.last = tail;
                tail.next = cur;
                tail = cur;
            }
        }
​
        public T popFromHead() {//头部弹出节点
            if (head == null) {
                return null;
            }
            Node<T> cur = head;
            if (head == tail) {
                head = null;
                tail = null;
            } else {
                head = head.next;
                cur.next = null;
                head.last = null;
            }
            return cur.value;
        }
​
        public T popFromBottom() {//尾部弹出节点
            if (head == null) {
                return null;
            }
            Node<T> cur = tail;
            if (head == tail) {
                head = null;
                tail = null;
            } else {
                tail = tail.last;
                tail.next = null;
                cur.last = null;
            }
            return cur.value;
        }
​
        public boolean isEmpty() {
            return head == null;
        }
​
    }
​
    public static class MyStack<T> {//栈
        private DoubleEndsQueue<T> queue;
​
        public MyStack() {
            queue = new DoubleEndsQueue<T>();
        }
​
        public void push(T value) {
            queue.addFromHead(value);
        }//头部压入
​
        public T pop() {
            return queue.popFromHead();
        }//头部弹出
​
        public boolean isEmpty() {
            return queue.isEmpty();
        }
​
    }
​
    public static class MyQueue<T> {//队列
        private DoubleEndsQueue<T> queue;
​
        public MyQueue() {
            queue = new DoubleEndsQueue<T>();
        }
​
        public void push(T value) {
            queue.addFromHead(value);
        }//头部压入
​
        public T poll() {
            return queue.popFromBottom();
        }//尾部弹出
​
        public boolean isEmpty() {
            return queue.isEmpty();
        }
​
    }
​
    public static boolean isEqual(Integer o1, Integer o2) {
        if (o1 == null && o2 != null) {
            return false;
        }
        if (o1 != null && o2 == null) {
            return false;
        }
        if (o1 == null && o2 == null) {
            return true;
        }
        return o1.equals(o2);
    }
​
    public static void main(String[] args) {
        int oneTestDataNum = 100;
        int value = 10000;
        int testTimes = 100000;
        for (int i = 0; i < testTimes; i++) {
            MyStack<Integer> myStack = new MyStack<>();
            MyQueue<Integer> myQueue = new MyQueue<>();
            Stack<Integer> stack = new Stack<>();
            Queue<Integer> queue = new LinkedList<>();
            for (int j = 0; j < oneTestDataNum; j++) {
                int nums = (int) (Math.random() * value);
                if (stack.isEmpty()) {
                    myStack.push(nums);
                    stack.push(nums);
                } else {
                    if (Math.random() < 0.5) {
                        myStack.push(nums);
                        stack.push(nums);
                    } else {
                        if (!isEqual(myStack.pop(), stack.pop())) {
                            System.out.println("oops!");
                        }
                    }
                }
                int numq = (int) (Math.random() * value);
                if (stack.isEmpty()) {
                    myQueue.push(numq);
                    queue.offer(numq);
                } else {
                    if (Math.random() < 0.5) {
                        myQueue.push(numq);
                        queue.offer(numq);
                    } else {
                        if (!isEqual(myQueue.poll(), queue.poll())) {
                            System.out.println("oops!");
                        }
                    }
                }
            }
        }
        System.out.println("finish!");
    }
}

数组实现(固定大小)

栈容易实现

package Demo02;
​
public class Code04_RingArray {
    public static class MyQueue {
        private int[] arr;
        private int pushi;
        private int polli;
        private int size;
        private final int limit;
​
        public MyQueue(int limit) {
            arr = new int[limit];
            pushi = 0;
            polli = 0;
            size = 0;
            this.limit = limit;
        }
​
        public void push(int value) {
            if (size == limit) {
                throw new RuntimeException("栈满了,不能再加了");
            }
            size++;
            arr[pushi] = value;
            pushi = nextIndex(pushi);
        }
​
        public int pop() {
            if (size == 0) {
                throw new RuntimeException("栈空了,不能再拿了");
            }
            size--;
            int ans = arr[polli];
            polli = nextIndex(polli);
            return ans;
        }
​
        public boolean isEmpty() {
            return size == 0;
        }
​
        // 如果现在的下标是i,返回下一个位置
        private int nextIndex(int i) {
            return i < limit - 1 ? i + 1 : 0;
        }
​
    }
​
}

在实现基本功能基础上再实现返回栈中最小元素

pop push getMin时间复杂度都是O(1)

package Demo02;
​
import java.util.Stack;
​
public class Code05_GetMinStack {
    public static class MyStack1 {
        private Stack<Integer> stackData;
        private Stack<Integer> stackMin;
​
        public MyStack1() {
            this.stackData = new Stack<Integer>();
            this.stackMin = new Stack<Integer>();
        }
​
        public void push(int newNum) {
            if (this.stackMin.isEmpty()) {
                this.stackMin.push(newNum);
            } else if (newNum <= this.getmin()) {//当前数小于等于最小栈栈顶,压入,否则不压入
                this.stackMin.push(newNum);
            }
            this.stackData.push(newNum);
        }
​
        public int pop() {
            if (this.stackData.isEmpty()) {
                throw new RuntimeException("Your stack is empty.");
            }
            int value = this.stackData.pop();
            if (value == this.getmin()) {
                this.stackMin.pop();
            }
            return value;
        }
​
        public int getmin() {
            if (this.stackMin.isEmpty()) {
                throw new RuntimeException("Your stack is empty.");
            }
            return this.stackMin.peek();
        }
    }
​
    public static class MyStack2 {
        private Stack<Integer> stackData;
        private Stack<Integer> stackMin;
​
        public MyStack2() {
            this.stackData = new Stack<Integer>();
            this.stackMin = new Stack<Integer>();
        }
​
        public void push(int newNum) {
            if (this.stackMin.isEmpty()) {
                this.stackMin.push(newNum);
            } else if (newNum < this.getmin()) {//当前的数小于最小栈的栈顶
                this.stackMin.push(newNum);//最小栈压入当前数
            } else {
                int newMin = this.stackMin.peek();//否则最小栈重复压入栈顶
                this.stackMin.push(newMin);
            }
            this.stackData.push(newNum);//Data栈正常压入
        }
​
        public int pop() {
            if (this.stackData.isEmpty()) {
                throw new RuntimeException("Your stack is empty.");
            }
            this.stackMin.pop();//弹出最小数
            return this.stackData.pop();//同步弹出Data栈顶
        }
​
        public int getmin() {
            if (this.stackMin.isEmpty()) {
                throw new RuntimeException("Your stack is empty.");
            }
            return this.stackMin.peek();
        }
    }
​
    public static void main(String[] args) {
        MyStack1 stack1 = new MyStack1();
        stack1.push(3);
        System.out.println(stack1.getmin());
        stack1.push(4);
        System.out.println(stack1.getmin());
        stack1.push(1);
        System.out.println(stack1.getmin());
        System.out.println(stack1.pop());
        System.out.println(stack1.getmin());
​
        System.out.println("=============");
​
        MyStack1 stack2 = new MyStack1();
        stack2.push(3);
        System.out.println(stack2.getmin());
        stack2.push(4);
        System.out.println(stack2.getmin());
        stack2.push(1);
        System.out.println(stack2.getmin());
        System.out.println(stack2.pop());
        System.out.println(stack2.getmin());
    }
}

两个栈实现队列

package Demo02;
​
import java.util.Stack;
​
public class Code06_TwoStacksImplementQueue {
    public static class TwoStacksQueue {
        public Stack<Integer> stackPush;
        public Stack<Integer> stackPop;
​
        public TwoStacksQueue() {
            stackPush = new Stack<Integer>();
            stackPop = new Stack<Integer>();
        }
​
        // push栈向pop栈倒入数据
        private void pushToPop() {
            if (stackPop.empty()) {//原则1 必须POP栈为空的时候
                while (!stackPush.empty()) {//原则2 Push栈一定要倒空才能停
                    stackPop.push(stackPush.pop());//一个进一个出
                }
            }
        }
​
        public void add(int pushInt) {
            stackPush.push(pushInt);
            pushToPop();//先看看能不能导,不妨碍
        }
​
        public int poll() {
            if (stackPop.empty() && stackPush.empty()) {
                throw new RuntimeException("Queue is empty!");
            }
            pushToPop();//先看看能不能导,不妨碍
            return stackPop.pop();
        }
​
        public int peek() {
            if (stackPop.empty() && stackPush.empty()) {
                throw new RuntimeException("Queue is empty!");
            }
            pushToPop();//先看看能不能导,不妨碍
            return stackPop.peek();
        }
    }
​
    public static void main(String[] args) {
        TwoStacksQueue test = new TwoStacksQueue();
        test.add(1);
        test.add(2);
        test.add(3);
        System.out.println(test.peek());
        System.out.println(test.poll());
        System.out.println(test.peek());
        System.out.println(test.poll());
        System.out.println(test.peek());
        System.out.println(test.poll());
    }
}

两个队列实现栈

package Demo02;
​
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;
​
public class Code07_TwoQueueImplementStack {
    public static class TwoQueueStack<T> {
        public Queue<T> queue;
        public Queue<T> help;
​
        public TwoQueueStack() {
            queue = new LinkedList<>();
            help = new LinkedList<>();
        }
​
        public void push(T value) {
            queue.offer(value);
        }
​
        public T poll() {
            while (queue.size() > 1) {
                help.offer(queue.poll());
            }
            T ans = queue.poll();
            Queue<T> tmp = queue;
            queue = help;
            help = tmp;
            return ans;
        }
​
        public T peek() {
            while (queue.size() > 1) {
                help.offer(queue.poll());
            }
            T ans = queue.poll();
            help.offer(ans);
            Queue<T> tmp = queue;
            queue = help;
            help = tmp;
            return ans;
        }
​
        public boolean isEmpty() {
            return queue.isEmpty();
        }
​
    }
​
    public static void main(String[] args) {
        System.out.println("test begin");
        TwoQueueStack<Integer> myStack = new TwoQueueStack<>();
        Stack<Integer> test = new Stack<>();
        int testTime = 1000000;
        int max = 1000000;
        for (int i = 0; i < testTime; i++) {
            if (myStack.isEmpty()) {
                if (!test.isEmpty()) {
                    System.out.println("Oops");
                }
                int num = (int) (Math.random() * max);
                myStack.push(num);
                test.push(num);
            } else {
                if (Math.random() < 0.25) {
                    int num = (int) (Math.random() * max);
                    myStack.push(num);
                    test.push(num);
                } else if (Math.random() < 0.5) {
                    if (!myStack.peek().equals(test.peek())) {
                        System.out.println("Oops");
                    }
                } else if (Math.random() < 0.75) {
                    if (!myStack.poll().equals(test.pop())) {
                        System.out.println("Oops");
                    }
                } else {
                    if (myStack.isEmpty() != test.isEmpty()) {
                        System.out.println("Oops");
                    }
                }
            }
        }
​
        System.out.println("test finish!");
​
    }
}

递归求最大值

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

a子函数个数 b几分 d剩下行为复杂度因子

1.log b a >d O(N^log b a)

2.log b a <d O(N^d) 常见a=b O(1)

3.log b a =d O(N^d *log N)

package Demo02;
​
public class Code08_GetMax {
    // 求arr中的最大值
    public static int getMax(int[] arr) {
        return process(arr, 0, arr.length - 1);
    }
​
    // arr[L..R]范围上求最大值  L ... R   N
    public static int process(int[] arr, int L, int R) {
        if (L == R) { // arr[L..R]范围上只有一个数,直接返回,base case
            return arr[L];
        }
        int mid = L + ((R - L) >> 1); // 中点    1
        int leftMax = process(arr, L, mid);
        int rightMax = process(arr, mid + 1, R);
        return Math.max(leftMax, rightMax);
    }
}

哈希表

package Demo02;
​
import java.util.HashMap;
import java.util.HashSet;
import java.util.TreeMap;
​
public class HashMapAndSortedMap {
​
        public static class Node{
            public int value;
            public Node(int v) {
                value = v;
            }
        }
​
        public static void main(String[] args) {
            // UnSortedMap C++里的哈希表
            HashMap<Integer, String> map = new HashMap<>();//K-V
            map.put(1000000, "我是1000000");
            map.put(2, "我是2");
            map.put(3, "我是3");
            map.put(4, "我是4");
            map.put(5, "我是5");
            map.put(6, "我是6");
            map.put(1000000, "我是1000001");
​
            System.out.println(map.containsKey(1));//有无加入1的记录
            System.out.println(map.containsKey(10));
​
            System.out.println(map.get(4));//查Value
            System.out.println(map.get(10));//无记录返回null
​
            map.put(4, "他是4");//更新V
            System.out.println(map.get(4));
​
            map.remove(4);//除去
            System.out.println(map.get(4));//null
​
​
​
            //       key
            HashSet<String> set = new HashSet<>();
            set.add("abc");
            set.contains("abc");//是否存在
            set.remove("abc");
​
            // 哈希表,增、删、改、查,在使用时,复杂度O(1)
​
​
            System.out.println("=====================");
​
​
            int a = 100000;
            int b = 100000;
            System.out.println(a == b);
​
            Integer c = 100000;
            Integer d = 100000;
            System.out.println(c.equals(d));//==引用传递 equal比较值
​
            Integer e = 127;  //  - 128  ~  127 此范围内是值传递
            Integer f = 127;
            System.out.println(e == f);
​
            //哈西表里一律值传递
​
            HashMap<Node, String> map2 = new HashMap<>();
            Node node1 = new Node(1);
            Node node2 = node1;
            map2.put(node1, "我是node1");
            map2.put(node2, "我是node1");
            System.out.println(map2.size());//1  非基础类型K 引用传递
​
            System.out.println("======================");
            //有序表(按序组织)
            TreeMap<Integer, String> treeMap = new TreeMap<>();
​
            treeMap.put(3, "我是3");
            treeMap.put(4, "我是4");
            treeMap.put(8, "我是8");
            treeMap.put(5, "我是5");
            treeMap.put(7, "我是7");
            treeMap.put(1, "我是1");
            treeMap.put(2, "我是2");
​
            System.out.println(treeMap.containsKey(1));
            System.out.println(treeMap.containsKey(10));
​
            System.out.println(treeMap.get(4));
            System.out.println(treeMap.get(10));
​
            treeMap.put(4, "他是4");
            System.out.println(treeMap.get(4));
​
            treeMap.remove(4);
            System.out.println(treeMap.get(4));
​
            System.out.println(treeMap.firstKey());//最小的K
            System.out.println(treeMap.lastKey());
            // <= 4
            System.out.println(treeMap.floorKey(4));//<=4 离4最近的K
            // >= 4
            System.out.println(treeMap.ceilingKey(4));//>=4 离4最近的K
​
            // O(logN)
​
        }
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值