双链表&栈

1、什么是LinkedList

LinkedList的底层是双链表结构,由于链表没有将元素存储在连续的空间,元素存在单独的节点中,然后通过引用将节点连接起来,因此在任意位置删除或添加元素时,不需要搬移元素,效率比较高。

2、说明

(1)LinkedList实现了List接口

(2)LinkedList使用了双链表结构

(3)LinkedList没有实现RandomAcess接口,因此不支持随机访问

(4)LinkedList插入根删除效率比较高,时间复杂度为O(1);

(5)LinkedList比较适合在任意节点插入的场景

3、用代码实现一个双链表

3.1、定义双链表的一个类,然后再定义它的头节点和尾节点

 //定义双向链表的节点
    public static class ListNode{
        int value;
        ListNode prev;
        ListNode next;
        public ListNode(int val){
            this.value=val;
        }
    }
    //头节点
    public ListNode head;
    //尾节点
    public ListNode tail;

3.2、头插法

//头插法
    public void addFirst(int data){
        ListNode node=new ListNode(data);
        if(head==null){
            //如果链表头为空
            head=node;
            tail=node;
        }else{
            node.next=head;
            head.prev=node;
            head=node;
        }
    }

3.3、尾插法

//尾插法
    public void addLast(int data){
        ListNode node=new ListNode(data);
        if(head==null){
            //如果链表为空
            head=node;
        }else{
            tail.next=node;
            node.prev=tail;
        }
        tail=node;
    }

3,4实现一个任意节点插入,第一个数据节点为0号下标

 public void addIndex(int index,int data){
        //校验index的合法性
        CheckRange(index);
        //下标为0的时候直接用头插法
        if(index==0){
            addFirst(data);
            return;
        }
        //下标为size的时候直接用尾插法
        if(index==size()){
            addLast(data);
            return;
        }
        // 处理中间位插入的时候要先找到对应下标的前一个节点
        ListNode prevNode = findIndex(index);
        // 创建一个新节点
        ListNode node = new ListNode(data);
        // 让这个新节点的next引用prevNode.next
        node.next = prevNode.next;
        // 让prevNode.next引用新节点
        prevNode.next = node;
    }

    private ListNode findIndex(int index) {
        ListNode current=head;
        while(index<0){
            current=current.next;
            index--;
        }
        return current;
    }

    public int size() {
        //直接遍历节点
        ListNode current=head;
        int count=0;
        while(current!=null){
            current=current.next;
            count++;
        }
        return count;
    }

    private void CheckRange(int index) {
        if(index<0||index>size()){
            throw new RuntimeException("插入位置不合法,index="+index);
        }
    }

3.5、查找关键字是否包含在链表中

public boolean contains(int key){
        ListNode current=head;
        while(current!=null){
            if(current.value==key){
                return true;
            }
            current=current.next;
        }
        return false;
    }

3.6、删除第一次出现key的关键字

public void remove(int key){
        ListNode current=head;
        while(current!=null){
            //头节点
            if(current.value==key) {
                if (current==head) {
                    //遍历进来之后删除头节点
                    head = head.next;
                    if (head == null) {
                        //如果链表已经是空
                        tail = null;
                    }else{
                        //只剩下一个节点
                        head.prev.next=null;
                        head.prev=null;
                    }
                } else if (current==tail) {
                    //删除尾节点
                    tail=tail.prev;
                    tail.next=null;
                }else{
                    //key在链表中间
                    current.prev.next=current.next;
                    current.next.prev=current.prev;
                }
                //删除完成就返回
                return;
            }
            //继续遍历
            current=current.next;
        }
    }

3.7、删除所有值为key的节点
 

public void removeAll(int key){
        ListNode current=head;
        while(current!=null){
            //头节点
            if(current.value==key) {
                if (current==head) {
                    //遍历进来之后删除头节点
                    head = head.next;
                    if (head == null) {
                        //如果链表已经是空
                        tail = null;
                    }else{
                        //只剩下一个节点
                        head.prev=null;
                    }
                } else if (current==tail) {
                    //删除尾节点
                    tail=tail.prev;
                    tail.next=null;
                }else{
                    //key在链表中间
                    current.prev.next=current.next;
                    current.next.prev=current.prev;
                }
            }
            //继续遍历
            current=current.next;
        }
    }

3.8、

打印显示1

public void dispaly(){
        StringBuilder sb=new StringBuilder();
        sb.append("[");
        ListNode current=head;
        while(current!=null){
            sb.append(current.value);
            if(current.next!=null){
                sb.append(",");
            }
            current=current.next;
        }
        sb.append("]");
        System.out.println(sb);
    }

打印显示2

public void printList(){
        //判断节点是否为空
        if(head==null){
            System.out.println();
            return;
        }
        //定义一个栈,用来保存每一个节点
        Stack<ListNode> stack=new Stack<>();
        //开始遍历,定义遍历节点
        ListNode current=head;
        while(current!=null){
            //链表元素入栈
            stack.push(current);
            current=current.next;
        }
        //遍历完成之后,所有的元素都在栈里,
        while(!stack.isEmpty()){
            //栈中元素依次出栈
            System.out.println(stack.pop().value+" ");
        }
    }

3.9、清空链表

 public void clear(){
        head=null;
    }

3.10测试类测试LinkedList


public class TestDemo1 {
    public static void main(String[] args) {
        Demo1 demo1 = new Demo1();
        System.out.println();
        demo1.dispaly();
        demo1.addFirst(1);
        demo1.addLast(12);
        demo1.addLast(23);
        demo1.addLast(34);
        System.out.println("====");
        demo1.addLast(45);
        demo1.addLast(56);
        demo1.addLast(45);
        demo1.dispaly();
        System.out.println(demo1.size());
        System.out.println("是否包含=>");
        System.out.println(demo1.contains(23));
        System.out.println(demo1.contains(89));
        System.out.println("增加元素=>");
        demo1.addIndex(3, 45);
        demo1.dispaly();
        System.out.println("删除元素=>");
        demo1.remove(12);
        demo1.removeAll(45);
        demo1.dispaly();
    }
}

3.11、测试结果

 

4、LinkedList和ArrayList的区别

 5、栈

5.1、什么是栈
栈:栈是一种特殊的线性表,其只允许在一端进行插入和删除元素操作,进行数据插入和删除操作的一端为栈顶,另外一端为栈底。栈中元素遵循先进后出的原则
5.2、压栈和出栈

压栈:栈的插入操作叫做进栈/入栈,入数据在栈顶

出栈:栈的删除操作叫做出栈,出数据在栈顶

 5.3、栈的实现


import java.util.Arrays;

public class MyStack {
    private int[] elementData;
    private int size;
    private final int DEFAULT_CAPACITY=7;
    public MyStack(){
        this.elementData=new int[DEFAULT_CAPACITY];
    }
    public MyStack(int capacity){
        if(capacity<0){
            throw new RuntimeException("数组容量不能小于零");
        } else if (capacity>0) {
            this.elementData=new int[capacity];
        }else{
            this.elementData=new int[DEFAULT_CAPACITY];
        }
    }
    //入栈操作
    public void push(int data){
        //是否需要扩容
        checkRange(data);
        //在size里面添加元素
        elementData[size]=data;
        size++;
    }
    //出栈操作
    public int pop(){
        int top=peek();
        size--;
        return top;
    }
    //找到栈顶元素
    private int peek() {
        //判断是否为空
        if(size==0){
            throw new RuntimeException("栈为空");
        }
        return elementData[size-1];
    }

    private void checkRange(int data) {
        if(elementData.length==size){
            this.elementData= Arrays.copyOf(this.elementData,2*elementData.length);
        }
    }
    public int size(){
        return size;
    }
    public boolean empty(){
        return size==0;
    }
}

public class TestStack {
    public static void main(String[] args) {
        Stack<Integer> s1=new Stack<>();
        s1.push(12);
        s1.push(23);
        s1.push(34);
        s1.push(45);
        s1.push(56);
        s1.push(67);
        System.out.println(s1);
        s1.pop();
        s1.pop();
        System.out.println(s1);
        //查看栈顶元素
        int top=s1.peek();
        System.out.println("查看栈顶元素,top="+top);
        //弹出栈顶元素
        int pop=s1.pop();
        System.out.println("查看出栈元素,pop="+pop);
        System.out.println(s1);
        System.out.println(s1.size());
        while(s1.isEmpty()==false){
            System.out.println(s1.pop());
        }
        System.out.println(s1);
        System.out.println(s1.size());
        //s1.pop();此时栈已经为空,再去pop栈中元素或者peek()栈中元素,就会抛出异常
    }
}

5.4栈的使用:算法实例

括号匹配问题:力扣

 public boolean isVaild(String s){
        if(s==null||s.equals("")){
            return false;
        }
        //1、定义一个栈用来存入左括号
        Stack<Character> stack=new Stack<>();
        //2、开始遍历字符串
        for (int i = 0; i <s.length(); i++) {
            char ch=s.charAt(i);
            //判断是否为左括号
            if(ch=='{'||ch=='('||ch=='['){
                //如果是左括号,入栈
                stack.push(ch);
            }else{
                //检查一下栈是否为空,如果直接为空返回false
                if(stack.isEmpty()){
                    return false;
                }
                //栈不为空,获取栈顶元素与当前右括号进行匹配
                char top=stack.peek();
                if(top==']'||top=='}'||top==')'){
                    //出栈栈顶元素
                    stack.pop();
                }else{
                    return false;
                }
            }
        }
        //检查一下栈是否为空
        if(!stack.isEmpty()){
            return false;
        }
        return true;
    }

 逆波兰表达式:力扣

 /**
     * 逆波兰表达式
     * @param tokens
     * @return
     */
    public int evalPAN(String[] tokens){
        //判断是否为空
        if(tokens==null||tokens.length==0){
            return -1;
        }
        //创建一个栈,用来存放元素
        Stack<Integer> stack=new Stack<>();
        //开始遍历字符数组
        for (int i = 0; i < tokens.length; i++) {
            String str=tokens[i];
            boolean b=isoperator(str);
            if(b){
                int left=stack.pop();
                int right=stack.pop();
                switch(str){
                    case"+":
                        stack.push(left+right);
                        break;
                    case"-":
                        stack.push(left-right);
                        break;
                    case"*":
                        stack.push(left*right);
                        break;
                    case"/":
                        stack.push(left/right);
                        break;
                }
            }else{
                stack.push(Integer.valueOf(str));
            }
        }
        return stack.pop();
    }

    private boolean isoperator(String str) {
        //判断是否是操作符
        if(str==null&&str.equals("")){
            return false;
        }
        if(str.equals("+")||str.equals("-")||str.equals("*")||str.equals("/")){
            return true;
        }
        return false;
    }

栈的压入和弹出序列:栈的压入、弹出序列_牛客题霸_牛客网

/**
     * 栈的压入,弹出序列
     * @param pushA
     * @param popA
     * @return
     */
    public boolean IsPopOrder(int [] pushA,int [] popA) {
        //先检查数组pushA是否为空
        if(pushA==null||pushA.length==0){
            return false;
        }
        //定义一个栈用来存放数组元素
        Stack<Integer> stack=new Stack<>();
        //定义一个变量j,防止被循环修改
        int j=0;
        //遍历数组元素pushA
        for(int i=0;i<pushA.length;i++){
            stack.push(pushA[i]);
            while(!stack.isEmpty()&&j<popA.length&&stack.peek()==popA[j]){
                j++;
                stack.pop();
            }
        }
        return stack.isEmpty();
    }

最小栈:力扣


/**
 * 最小栈
 */
public class minStack {
    //创建两个栈
    Stack<Integer> stack;
    Stack<Integer> MinStack;
    //初始化堆栈对象
    public minStack(){
        stack=new Stack<>();
        MinStack=new Stack<>();
    }
    public void push(int val){
        //将元素直接入栈到satck,无条件入栈
        stack.push(val);
        //判断MinStack是否为空,获取val小于MinStack的栈顶元素,直接入栈
        if(MinStack.isEmpty()||val<MinStack.peek()){
            MinStack.push(val);
        }
    }
    public void pop(){
        //删除栈顶元素
        //首先判断stack是否为空,如果为空直接返回
        if(stack.isEmpty()){
            return;
        }
        int value=stack.pop();
        if(value==MinStack.peek()&&MinStack.isEmpty()){
            MinStack.pop();
        }
    }
    public int top(){
        //获取satck的堆顶元素
        if(stack.isEmpty()){
            return -1;
        }
        return stack.peek();
    }
    public int getMin(){
        //获取最小栈的堆顶元素
        if(MinStack.isEmpty()){
            return -1;
        }
        return stack.peek();
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值