算法基础(3)

141 阅读5分钟

1.单、双链表结构,以及对链表的反转、删除链表中的某个值

双链表节点结构:

public class DoubleNode {
    int value;
    public DoubleNode before;
    public DoubleNode next;

    public DoubleNode(int value) {
        this.value = value;
    }
}

单链表节点结构:

public class Node {
    int value;
    public Node next;
    public Node(int value){
        this.value = value;
    }
}

示例代码(我写的草稿不太完善):

public class Reverse {
    //单链表反转
    public static Node reverse(Node head){
        Node pre = null;
        Node next = null;
        while (head != null) {
            next = head.next; // 记录head的下一个节点
            head.next = pre;
            pre = head; //记录此时的头节点
            head = next; //往下一个节点跳
        }
        return pre;
    }

    //双链表反转
    public static DoubleNode reverse(DoubleNode head){
        DoubleNode pre = null;
        DoubleNode next = null;
        while (head != null){
            next = head.next; //记录head的下一个节点
            head.next = pre;
            head.before = next;
            pre = head;
            head = next;
        }
        return pre;
    }

    //删除单链表的一个值
    //TODO: 这需要写出删除所有相同的值
    public static Node delete(Node head,int num){
        Node pre = null;
        Node newHead = head;
        if(head == null){
            return newHead;
        }
        while (head!=null){
            if(head.value == num){
                if(pre!=null) {
                    pre.next = head.next;
                    head.next = null;
                    return newHead;
                }

                if(pre == null){
                    pre = head.next;
                    head.next = null;
                    return pre;
                }

            }
            pre = head;
            head = head.next;
        }
        return newHead;
    }


    //删除双链表的一个值
    //TODO: 这需要写出删除所有相同的值
    public static DoubleNode delete(DoubleNode head,int num){
        DoubleNode newHead = head;
        DoubleNode preHead = null;
        DoubleNode afterHead = null;
        while (head!=null){
            if(head.value==num){
                if(preHead != null){
                    if(head.next!=null) {
                        afterHead = head.next;
                        afterHead.before = preHead;
                    }
                    preHead.next = afterHead;
                    head.before = null;
                    head.next = null;
                    return newHead;
                }

                if(preHead == null){
                    newHead = head.next;
                    head.next = null;
                    newHead.before = null;
                    return newHead;
                }
            }
            preHead = head;
            head = head.next;
        }
        return newHead;
    }

    //打印单链表
    public static void print(Node head){
        Node next = head;
        while (next!=null){
            System.out.println(next.value);
            next = next.next;
        }
    }
    //打印双链表
    public static void print1(DoubleNode head){
        DoubleNode next = head;
        while (next!=null){
            System.out.println(next.value);
            next = next.next;
        }
    }

    public static void main(String[] args) {
        Node node1 = new Node(1);
        Node node2 = new Node(2);
        Node node3 = new Node(3);
        node1.next = node2;
        node2.next = node3;
        print(node1);
        Node reverse = delete(node1,3);
        System.out.println("反转后....");
        print(reverse);

        DoubleNode node4 = new DoubleNode(1);
        DoubleNode node5 = new DoubleNode(2);
        DoubleNode node6 = new DoubleNode(3);
        node4.before = null;
        node4.next = node5;

        node5.before = node4;
        node5.next = node6;

        node6.before = node5;
        node6.next = null;

        System.out.println("========================================");
        print1(node4);
        DoubleNode reverse1 = delete(node4,2);
        System.out.println("反转后....");
        print1(reverse1);
    }
}

2.我们要明白计算机底层的真实物理数据结构只有数组和链表,其他任何数据结构都是假的,都是人为造的,都是通过数组和链表来实现的一种合金结构。

分别用双向链表和数组实现栈和队列:

双向链表:

public class MyLinked {
    public DoubleNode head = null;
    public DoubleNode tail = null;

    //从头部增加一个数
    public void addFromHead(int num){
        if(head == null){
            DoubleNode node = new DoubleNode(num);
            head = node;
            tail = node;
        }else{
            DoubleNode node = new DoubleNode(num);
            node.next = head;
            head.before = node;
            head = node;
        }
    }

    //从尾部增加一个数
    public void addFromTail(int num){
        if(head == null){
            DoubleNode node = new DoubleNode(num);
            head = node;
            tail = node;
        }else{
            DoubleNode node = new DoubleNode(num);
            tail.next = node;
            node.before = tail;
            tail = node;
        }
    }

    //从头部删除一个数
    public void deleteFromHead(){
        if(head != null){
            DoubleNode next = head.next;
            next.before = null;
            head.next = null;
            head = next;
        }
    }

    //从尾部删除一个数,想找到尾部节点的上一个节点,单链表比较复杂,因此采用双链表
    public void deleteFromTail(){
        if(head != null){
            DoubleNode before = tail.before;
            before.next = null;
            tail.before = null;
            tail = before;
        }
    }
}

用双向链表实现栈和队列:

//用链表和数组实现队列
public class MyQueue {
    private static MyLinked myLinked = new MyLinked();

    //队列,从尾部进,从头部出,先进先出

    public void add(int num){
        myLinked.addFromTail(num);
    }

    public void pop(){
        myLinked.deleteFromHead();
    }
}
//用链表和数组实现栈
public class MyStack {
    private static MyLinked myLinked = new MyLinked();

    //栈,从尾部进,从尾部出,先进后出

    public void add(int num){
        myLinked.addFromTail(num);
    }

    public void pop(){
        myLinked.deleteFromTail();
    }
}

用数组实现栈和队列(写了个草稿不完善):

//TODO: 这需要写成一个环形数组
public class MyQueue1 {
    private static int[] innerArr = {};
    private int head;
    private int tail;

    public void add(int num){
        innerArr[tail] = num;
        tail++;
    }

    public int pop(){
        int num = innerArr[head];
        head--;
        return num;
    }
}
public class MyStack1 {
    private static int[] innerArr = {};
    private int index;

    public void add(int num){
        innerArr[index] = num;
        index++;
    }

    public int pop(){
        int num = innerArr[index];
        index--;
        return num;
    }
}

3.实现一个特殊的栈,在基本功能的基础上,再实现返回栈中最小元素的功能

/**
 * 实现一个特殊的栈,在基本功能的基础上,再实现返回栈中最小元素的功能
 * 要求:
 * 1.pop,push,getMin操作的时间复杂度都是o(1)
 * 2.设计的栈类型可以使用现成的栈结构
 */
public class Task1 {
    public static void main(String[] args) throws Exception {
        //用双向链表实现栈
        MyStackOfMinValue myStackOfMinValue = new MyStackOfMinValue();
        myStackOfMinValue.push(2);
        myStackOfMinValue.push(3);
        myStackOfMinValue.push(2);
        myStackOfMinValue.push(3);
        int pop = myStackOfMinValue.pop();
        System.out.println("pop = " + pop);

        int min = myStackOfMinValue.getMin();
        System.out.println("min = " + min);
    }
}

class MyStackOfMinValue{
    private static final MyStack myStack1 = new MyStack();
    private static final MyStack myStack2 = new MyStack();

    //当插入一个数时
    void push(int num) throws Exception{
        if(myStack1.isEmpty()){
            myStack1.push(num);
            myStack2.push(num);
        }else{
            myStack1.push(num);
            if(myStack2.stackTop() >= num){
                myStack2.push(num);
            }
        }
    }

    //当弹出一个数时
    int pop() throws Exception{
        int pop = myStack1.pop();
        if(myStack2.stackTop() == pop){
            myStack1.pop();
        }
        return pop;
    }

    //获取最小值
    int getMin() throws Exception{
        return myStack2.stackTop();
    }
}

class MyStack{
    private MyLinked myLinked = new MyLinked();
    //栈是先进后出,从尾部插入,从尾部取出

    void push(int num){
        myLinked.insertFromTail(num);
    }

    int pop() throws Exception{
        return myLinked.getFromTail();
    }

    boolean isEmpty(){
        return myLinked.head == null;
    }

    //查看栈顶元素
    int stackTop() throws Exception{
        if(isEmpty()){
            throw  new Exception("栈中没有元素!");
        }
        return myLinked.tail.value;
    }
}

class DoubleNode{
    DoubleNode pre;
    DoubleNode next;
    int value;
}

class MyLinked{
    DoubleNode head=null;
    DoubleNode tail=null;

    //从头部插入
    void insertFromHead(int num){
        if(head == null){
            DoubleNode doubleNode = new DoubleNode();
            doubleNode.value = num;
            head = doubleNode;
            tail = doubleNode;
        }else{
            DoubleNode doubleNode = new DoubleNode();
            doubleNode.value = num;
            doubleNode.next = head;
            head = doubleNode;
        }
    }

    //从尾部插入
    void insertFromTail(int num){
        if(tail == null){
            DoubleNode doubleNode = new DoubleNode();
            doubleNode.value = num;
            head = doubleNode;
            tail = doubleNode;
        }else{
            DoubleNode doubleNode = new DoubleNode();
            doubleNode.value = num;
            tail.next = doubleNode;
            tail = doubleNode;
        }
    }

    //从头部弹出一个数
    int getFromHead() throws Exception{
        if(head==null){
            throw new Exception("没有元素可以获取!");
        }else{
            int num = head.value;
            head = head.next;
            return num;
        }
    }

    //从尾部弹出一个数
    int getFromTail() throws Exception{
        if(tail == null){
            throw new Exception("没有元素可以获取!");
        }else{
            int num = tail.value;
            tail = tail.pre;
            if(tail!=null) {
                tail.next = null;
            }
            return num;
        }
    }
}

4,如果只给你队列结构怎么实现栈,如果只给你栈结构怎么实现队列?

/**
 * 1.如何用栈结构实现队列结构
 * 2。如何用队列结构实现栈结构
 */
public class Task2 {
    public static void main(String[] args) throws Exception{
        /*MyStack2 myStack2 = new MyStack2();
        myStack2.push(1);
        myStack2.push(2);
        myStack2.push(3);
        myStack2.push(4);
        myStack2.push(5);
        int pop = myStack2.pop();
        System.out.println("pop = " + pop);
        myStack2.push(6);
        int pop1 = myStack2.pop();
        System.out.println("pop1 = " + pop1);*/
        MyQueue2 myQueue2 = new MyQueue2();
        myQueue2.add(1);
        myQueue2.add(2);
        myQueue2.add(3);
        myQueue2.add(4);
        myQueue2.add(5);
        int remove = myQueue2.remove();
        System.out.println("remove = " + remove);
        myQueue2.add(6);
        int remove1 = myQueue2.remove();
        System.out.println("remove1 = " + remove1);
    }
}

/**
 * 栈:先进后出
 * 用队列模仿栈,入队和入栈一样,出栈的话用队列模拟就是要把最后一个值取出来,出队列。
 * 思路:搞两个队列,每次要模拟出栈的时候,将队列出列到另一个空队列中,直到队列中只剩余一个值,将这个值出队就是出栈。
 */
class MyStack2{
    private Queue dataQueue = new LinkedBlockingQueue();
    private Queue subQueue = new LinkedBlockingQueue();

    public void push(int num){
        if(dataQueue.size()==0 && subQueue.size() == 0){
            dataQueue.add(num);
        }else if(dataQueue.size() > 0){
            dataQueue.add(num);
        }else{
            subQueue.add(num);
        }
    }

    public int pop() throws Exception{
        if(dataQueue.size() == 0 && subQueue.size() == 0){
            throw new Exception("栈里没有元素!");
        }
        if(dataQueue.size() > 0){
            while (dataQueue.size() > 1){
                Object poll = dataQueue.poll();
                subQueue.add(poll);
            }
            return (Integer) dataQueue.poll();
        }else{
            while (subQueue.size() > 1){
                Object poll = subQueue.poll();
                dataQueue.add(poll);
            }
            return (Integer) subQueue.poll();
        }
    }
}

/**
 * 队列:先进先出
 * 用栈模拟队列,入队和入栈一样,出队的话用栈模拟就是要·把第一个值取出来出栈。
 * 思路:搞两个栈,每次要模拟出队的时候,将栈出栈到另一个空栈中,直到栈中只剩余一个值,将这个值出栈后,再将另一个栈的数据出栈入到这个栈中就是出队。
 */
class MyQueue2{
    private Stack dataStack = new Stack();
    private Stack preStack = new Stack();

    public void add(int num){
        dataStack.push(num);
    }

    public int remove() throws Exception{
        if(dataStack.isEmpty()){
            throw new Exception("队列中没有元素");
        }
        while (!dataStack.isEmpty()){
            preStack.push(dataStack.pop());
        }

        Object pop = preStack.pop();

        while (!preStack.isEmpty()){
            dataStack.push(preStack.pop());
        }
        return (Integer) pop;
    }
}