栈和队列,双端队列,如何用链表实现双端队列?如何用双端队列实现栈和队列?
提示:链表用来干嘛?双端队列如何实现栈与队列?
栈:Stack
拿系统栈玩一下就知道栈是啥玩意了
Stack<Integer> stack = new Stack<>();
stack.push(1);
stack.push(2);
System.out.println(stack.pop() +" "+ stack.pop());
结果:2 1
说明栈:是先进后出的数据结构:
队列:queue,LinkedList
也用系统队列玩一下:java中的队列是LinkedList,别整错了
Queue<Integer> queue = new LinkedList<>();
queue.add(1);
queue.add(2);
System.out.println(queue.poll() +" "+ queue.poll());
结果:1 2
说明:队列是先进先出的数据结构
双端队列:链表实现双端队列
这个双端队列,系统没有,咱们自己定义:
双端队列,本身是队列,内部是一个双向链表,可以从头入,尾入,还可以从头出,尾出
这既是双端操作的意思:
我们来实现一下双端队列:DoubleEndsQueue2:T
T代表泛型数据类型:可以是String,Integer,随意
链表的节点:
//双向链表节点
public static class Node<T> {
public T value;//这个T就是任意形式的数据类型包括int啥的,Integer啥的,String等等
//用的时候指定清楚这是啥类型就行
public Node<T> last = null;//指向前一个节点的指针,与parent一个道理,
// 未来在双向二叉树中就可以看到这种,有个父亲指针parent,有左子指针left,右子指针right
public Node<T> next = null;//指向下一个几点的指针,
//初始化,构造函数
public Node(T v) {
value = v;
}
}
——双端队列内部至少是一个双向链表,属性有head和tail维持这个链表
——函数有:
(1)从头部输入新节点value;
(2)从尾部输入新节点value;
(3)从头部输出节点value;
(4)从尾部输出节点value;
手撕双端队列的代码,这没啥可说,必须自己手撕会,就是达到:不看别人的代码,自己也要写出来,调试通过,验证正误:
//复习双端队列
public static class DoubleEndsQueue2<T>{
public Node<T> head;
public Node<T> tail;
public DoubleEndsQueue2(){
head = null;
tail = null;
}
//四个函数:
// (1)从头部输入新节点value;
public void addFromHead(T value){
//既然新来节点,那新建
Node<T> cur = new Node<>(value);
//如果之前压根没有节点
if (head == null){
//则此时cur既是head,又是tail
head = cur;
tail = cur;
}else {
//从头部输入,挂接,换头
head.last = cur;
cur.next = head;
head = cur;
}
}
// (2)从尾部输入新节点value;
public void addFromTail(T value){
//既然新来节点,那新建
Node<T> cur = new Node<>(value);
//如果之前压根没有节点
if (head == null){
//则此时cur既是head,又是tail
head = cur;
tail = cur;
}else{
//从尾部接入,换尾
tail.next = cur;
cur.last = tail;
tail = cur;
}
}
// (3)从头部输出节点value;
public T popFromHead(){
Node<T> cur = head;//head
//就一个点
if (head == tail) {
head = null;
tail = null;
}else {
//将head移动下一个位置,然后把cur与head断开
head = cur.next;
head.last = null;
cur.next = null;
}
return cur.value;
}
// (4)从尾部输出节点value;
public T popFromTail(){
Node<T> cur = tail;//tail
//就一个点
if (head == tail) {
head = null;
tail = null;
}else {
//将tail前移一个位置,然后将tail和cur断开,返回cur
tail = cur.last;
tail.next = null;
cur.last = null;
}
return cur.value;
}
//判空
public boolean isEmpty(){
return head == null;//头结点都没有,那还用说,就是空呗
}
}
测试:
//测试双端队列的正误
public static void test3(){
DoubleEndsQueue2<Integer> queue2 = new DoubleEndsQueue2<>();
queue2.addFromHead(1);//1
queue2.addFromTail(2);//1 2
queue2.addFromHead(3);//3 1 2
queue2.addFromTail(4);//3 1 2 4
Node<Integer> cur = queue2.head;
while (cur != null){
System.out.print(cur.value +" ");
cur = cur.next;
}
System.out.println();
//弹出
Integer a = queue2.popFromHead();
System.out.println(a);
cur = queue2.head;
while (cur != null){
System.out.print(cur.value +" ");
cur = cur.next;
}
System.out.println();
//弹出
Integer b = queue2.popFromTail();
System.out.println(b);
cur = queue2.head;
while (cur != null){
System.out.print(cur.value +" ");
cur = cur.next;
}
}
public static void main(String[] args) {
//test2();
test3();
}
结果:
3 1 2 4
3
1 2 4
4
1 2
完全没有任何问题
请你使用双端队列实现系统栈和队列
双端队列实现系统栈
非常简单,你不是双端都可以操作吗???
栈:先进先出
干脆这样,我让头进,头出就行呗:
(1)栈中属性:属性,就是双端队列一个
(2)仨函数:isEmpyt()判断栈是否为空?
(3)仨函数:push(value)压入元素
(4)仨函数:pop()弹出元素
手撕代码:
//双端队列实现栈
public static class ReviewStack<T>{
//属性,就是双端队列一个
public DoubleEndsQueue2 queue2;
//构造时先生成一个双端队列
public ReviewStack(){
queue2 = new DoubleEndsQueue2<>();
}
//提供仨函数
//(2)仨函数:isEmpyt()判断栈是否为空?
public boolean isEmpty(){
return queue2.isEmpty();//直接用双端队列的判断函数
}
//(3)仨函数:push(value)压入元素
public void push(T value){
queue2.addFromHead(value);//直接头入
}
//(4)仨函数:pop()弹出元素
public T pop(){
return (T) queue2.popFromHead();//头返回即可
}
}
public static void test4(){
ReviewStack<Integer> stack = new ReviewStack<>();
stack.push(1);
stack.push(2);
System.out.println(stack.pop());
System.out.println(stack.pop());
System.out.println(stack.isEmpty());
}
public static void main(String[] args) {
//test2();
//test3();
test4();
}
看结果:
2
1
true
很完美
双端队列实现系统队列
和栈类似,栈是先进后出
队列是先进就先出
那头进,尾出就行了
一样,队列内部有一个双向队列:DoubleEndsQueue2
仨函数:
(1)add(value)头入元素
(2)poll()尾部输出元素
(3)判空isEmpty()
手撕代码:
//用双向队列实现队列
public static class ReviewQueue<T>{
public DoubleEndsQueue2<T> queue2;
public ReviewQueue(){
queue2 = new DoubleEndsQueue2<>();//属性,生成
}
//仨函数:
//(1)add(value)头入元素
public void add(T value){
queue2.addFromHead(value);
}
//(2)poll()尾部输出元素
public T poll(){
return queue2.popFromTail();//尾部输出
}
//(3)判空isEmpty()
public boolean isEmpty(){
return queue2.isEmpty();
}
}
public static void test5(){
ReviewQueue<Integer> queue = new ReviewQueue<>();
queue.add(1);
queue.add(2);
System.out.println(queue.poll());
System.out.println(queue.poll());
System.out.println(queue.isEmpty());
}
public static void main(String[] args) {
//test2();
//test3();
//test4();
test5();
}
结果:
1
2
true
自然是美滋滋的
总结
提示:重要经验:
1)了解系统中的栈,和队列,栈:先进后出,队列:先进先出
2)双向队列底层就是双向链表的操作,增删两个,不过就是在head和tail上操作
3)利用双向队列可以轻易地实现栈和队列。