栈与队列的区别
栈和队列是两种重要的线性数据结构.
栈是后进先出,队列是先进先出.
实现栈的方式
方法1:使用java.util包下的Stack
方法2:使用数组实现
public class 数组实现栈<E> {
private Object[] stack;
private int size;
public 数组实现栈() {
stack=new Object[10];//初始长度
}
//判断栈是否为空
public boolean isEmpty() {
return size==0;
}
public E peek() {
if (isEmpty()) {
return null;
}
return (E) stack[size-1];
}
public E pop() {
E e=peek();
stack[size-1]=null;
size--;
return e;
}
private void ensureCapacity(int size) {
int len=stack.length;
if (size>len) {
int newlen=10;
stack=Arrays.copyOf(stack, newlen);
}
}
public E push(E item) {
ensureCapacity(size+1);
stack[size++]=item;
return item;
}
public static void main(String[] args) {
数组实现栈<Integer> s=new 数组实现栈<>();
s.push(1);
s.push(2);
System.out.println("栈中元素个数:"+s.size);
System.out.println("栈顶元素为:"+s.pop());
System.out.println("栈顶元素为:"+s.pop());
}
}
方法3:使用链表实现
class Node<E>{
Node<E> next=null;
E data;
public Node(E data) {
// TODO Auto-generated constructor stub
this.data=data;
}
}
public class 链表实现栈<E> {
Node<E> top =null;
//头插法
public void push(E data) {
Node<E> newNode=new Node(data);
newNode.next=top;
top=newNode;
}
public boolean isEmpty() {
return top==null;
}
public E pop() {
if (this.isEmpty()) {
return null;
}
E data=top.data;
top=top.next;
return data;
}
public E peek() {
if (isEmpty()) {
return null;
}
return top.data;
}
}
如何用O(1)的时间复杂度求栈中最小元素
如果当前入栈的元素比原来栈中的最小值还小,则把这个值压入保存最小元素的栈中.在出栈时,如果当前出栈的元素恰好为当前栈中的最小值,保存最小值的栈顶元素也出栈,使得当前最小值变为其入栈之前的那个最小值.
如何实现队列
方法1:使用数组
方法2:使用链表
如何用两个栈模拟队列操作
使用栈A和栈B模拟队列Q
命令栈A为插入栈 ,栈B为弹出栈
入队列的操作为 入栈A
出队列的操作为 :
情形1: 若栈B不为空,直接弹出栈B的数据
情形2:若栈B为空,依次弹出栈A的数据放入栈B中,再弹出栈B的数据.
实现代码如下:
public class 两个栈模拟队列<E> {
private Stack<E> s1=new Stack<>();
private Stack<E> s2=new Stack<>();
public synchronized void put(E e) {
s1.push(e);
}
public synchronized E pop() {
if (s2.isEmpty()) {
while(!s1.isEmpty()) {
s2.push(s1.pop());
}
}
return s2.pop();
}
public synchronized boolean empty() {
return s1.isEmpty()&&s2.isEmpty();
}
public static void main(String[] args) {
两个栈模拟队列<Integer> q=new 两个栈模拟队列<Integer>();
q.put(1);
q.put(2);
System.out.println("队列首元素:"+q.pop());
System.out.println("队列首元素"+q.pop());
}
}
判断一个数是否为2的n次方
最直观的解法是用1做移位操作,然后判断移位后的值是否与给定的数相等.这个算法的时间复杂度O(lgn).
代码实现如下:
public static boolean isPower(int n) {
if (n<1) {
return false;
}
int i=1;
while(i<=n) {
if (i==n) {
return true;
}
i<<=1;
}
return false;
}
算法优化:
观察发现,2的n次方转为2进制后只有1位是1如num=00010000,那么num-1=00001111,将00010000和00001111进行与(&)操作结果为0.
推出:若num为2的n次方,则num&(num-1)==0.
代码实现如下:
public static boolean isPower2(int n) {
if (n<1) {
return false;
}
int m=n&(n-1);
return m==0;
}
如何求二进制数中1的个数
我们可以通过位操作完成算法.
首先判断这个数的最后一位是否为1,如果为1,计数器加1,然后通过右移丢弃最后一位.
循环执行直到这个数等于0为止.
代码实现:
public static int countOne(int n) {
int count=0;
while(n>0) {
//如果最后一位是1
if ((n&1)==1) {
count++;
}
n>>=1;
}
return count;
}
算法优化:
我们在判断一个数是否为2的n次方时说到了一个特性:2进制数0100&(0100-1)=0,即如果2进制数n有1,则n&(n-1)后这个1必为0.
代码实现:
public static int countOne2(int n) {
int count=0;
while(n>0) {
n=n&(n-1);
count++;
}
return count;
}