手写实现java栈结构,并实现简易的计算器(基于后缀算法)

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介:

手写实现java栈结构,并实现简易的计算器(基于后缀算法)

一、定义
栈是一种线性表结构,栈结构中有两端,对栈的操作都是对栈的一端进行操作的,那么被操作的一端称为栈顶,另一端则为栈底。对栈的操作其实就是只有两种,分别是入栈(也称为压栈)和出栈(也称为弹栈)。入栈,将新元素压入栈中,那么此时这个栈元素就成为了栈顶元素,栈深度相应的+1。出栈,将栈中的栈顶元素弹出来,此时栈顶的下一个元素就会成为新的栈顶元素,栈深度也相应的-1。根据入栈和出栈的规则,也可以得到栈数据的顺序是后进先出(LIFO,LAST IN FIRST OUT)的特性。栈结构的效率是非常高的,因此无论栈中数据的量有多大,操作的也只有栈顶元素一个数据,因此栈的时间复杂度为O(1),这里不考虑栈溢出扩容的问题。栈结构示意图下图:

  二、栈的应用场景
栈的数据接口在编程中的应用是非常广泛的,其中包括:

1、浏览器页面的浏览记录。我们在浏览器中浏览的页面的时候后退和前进能够正确的跳转到对应的页面,就是利用了栈的特性来实现的。

2、java虚拟机中栈的操作数栈也是利用栈实现的。java在编译的时候讲操作的代码压入操作数栈中,进行运算时就将栈顶元素弹出来,然后进行运算后将结果再压进操作数栈中。

3、计算器的实现。我们在计算的时候一般都是从左往右计算的,但是这种方式对于计算机是非常不友好的,它需要进行大量的判断才可以。但是利用栈以及一些算法就能轻松实现计算的功能。我们下面的例子也将会利用栈结构来实现简易的计算器的功能。

  三、入栈和出栈
栈结构可以使用数组结构和链表结构来实现,因此不同的实现方式,入栈和出栈的实现方式也会有所区别。基于数组实现的栈的入栈和出栈操作实质是在内部维护了一个指针,这个指针指向的元素即为栈顶元素,入栈时讲指针向上移动一位,相反地则向下移动一位。基于链表的栈就没有了指针的概念。链表使用单向链表即可实现。链表的出栈和入栈实质上维护的链表头部元素。下面使用示意图来简单的演示一下两种结构的入栈和出栈的流程:

  1、基于数组的入栈和出栈:

   2.链表的入栈和出栈

  四、代码实现
  1.数组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/**
 * 基于数组实现的栈
 */
public class ArrayStack implements Stack {

    private Object[] data;
    private int index = -1;
    private int deep;
    private static final int DEFAULT_CAPACITY = 1 << 4;

    public ArrayStack() {
        deep = DEFAULT_CAPACITY;
        data = new Object[deep];
    }

    public ArrayStack(int capacity) {
        if (capacity <= 0) {
            capacity = DEFAULT_CAPACITY;
        }
        deep = capacity;
        data = new Object[deep];
    }

    /**
     * 添加数据,数组满了就不添加
     * @param e 入栈元素
     * @return
     */
    @Override
    public E push(E e) {
        if (isFull()) {
            System.out.println("栈已满");
            return null;
        }
        data[++index] = e;
        return e;
    }

    /**
     * 弹出元素
     * @return 栈顶元素
     */
    @Override
    public E pop() {
        if (isEmpty()) {
            System.out.println("栈为空");
            return null;
        }
        return (E) data[index--];
    }

    /**
     * 查看栈顶元素
     * @return
     */
    @Override
    public E peek() {
        if (isEmpty()) {
            System.out.println("栈为空");
            return null;
        }
        return (E) data[index];
    }

    /**
     * 栈深度
     * @return
     */
    @Override
    public int size() {
        return index + 1;
    }

    private boolean isEmpty() {
        return index <= -1;
    }

    private boolean isFull() {
        return deep == index + 1;
    }
  2.链表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/**
 * 基于链表实现的栈
 * @param
 */
public class LinkStack implements Stack {

    private Node head;
    private int size;

    @Override
    public E push(E e) {
        Node node = new Node<>(e);
        if (head == null) {
            head = node;
        }else {
            Node n = head;
            head = node;
            head.next = n;
        }
        size++;
        return e;
    }

    @Override
    public E pop() {
        if (head == null) {
            return null;
        }
        E data = head.data;
        head = head.next;
        size--;
        return data;
    }

    @Override
    public E peek() {
        return head == null ? null : head.data;
    }

    @Override
    public int size() {
        return size;
    }

    private static class Node {
        E data;
        Node next;

        public Node(E e) {
            data = e;
        }
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
 * 栈结构
 */
public interface Stack {

    /**
     * 入栈
     * @param e 入栈元素
     * @return 入栈元素
     */
    E push(E e);

    /**
     * 将栈顶元素弹出
     * @return 栈顶元素
     */
    E pop();

    /**
     * 查看栈顶元素,该方法不会弹出栈顶元素
     * @return 栈顶元素
     */
    E peek();

    /**
     * 查看栈深度
     * @return 栈深度
     */
    int size();
}

  五、应用实例:简易计算器
在进入写代码之前需要知道的前置知识是:前缀表达式(也叫波兰表达式),中缀表达式和后缀表达式(也叫逆波兰表达式)。

前缀、中缀、后缀表达式是对表达式的不同记法,其区别在于运算符相对于操作数的位置不同,前缀表达式的运算符位于操作数之前,中缀和后缀同理

举例:
中缀表达式:1 + (2 + 3) × 4 - 5
前缀表达式:- + 1 × + 2 3 4 5
后缀表达式:1 2 3 + 4 × + 5 -

中缀表达式 中缀表达式是一种通用的算术或逻辑公式表示方法,操作符以中缀形式处于操作数的中间。中缀表达式是人们常用的算术表示方法。 虽然人的大脑很容易理解与分析中缀表达式,但对计算机来说中缀表达式却是很复杂的,因此计算表达式的值时,通常需要先将中缀表达式转换为前缀或后缀表达式,然后再进行求值。对计算机来说,计算前缀或后缀表达式的值非常简单。

我下面讲解的例子中是利用后缀表达式的算法来实现的,因此,代码中回涉及到 运算字符串转中缀表达式,中缀表达式转后缀表达式的过程。

  后缀表达式步骤
从左至右扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(次顶元素 和 栈顶元素),并将结果入栈;重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果。

例如: (3+4)×5-6 对应的后缀表达式就是 3 4 + 5 × 6 - , 针对后缀表达式求值步骤如下:

1.从左至右扫描,将3和4压入堆栈;
2.遇到+运算符,因此弹出4和3(4为栈顶元素,3为次顶元素),计算出3+4的值,得7,再将7入栈;
3.将5入栈;
4.接下来是×运算符,因此弹出5和7,计算出7×5=35,将35入栈;
5.将6入栈;
6.最后是-运算符,计算出35-6的值,即29,由此得出最终结果

根据上面的步骤,我们可以使用代码来实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/**
     * 根据后缀表达式计算值
     * @param items 后缀表达式
     * @return 计算结果
     */
    public int calculate(List items) {
        /**
         * 用于保存过程变量和操作符等
         */
        Stack stack = new LinkStack<>();
        //便利
        for (String item : items) {
            //如果为数字,直接放入栈中
            if (item.matches("\d+")) {
                stack.push(item);
            }else {
                //弹出栈顶元素进行运算
                int num2 = Integer.parseInt(stack.pop());
                int num1 = Integer.parseInt(stack.pop());
                int res;
                switch (item) {
                    case "+" :
                        res = num1 + num2;
                        break;
                    case "-" :
                        res = num1 - num2;
                        break;
                    case "*" :
                        res = num1 * num2;
                        break;
                    case "/" :
                        res = num1 / num2;
                        break;
                    default:
                        throw new RuntimeException("非法的运算符:" + item);
                }
                //运算完将结果压入栈中
                stack.push("" + res);
            }
        }
        //整个表达式扫描结束后,此时栈中只剩一个元素,该元素即为结算结果,从栈中弹出即可
        return Integer.parseInt(stack.pop());
    }
测试结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static void main(String[] args) {
        Calculator calculator = new Calculator();
        List items = new ArrayList<>();
        items.add("3");
        items.add("4");
        items.add("+");
        items.add("5");
        items.add("*");
        items.add("6");
        items.add("-");
        System.out.println(calculator.calculate(items));
    }

//结果:29
虽然后面可以计算出表达式的最终结果,但是的实际的应用中计算的表达式往往都是按照我们的计算习惯来书写的(即中缀表达式,如(3+4)×5-6)。因此,想要正确的得到结果我们需要再多一个步骤,就是人们习惯的计算方式的中缀表达式转换成对计算机友好的后缀表达式。具体步骤如下:

1)初始化两个栈:运算符栈s1和储存中间结果的栈s2;
2)从左至右扫描中缀表达式;
3)遇到操作数时,将其压s2;
4)遇到运算符时,比较其与s1栈顶运算符的优先级:
4.1)如果s1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
4.2)否则,若优先级比栈顶运算符的高,也将运算符压入s1;
4.3)否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈顶运算符相比较;

5)遇到括号时:
5.1) 如果是左括号“(”,则直接压入s1
5.2) 如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
6)重复步骤2至5,直到表达式的最右边
7)将s1中剩余的运算符依次弹出并压入s2
8)依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式

具体代码如下:

  (一)、解析算式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
     * 将表达式解析成List
     * @param expression 表达式
     * @return
     */
    private List parseExpr(String expression) {
        char[] chars = expression.toCharArray();
        int len = chars.length;
        List items = new ArrayList<>(len);
        int index = 0;
        while (index < len) {
            char c = chars[index];
            //数字
            if (c >= 48 && c <= 57) {
                String tmp = "";
                //操作数大于一位数,主要是通过判断下一位是否为数字
                while (index < chars.length && chars[index] >= 48 && chars[index] <= 57) {
                    tmp += chars[index];
                    index++;
                }
                items.add(tmp);
            }else {
                items.add(c + "");
                index++;
            }
        }
        return items;
    }
  (二)、获取运算符的优先级
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
     * 获取运算符的优先级,数字越大优先级越大
     * @param operateChar 运算符
     * @return 优先级
     */
    private int priority(String operateChar) {
        if ("*".equals(operateChar) || "/".equals(operateChar)) {
            return 2;
        }else if ("+".equals(operateChar) || "-".equals(operateChar)) {
            return 1;
        }else {
            //throw new RuntimeException("非法的操作符:" + operateChar);
            return 0;
        }
    }

  (三)、中缀转后缀表达式
/**

  • 1)初始化两个栈:运算符栈operateStack和储存中间结果的栈tmp;
  • 2)从左至右扫描中缀表达式;
  • 3)遇到操作数时,将其压tmp;
  • 4)遇到运算符时,比较其与operateStack栈顶运算符的优先级:
  •   4.1)如果operateStack为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
  •   4.2)否则,若优先级比栈顶运算符的高,也将运算符压入operateStack;
  •   4.3)否则,将operateStack栈顶的运算符弹出并压入到tmp中,再次转到(4-1)与operateStack中新的栈顶运算符相比较;
  • 5)遇到括号时:
  •   5.1) 如果是左括号“(”,则直接压入operateStack
  •   5.2) 如果是右括号“)”,则依次弹出operateStack栈顶的运算符,并压入tmp,直到遇到左括号为止,此时将这一对括号丢弃
  • 6)重复步骤2至5,直到表达式的最右边
  • 7)将operateStack中剩余的运算符依次弹出并压入tmp
  • 8)依次弹出tmp中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式
  • @param expr 中缀表达式
  • @return 后缀表达式
    */

public List midfixToSuffix(String expr) {

/**
 * 将表达式的操作数和运算符转换成集合
 */
List<String> items = parseExpr(expr);
//操作数栈
Stack<String> operateStack = new LinkStack<>();
//临时变量的保存集合,这里使用了List集合
//如果用栈也可以实现,但是需要在最后将弹出栈元素的逆序进行运算
//所以使用List集合避免了这个转换的问题
List<String> tmp = new ArrayList<>();
//操作的位置
int index = 0;
//表达式长度
int len = items.size();
while (index < len) {
    String item = items.get(index);
    //遇到操作数时,将其压tmp;
    if (item.matches("\\d+")) {
        tmp.add(item);
    }else if (item.equals("(")) {//如果是左括号“(”,则直接压入operateStack
        operateStack.push(item);
    } else if (item.equals(")")) {//如果是右括号“)”,则依次弹出operateStack栈顶的运算符,并压入tmp,直到遇到左括号为止,此时将这一对括号丢弃
        while (!operateStack.peek().equals("(")) {
            tmp.add(operateStack.pop());
        }
        //直接弹出栈顶元素即可
        operateStack.pop();
    } else {//遇到运算符时,比较其与operateStack栈顶运算符的优先级
        //如果operateStack为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
        if (operateStack.isEmpty() || "(".equals(operateStack.peek())) {
            operateStack.push(item);
        }else if (priority(item) > priority(operateStack.peek())) {//否则,若优先级比栈顶运算符的高,也将运算符压入operateStack;
            tmp.add(item);
        } else {//否则,将operateStack栈顶的运算符弹出并压入到tmp中,再次转到(4-1)与operateStack中新的栈顶运算符相比较;
            while (!operateStack.isEmpty() && priority(item) <= priority(operateStack.peek())) {
                tmp.add(operateStack.pop());
            }
            //将运算符压入栈
            operateStack.push(item);
        }
    }
    //没一轮结束需要将操作位置往后移动一位
    index++;
}
//解析结束后需要将剩下的栈元素全部弹出来放入到tmp中
while (!operateStack.isEmpty()) {
    tmp.add(operateStack.pop());
}
return tmp;

}
  (四)、计算结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/**
     * 根据后缀表达式计算值
     * @param items 后缀表达式
     * @return 计算结果
     */
    public int calculate(List items) {
        /**
         * 用于保存过程变量和操作符等
         */
        Stack stack = new LinkStack<>();
        //便利
        for (String item : items) {
            //如果为数字,直接放入栈中
            if (item.matches("\d+")) {
                stack.push(item);
            }else {
                //弹出栈顶元素进行运算
                int num2 = Integer.parseInt(stack.pop());
                int num1 = Integer.parseInt(stack.pop());
                int res;
                switch (item) {
                    case "+" :
                        res = num1 + num2;
                        break;
                    case "-" :
                        res = num1 - num2;
                        break;
                    case "*" :
                        res = num1 * num2;
                        break;
                    case "/" :
                        res = num1 / num2;
                        break;
                    default:
                        throw new RuntimeException("非法的运算符:" + item);
                }
                //运算完将结果压入栈中
                stack.push("" + res);
            }
        }
        //整个表达式扫描结束后,此时栈中只剩一个元素,该元素即为结算结果,从栈中弹出即可
        return Integer.parseInt(stack.pop());
    }

  (五)、测试
1
2
3
4
5
6
7
8
9
10
public static void main(String[] args) {
        Calculator calculator = new Calculator();
        List items = calculator.midfixToSuffix("(3+4)*5-6");
        System.out.println("后缀表达式为:" + items);
        int result = calculator.calculate(items);
        System.out.println("运算结果为: " + result);
    }

//后缀表达式为:[3, 4, +, 5, *, 6, -]
//运算结果为: 29

完整的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
public class Calculator {

    public static void main(String[] args) {
        Calculator calculator = new Calculator();
        List items = calculator.midfixToSuffix("(3+4)*5-6");
        System.out.println("后缀表达式为:" + items);
        int result = calculator.calculate(items);
        System.out.println("运算结果为: " + result);
    }

    /**
     * 1)初始化两个栈:运算符栈operateStack和储存中间结果的栈tmp;
     * 2)从左至右扫描中缀表达式;
     * 3)遇到操作数时,将其压tmp;
     * 4)遇到运算符时,比较其与operateStack栈顶运算符的优先级:
     *   4.1)如果operateStack为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
     *   4.2)否则,若优先级比栈顶运算符的高,也将运算符压入operateStack;
     *   4.3)否则,将operateStack栈顶的运算符弹出并压入到tmp中,再次转到(4-1)与operateStack中新的栈顶运算符相比较;
     * 5)遇到括号时:
     *   5.1) 如果是左括号“(”,则直接压入operateStack
     *   5.2) 如果是右括号“)”,则依次弹出operateStack栈顶的运算符,并压入tmp,直到遇到左括号为止,此时将这一对括号丢弃
     * 6)重复步骤2至5,直到表达式的最右边
     * 7)将operateStack中剩余的运算符依次弹出并压入tmp
     * 8)依次弹出tmp中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式
     * @param expr 中缀表达式
     * @return 后缀表达式
     */
    public List midfixToSuffix(String expr) {
        /**
         * 将表达式的操作数和运算符转换成集合
         */
        List items = parseExpr(expr);
        //操作数栈
        Stack operateStack = new LinkStack<>();
        //临时变量的保存集合,这里使用了List集合
        //如果用栈也可以实现,但是需要在最后将弹出栈元素的逆序进行运算
        //所以使用List集合避免了这个转换的问题
        List tmp = new ArrayList<>();
        //操作的位置
        int index = 0;
        //表达式长度
        int len = items.size();
        while (index < len) {
            String item = items.get(index);
            //遇到操作数时,将其压tmp;
            if (item.matches("\d+")) {
                tmp.add(item);
            }else if (item.equals("(")) {//如果是左括号“(”,则直接压入operateStack
                operateStack.push(item);
            } else if (item.equals(")")) {//如果是右括号“)”,则依次弹出operateStack栈顶的运算符,并压入tmp,直到遇到左括号为止,此时将这一对括号丢弃
                while (!operateStack.peek().equals("(")) {
                    tmp.add(operateStack.pop());
                }
                //直接弹出栈顶元素即可
                operateStack.pop();
            } else {//遇到运算符时,比较其与operateStack栈顶运算符的优先级
                //如果operateStack为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
                if (operateStack.isEmpty() || "(".equals(operateStack.peek())) {
                    operateStack.push(item);
                }else if (priority(item) > priority(operateStack.peek())) {//否则,若优先级比栈顶运算符的高,也将运算符压入operateStack;
                    tmp.add(item);
                } else {//否则,将operateStack栈顶的运算符弹出并压入到tmp中,再次转到(4-1)与operateStack中新的栈顶运算符相比较;
                    while (!operateStack.isEmpty() && priority(item) <= priority(operateStack.peek())) {
                        tmp.add(operateStack.pop());
                    }
                    //将运算符压入栈
                    operateStack.push(item);
                }
            }
            //没一轮结束需要将操作位置往后移动一位
            index++;
        }
        //解析结束后需要将剩下的栈元素全部弹出来放入到tmp中
        while (!operateStack.isEmpty()) {
            tmp.add(operateStack.pop());
        }
        return tmp;
    }

    /**
     * 获取运算符的优先级,数字越大优先级越大
     * @param operateChar 运算符
     * @return 优先级
     */
    private int priority(String operateChar) {
        if ("*".equals(operateChar) || "/".equals(operateChar)) {
            return 2;
        }else if ("+".equals(operateChar) || "-".equals(operateChar)) {
            return 1;
        }else {
            //throw new RuntimeException("非法的操作符:" + operateChar);
            return 0;
        }
    }

    /**
     * 将表达式解析成List
     * @param expression 表达式
     * @return
     */
    private List parseExpr(String expression) {
        char[] chars = expression.toCharArray();
        int len = chars.length;
        List items = new ArrayList<>(len);
        int index = 0;
        while (index < len) {
            char c = chars[index];
            //数字
            if (c >= 48 && c <= 57) {
                String tmp = "";
                //操作数大于一位数,主要是通过判断下一位是否为数字
                while (index < chars.length && chars[index] >= 48 && chars[index] <= 57) {
                    tmp += chars[index];
                    index++;
                }
                items.add(tmp);
            }else {
                items.add(c + "");
                index++;
            }
        }
        return items;
    }

    /**
     * 根据后缀表达式计算值
     * @param items 后缀表达式
     * @return 计算结果
     */
    public int calculate(List items) {
        /**
         * 用于保存过程变量和操作符等
         */
        Stack stack = new LinkStack<>();
        //便利
        for (String item : items) {
            //如果为数字,直接放入栈中
            if (item.matches("\d+")) {
                stack.push(item);
            }else {
                //弹出栈顶元素进行运算
                int num2 = Integer.parseInt(stack.pop());
                int num1 = Integer.parseInt(stack.pop());
                int res;
                switch (item) {
                    case "+" :
                        res = num1 + num2;
                        break;
                    case "-" :
                        res = num1 - num2;
                        break;
                    case "*" :
                        res = num1 * num2;
                        break;
                    case "/" :
                        res = num1 / num2;
                        break;
                    default:
                        throw new RuntimeException("非法的运算符:" + item);
                }
                //运算完将结果压入栈中
                stack.push("" + res);
            }
        }
        //整个表达式扫描结束后,此时栈中只剩一个元素,该元素即为结算结果,从栈中弹出即可
        return Integer.parseInt(stack.pop());
    }

}

简单的计算器基本已经写完了。如果你感兴趣的话,可以将上面的代码拿下来自己显现更多的功能,比如说支持小数,其他的运算,表达式中允许有空格等。这些功能实现起来是不难的,只要在上面的基础上做一些改动即可。

原文地址https://www.cnblogs.com/rainple/p/12731553.html

相关文章
|
1月前
|
存储 算法 安全
探究‘公司禁用 U 盘’背后的哈希表算法与 Java 实现
在数字化办公时代,信息安全至关重要。许多公司采取“禁用U盘”策略,利用哈希表算法高效管理外接设备的接入权限。哈希表通过哈希函数将设备标识映射到数组索引,快速判断U盘是否授权。例如,公司预先将允许的U盘标识存入哈希表,新设备接入时迅速验证,未授权则禁止传输并报警。这有效防止恶意软件和数据泄露,保障企业信息安全。 代码示例展示了如何用Java实现简单的哈希表,模拟公司U盘管控场景。哈希表不仅用于设备管理,还在文件索引、用户权限等多方面助力信息安全防线的构建,为企业数字化进程保驾护航。
|
4月前
|
存储 人工智能 算法
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
这篇文章详细介绍了Dijkstra和Floyd算法,这两种算法分别用于解决单源和多源最短路径问题,并且提供了Java语言的实现代码。
126 3
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
|
6月前
|
存储 算法 Java
惊!Java程序员必看:JVM调优揭秘,堆溢出、栈溢出如何巧妙化解?
【8月更文挑战第29天】在Java领域,JVM是代码运行的基础,但需适当调优以发挥最佳性能。本文探讨了JVM中常见的堆溢出和栈溢出问题及其解决方法。堆溢出发生在堆空间不足时,可通过增加堆空间、优化代码及释放对象解决;栈溢出则因递归调用过深或线程过多引起,调整栈大小、优化算法和使用线程池可有效应对。通过合理配置和调优JVM,可确保Java应用稳定高效运行。
178 4
|
2月前
|
存储 算法 Java
Java 内存管理与优化:掌控堆与栈,雕琢高效代码
Java内存管理与优化是提升程序性能的关键。掌握堆与栈的运作机制,学习如何有效管理内存资源,雕琢出更加高效的代码,是每个Java开发者必备的技能。
95 5
|
3月前
|
JSON Java 程序员
Java|如何用一个统一结构接收成员名称不固定的数据
本文介绍了一种 Java 中如何用一个统一结构接收成员名称不固定的数据的方法。
52 3
|
3月前
|
存储 缓存 算法
通过优化算法和代码结构来提升易语言程序的执行效率
通过优化算法和代码结构来提升易语言程序的执行效率
|
3月前
|
算法 测试技术 开发者
在Python开发中,性能优化和代码审查至关重要。性能优化通过改进代码结构和算法提高程序运行速度,减少资源消耗
在Python开发中,性能优化和代码审查至关重要。性能优化通过改进代码结构和算法提高程序运行速度,减少资源消耗;代码审查通过检查源代码发现潜在问题,提高代码质量和团队协作效率。本文介绍了一些实用的技巧和工具,帮助开发者提升开发效率。
67 3
|
3月前
|
存储 算法 Java
🧠Java零基础 - Java栈(Stack)详解
【10月更文挑战第17天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
99 2
|
4月前
|
存储 算法 Java
🚀Java零基础-顺序结构详解 🚀
【10月更文挑战第11天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
52 6
|
4月前
|
存储 缓存 算法
如何通过优化算法和代码结构来提升易语言程序的执行效率?
如何通过优化算法和代码结构来提升易语言程序的执行效率?
105 5