Java 语言中的 Stack 类,有什么问题?

当新建一个栈时,不推荐写成:

Stack<Integer> stack=new Stack<>()

而是:

Deque<Integer> stack=new ArrayDeque<>()

 

 

就来说说Java 语言中的 Stack 类,有什么问题?

Java中的Stack类继承了Vector这个类。Vector是一个动态数组

这样Stack就继承了Vector的所有公有方法

Vector作为动态数组,有能力在数组中的任何位置添加或删除元素,Stack也有了这样的能力

stack.add(1,666);

对于栈来说,指定在index为1这个位置插入666这个元素,破坏了栈这种数据结构的封装

用户可能会有意无意地调用这些操作,这就将成为bug的来源

 

 

出现这样的问题,原因是:

Stack和Vector之间的关系不应该是继承关系,而应该是组合关系(composition)

继承:is-a 是一个,例如:猫是一个动物,猫类继承了动物类

组合:has-a 有一个,例如:车里有一台发动机,发动机类和车类是组合关系(车中有发动机类的对象这个成员变量)

在真实世界中,真正的继承关系很少,组合关系更常用多用组合,少用继承

 

 

Java官方不改Stack类的原因:

若修改,使用老版本Java的程序将在新的Java环境下无法执行

 

 

Deque接口:

Deque其实是双端队列的意思,可以在两端进行插入和删除操作,然后真正的栈只能在同一端做插入和删除操作。

就如前面所说,Stack类的问题是继承了Vector这个类的若干不需要的方法,破坏了封装性。而Deque接口的stack依然有不需要的方法,这是Java的历史遗留问题,现在已经无解了。

总结:虽然 Java 官方推荐使用 Deque 接口实现 stack,但是这样的 stack 也破坏了封装性,并不安全

 

 

LinkedList与ArrayDeque的区别:

使用ArrayDeque动态数组,如果触发了扩容操作,世界复杂度为O(n)

使用LinkedList链表,不会牵扯到扩容问题,因此每一个添加操作,时间复杂夫欧式O(1)

可实际上,当数据量达到一定程度的时候,链表的性能是远低于动态数组的,因为链表每添加一个元素都要重新创建一个Node类对象,也就是进行一次new的内存操作,而对内存的操作是非常慢的

总结:在实践中,尤其是面对大规模数据的时候,不应该使用链表

 

对于ArrayList,如果你的应用场景不需要线程安全的特性,那么对于动态数组,应该使用 ArrayList

 

 

Stack与ArrayDeque方法的不同:

Stack:

stack.push()

stack.pop()

stack.peek()

 

ArrayDeque:

stack.addLast()

stack.removeLast()

stack.peekLast()

 

 

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Java语言实现凸包算法可以使用 Graham 扫描算法。以下是一个简单的示例代码: ```java import java.util.*; public class ConvexHull { public static List<Point> convexHull(List<Point> points) { // 如果点的数量小于等于1,则返回点列表 if (points.size() <= 1) { return points; } // 对点按照x坐标进行排序 Collections.sort(points); // 创建一个栈来保存凸包上的点 Stack<Point> stack = new Stack<>(); // 将前两个点加入栈 stack.push(points.get(0)); stack.push(points.get(1)); // 从第三个点开始,依次判断是否为凸包上的点 for (int i = 2; i < points.size(); i++) { Point top = stack.pop(); while (!stack.isEmpty() && orientation(stack.peek(), top, points.get(i)) <= 0) { top = stack.pop(); } stack.push(top); stack.push(points.get(i)); } // 将栈的点转换成列表 List<Point> hull = new ArrayList<>(stack); Collections.reverse(hull); return hull; } // 判断点a、b、c的方向 public static int orientation(Point a, Point b, Point c) { return (b.y - a.y) * (c.x - b.x) - (b.x - a.x) * (c.y - b.y); } public static void main(String[] args) { List<Point> points = new ArrayList<>(); points.add(new Point(0, 0)); points.add(new Point(1, 1)); points.add(new Point(2, 2)); points.add(new Point(3, 3)); points.add(new Point(0, 3)); List<Point> hull = convexHull(points); System.out.println("Convex Hull:"); for (Point p : hull) { System.out.println(p); } } } class Point implements Comparable<Point> { int x, y; public Point(int x, int y) { this.x = x; this.y = y; } @Override public int compareTo(Point other) { if (this.x == other.x) { return Integer.compare(this.y, other.y); } return Integer.compare(this.x, other.x); } @Override public String toString() { return "(" + x + ", " + y + ")"; } } ``` 在上面的代码,我们定义了一个 `Point` 类来表示一个二维点,然后实现了 `convexHull` 方法来计算给定点集的凸包。最后,我们在 `main` 方法测试了这个算法,并输出了计算结果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值