链表的优点在于对表头元素的插入和删除复杂度很低,所以对于链表实现的栈复杂度很低。
链表的代码
/**
* @Author: Cui
* @Date: 2020/7/9
* @Description:
*/
public class LinkedList<E> {
private class Node{
E e;
Node next;
Node(E e,Node next){
this.e = e;
this.next = next;
}
Node(E e){
this(e,null);
}
Node(){
this(null,null);
}
@Override
public String toString(){
return e.toString();
}
}
private Node dummyHead;
private int size;
public LinkedList(){
dummyHead = new Node(null,null);
size = 0;
}
public int getSize() {
return size;
}
public boolean isEmpty(){
return size == 0;
}
//在链表头添加新的元素e
public void addFirst(E e){
add(0,e);
}
/**
* 在链表的index位置添加新的元素e,在链表中不是一个常用的操作
* @param index
* @param e
*/
public void add(int index,E e){
if(index < 0 || index > size){
throw new IllegalArgumentException("索引错误");
}
Node prev = dummyHead;
for(int i = 0; i < index ; i++){
prev = prev.next;
}
prev.next = new Node(e,prev.next);
size++;
}
/**
* 向链表末尾添加元素
* @param e
*/
public void addLast(E e){
add(size,e);
}
/**
* 获取链表的第index个元素
* @param index
* @return
*/
public E get(int index){
if(index < 0 || index > size){
throw new IllegalArgumentException("索引错误");
}
Node cur = dummyHead.next;
for(int i = 0; i < index; i++){
cur = cur.next;
}
return cur.e;
}
//获取链表的第一个元素
public E getFirst(){
return get(0);
}
//获取链表的最后一个元素
public E getLast(){
return get(size-1);
}
public void set(int index,E e){
if(index < 0 || index > size){
throw new IllegalArgumentException("索引错误");
}
Node cur = dummyHead.next;
for(int i = 0; i < index; i++){
cur = cur.next;
}
cur.e = e;
}
public boolean contains(E e){
Node cur = dummyHead.next;
while (cur != null){
if(cur.e.equals(e)){
return true;
}
cur = cur.next;
}
return false;
}
public E remove(int index){
if(index < 0 || index > size){
throw new IllegalArgumentException("索引错误");
}
Node prev = dummyHead;
for(int i = 0; i < index; i++){
prev = prev.next;
}
Node retNode = prev.next;
prev.next = retNode.next;
retNode.next = null;
size--;
return retNode.e;
}
//删除第一个元素
public E removeFirst(){
return remove(0);
}
//删除链表最后一个元素
public E removeLast(){
return remove(size-1);
}
@Override
public String toString() {
StringBuilder res = new StringBuilder();
Node cur = dummyHead.next;
while (cur != null){
res.append(cur+"->");
cur = cur.next;
}
res.append("null");
return res.toString();
}
}
栈的接口
public interface Stack<E> {
//查看栈的长度
int getSize();
//查看栈是否为空
boolean isEmpty();
//压栈
void push(E e);
//出栈
E pop();
//查看栈顶元素
E peek();
}
栈的实现
import com.yunding.dataStructures.interf.Stack;
/**
* @Author: Cui
* @Date: 2020/7/10
* @Description:
*/
public class LinkedListStack<E> implements Stack<E> {
private LinkedList<E> list;
public LinkedListStack() {
this.list = new LinkedList<>();
}
//获取链表元素的个数
@Override
public int getSize() {
return list.getSize();
}
//判断是否为空
@Override
public boolean isEmpty() {
return list.isEmpty();
}
//入栈
@Override
public void push(E e) {
list.addFirst(e);
}
//出栈
@Override
public E pop() {
return list.removeFirst();
}
//查看栈顶元素
@Override
public E peek() {
return list.getFirst();
}
@Override
public String toString() {
StringBuilder res = new StringBuilder();
res.append("Stack:top ");
res.append(list);
return res.toString();
}
}
测试
public class Main {
public static void main(String[] args) {
LinkedListStack<Integer> stack = new LinkedListStack<>();
for(int i = 0; i < 5; i++ ){
stack.push(i);
}
System.out.println(stack);
System.out.println("弹出:"+stack.pop());
System.out.println(stack);
}
}
结果
链表实现队列
链表实现队列就不能复用上面链表的代码了,因为队列是先入先出,而对于一般链表来说对于队尾的插入操作是复杂度很高的,需要从表头一直遍历到表尾,所以需要重写链表添加表尾的标志。
import com.yunding.dataStructures.interf.Queue;
/**
* @Author: Cui
* @Date: 2020/7/11
* @Description:
*/
public class LinkedListQueue<E> implements Queue<E> {
private class Node{
E e;
Node next;
Node(E e, Node next){
this.e = e;
this.next = next;
}
Node(E e){
this(e,null);
}
Node(){
this(null,null);
}
@Override
public String toString(){
return e.toString();
}
}
private Node head,tail;
private int size;
public LinkedListQueue(){
head = null;
tail = null;
size = 0;
}
//获取队内元素个数
@Override
public int getSize() {
return size;
}
//判断元素是否为空
@Override
public boolean isEmpty() {
return size == 0;
}
//入队
@Override
public void enqueue(E e) {
if(tail == null){
tail = new Node(e);
head = tail;
}else {
tail.next = new Node(e);
tail = tail.next;
}
size ++;
}
//出队
@Override
public E dequeue() {
if(isEmpty()){
throw new IllegalArgumentException("队列为空");
}
Node retNode = head;
head = head.next;
retNode.next = null;
if(head == null){
tail = null;
}
size --;
return retNode.e;
}
//获取队头元素
@Override
public E getFront() {
if(isEmpty()){
throw new IllegalArgumentException("队列为空");
}
return head.e;
}
@Override
public String toString() {
StringBuilder res = new StringBuilder();
res.append("Queue: front");
Node cur = head;
while (cur != null){
res.append(cur+"->");
cur = cur.next;
}
res.append("null tail");
return res.toString();
}
}
用tail来记录队的最后一个元素,这样可以直接操作队尾,可以降低队列的复杂度。