第一天..

练习

用队列实现栈

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。

实现 MyStack 类:

  • void push(int x) 将元素 x 压入栈顶。

  • int pop() 移除并返回栈顶元素。

  • int top() 返回栈顶元素。

  • boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。

注意:

  • 你只能使用队列的基本操作 —— 也就是 push to back、peek/pop from front、size 和 is empty 这些操作。

  • 你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。

示例:

输入:

["MyStack", "push", "push", "top", "pop", "empty"]

[[], [1], [2], [], [], []]

输出:

[null, null, null, 2, 2, false]

解释:

MyStack myStack = new MyStack();

myStack.push(1); 栈里 1

myStack.push(2); 栈里 1 2

myStack.top(); // 返回 2 返回最后的栈顶 不删除

myStack.pop(); // 返回 2返回最后的栈顶 删除

myStack.empty(); // 返回 False 栈里剩下1

提示:

  • 1 <= x <= 9

  • 最多调用100 次 push、pop、top 和 empty

  • 每次调用 pop 和 top 都保证栈不为空

package easy.a用队列实现栈2;

import java.util.LinkedList;
import java.util.Queue;

/**
 *
 */
class MyStack {
    private Queue<Integer> queue;
    /** Initialize your data structure here. */
    public MyStack() {
        queue = new LinkedList<>();
    }

    public static void main(String[] args) {
        MyStack myStack = new MyStack();
        myStack.push(1);
        System.out.println(" ");
        System.out.println("下一行");
        myStack.push(2);
        System.out.println(" ");
        System.out.println("下一行");
        myStack.push(3);
        System.out.println(" ");
        System.out.println("下一行");
        myStack.push(4);
//        myStack.top();
        System.out.println(myStack.top());
//        myStack.pop();
        System.out.println(myStack.pop());
        myStack.empty();
        System.out.println(myStack.queue);

    }
    /**
     * 在添加数据的时候进行翻转
     */
    /** Push element x onto stack. */
    public void push(int x) {
        Queue<Integer> temp = new LinkedList<>();
        while (!queue.isEmpty()) {
            System.out.println("queue:"+queue);
            temp.add(queue.poll());
            System.out.println("TEMP:"+temp);

        }
        System.out.println("------------");
        queue.add(x);
        System.out.println(queue);
        System.out.println("------------");
        while (!temp.isEmpty()) {
            System.out.println("TEMP:"+temp);
            queue.add(temp.poll());
            System.out.println("queue:"+queue);
        }
    }
    /** Removes the element on top of the stack and returns that element. */
    public int pop() {
        return queue.poll();
    }
    /** Get the top element. */
    public int top() {
        return queue.peek();
    }
    /** Returns whether the stack is empty. */
    public boolean empty() {
        return queue.isEmpty();
    }
}

上述演示最后一次push

介绍

栈底是第一个进栈的数据,栈顶就是最后一个进栈的数据

poll是队列数据结构实现类的方法,从队首获取元素,同时获取的这个元素将从原队列删除

peek()方法用于从此Stack中返回顶部元素,并且它不删除就检索元素

栈:是一种特殊的线性表,其只允许在一端出数据和入数据,插入数据和删除数据的一端加栈顶,另一端叫栈底。其数据遵守先进后出的原则(Last in First out)

总结

从结果来看 好像是倒叙的

但是栈不能遍历,要访问下一个数据,必须把现在的数据弹出栈顶。

如果是一边访问数据一边输出,还是以1 2 3 4 出现

扩展

队列:队列具有先进先出,进行插入操作的一端称为队尾。进行删除操作的一端称为队首。

因为其只能在队头出数据,所以进入一段数据 1 2 3 4 ,那么出数据的顺序也该是 1 2 3 4

如果加入5 则在4后面加入

小玉家的电费

夏天到了,各家各户的用电量都增加了许多,相应的电费也交的更多了。小玉家今天收到了一份电费通知单。小玉看到上面写:据闽价电[2006]27号规定,月用电量在150千瓦时及以下部分按每千瓦时0.4463元执行,月用电量在151~400千瓦时的部分按每千瓦时0.4663元执行,月用电量在401千瓦时及以上部分按每千瓦时0.5663元执行;小玉想自己验证一下,电费通知单上应交电费的数目到底是否正确呢。请编写一个程序,已知用电总计,根据电价规定,计算出应交的电费应该是多少。

输入描述:
输入一个整数,表示用电总计(单位以千瓦时计),不超过10000。

输出描述:
输出一个数,保留到小数点后1位(单位以元计,保留到小数点后1位
import java.util.ArrayList;
import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        String str_0 = scan.nextLine().trim();
        int amount = Integer.parseInt(str_0);

        scan.close();

        float result = solution(amount);

        System.out.println(String.format("%.1f", result));

    }

    public static float solution(int amount){
        float result = (float)0.0;

        if(0<=amount&&amount<=150){
            result=(float)(amount*0.4463);
        }else if(150<amount&&amount<=400){
            result=(float)(150*0.4463+(amount-150)*0.4663);
        }else if(400<amount&&amount<=10000){
            result=(float)(150*0.4463+250*0.4663+(amount-400)*0.5663);
        }

        return result;
    }
}

结论: 1.&& 2.输出时使用 String.format("%.1f", result) 3.强制类型转换

查找整数

题目描述
给定一个非降序的整数数组,数组中包含重复数字(重复数字很多) ,给定任意整数,对数组进行二分查找,返回数组正确的位置,给出函数实现。 a. 连续相同的数字,返回最后一个匹配的位置 b. 如果数字不存在返回 -1。(测试用例仅做参考,我们会根据代码质量进行评分)

输入描述:
第一行给定数组长度n,目标值tar。(1<=n,tar<=10000) 第二行给出n个整数a.(1<=a<=10000)

输出描述:
按题目描述输出。

示例 
示例1
输入
7 4
1 2 2 3 4 4 10
输出
5
import java.util.ArrayList;
import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);

        String str_0 = scan.nextLine();
        String[] line_list_0 = str_0.trim().split(" ");
        ArrayList<Integer> arr_temp = new ArrayList<>();
        for(int i = 0; i < line_list_0.length; i++){
            arr_temp.add(Integer.parseInt(line_list_0[i]));
        }


        int n = arr_temp.get(0);//数组长度
        int tar = arr_temp.get(1);//目标值


        String str_2 = scan.nextLine();
        String[] line_list_2 = str_2.trim().split(" ");
        ArrayList<Integer> arr = new ArrayList<>();
        for(int i = 0; i < line_list_2.length; i++){
            arr.add(Integer.parseInt(line_list_2[i]));
        }//一堆数字

        scan.close();

        int result = solution(n, tar, arr);

        System.out.println(result);

    }

     public static int solution(int n, int tar, ArrayList<Integer> arr){
        int result = 0;
        int left=0;int right=n-1;int mid=0;
        while(left<=right){//如果最后的下标大于等于左边的下标
            mid=(left+right)/2;//二分查找精华 取中值下标
            if(tar==arr.get(mid)){//如果值相等
                if(mid==0){//判断下标为0的情况
                    return right;
                }
                if(mid!=right) {//如果中值下标与边界不相等
                    while (arr.get(mid).equals(arr.get(mid + 1))) {//判断中值和后一个下标值是否一致
                        mid++;//一致就自增
                    }
                    if (!arr.get(mid).equals(arr.get(mid + 1))) {//是否不一致
                        result = mid;//可以把result去了 好像是刷题自带的 没用上 
                        return result;
                    }
                }else {
                    return right;//如果相等了 就直接返回下标 因为已经边界了
                }
            }else if (tar<arr.get(mid)) {//二分查找精华 目标值小于中间值 就right变化
                right=mid-1;
            }else {//二分查找精华 目标值大于中间值 就left变化
                left=mid+1;
            }
        }
        return -1;//没查到
    }
}

总结:

  1. 二分查找,查找的是顺序队列的,无序查不出来

  1. 数组有n个 下标是n-1个 因为是从0开始

  1. 考虑有无输入的数字 看看后面的数字是否与前面相同

  1. 要考虑下标为0和1的情况

可能还可以简化,新手学习,请多指点。

八股

hashMap 链表长度大于8后一定会转为红黑树吗?

不一定,如果链表长度大于8同时数组长度大于64才会变成红黑树,数组小于64会进行扩容,这种情况下数组加链表比红黑树更有效率,查询速度更快。

红黑树的元素小于6一定会变成链表吗?

不一定,如果出现resize(改变尺寸大小)的时候才会根据untreeify_threshold(取消验证_阈值)进行转换

concurrentMashMap(线程安全)分段锁之间加了什么锁,读写之间是互斥的吗?

1.7

使用分段锁(Segment)来控制并发访问。每个段都是一个独立的哈希表,只包含总容量的一部分,每个段都有自己的锁,因此不同的线程可以同时访问不同的段

1.8

它使用CAS(Compare and Swap)和synchronized来取代分段锁。这种实现方式被称为"数组+链表+红黑树",即每个桶内部采用链表或红黑树来存储键值对,当桶内键值对数量达到一定阈值时,链表会自动转化为红黑树,以提高查找效率。

整个哈希表被分成若干个段,每个段都被实现为一个数组,每个数组元素都是一个链表或红黑树。每个元素都是一个桶,通过哈希函数将键值对映射到桶中。每个桶内部都通过synchronized来实现同步,以保证线程安全性。而对于读操作,使用了无锁的CAS操作。

类型

JDK1.7

JDK1.8

数据结构

Segment分段锁

数组+链表+红黑树

线程安全机制

segment的分段锁机制

CAS+Synchorized机制

锁的粒度

每段Segment加锁,粒度大

每个Node元素加锁,粒度更细

减少锁竞争:由于每个桶内部采用了synchronized来实现同步,不同的线程可以同时访问不同的桶,从而减少了锁竞争。

更高的并发度:由于不再受限于固定数量的段,ConcurrentHashMap 可以根据需要动态调整大小,并支持更高的并发度。

更好的扩展性:由于不再需要维护多个段的锁,因此在扩展时可以更容易地添加或删除桶,而不需要重构整个数据结构。

更好的性能:使用CAS操作替代了分段锁,避免了分段锁中的自旋等待开销,提高了并发性能。

三次握手后一直不连接会怎么样?

服务器会认为丢包,然后向客户端发送大量syn包重传,产生半连接,如果客户端一直不发送数据,也就是不回送ack包, 就会让服务器产生大量的半连接,从而占用服务器的大量资源

TCP/IP协议四层是什么?

数据链路层、网络层、传输层、应用层。

以太网的数据帧在链路层; IP包在网络层; TCP和UDP包在传输层; TCP和UDP中的数据在应用层

三次握手四次挥手介绍

三次握手

  1. 第一次客户端向服务端发送syn=1 seq=x 数据包 代表请求连接

  1. 第二次服务器收到数据包后回送 syn=1 seq=y ack=x+1的数据包 代表可以,允许连接

  1. 第三次客户端向服务器发送syn=1 seq=x+1 ack=y+1的数据包 代表收到,开始连接

三次握手连接成功 其中syn标志位数置1,表示建立TCP连接;ack标志表示验证字段。

四次挥手

  1. 第一次客户端向服务端发送fin=1 seq=x数据包 代表请求断开连接 然后变成fin_wait(等待之前发送的连接终止请求的确认)

  1. 第二次服务器向客户端发送fin=1 ack=x+1 seq=y数据包 代表可以断开,请等待 然后变成close_wait(等待本地用户的连接终止请求)

  1. 第三次服务器确保数据传输完成,再向客户端发送fin=1 ack=x+1 seq=z数据包 代表结束等待 变成lask_act并等待(lask_act:等待先前发送给远端TCP 的连接终止请求的确认(包括它字节的连接终止请求的确认))

  1. 第四次客户端确认后回送fin=1 ack=z+1 seq=h数据包 代表确认终止 并变成time_wait(等待足够的时间过去以确保远端TCP 接收到它的连接终止请求的确认)

四次挥手断开连接完成

HashMap的底层是数组+链表

jdk1.8底层是数组+链表或者数组+红黑树

HaspMap的数组默认大小为16

HashMap线程不安全

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值