前言
链表、队列、栈,是数据结构中最基础的几个结构,而链表是最基础的。之后的复杂数据结构大都是在其基础上演化出来的。
链表
一种线程数据结构,与数组不同的是,它在内存空间中不一定是顺序存储的,为了保证链表中元素的连续性,一般使用一个指针来找到下一个元素。
使用java实现一个链表链表,首先需要定义一个节点
1 2 3 4 5 6 7 8
| class Node<T> { T value; Node<T> next;
public Node(T value) { this.value = value; } }
|
因此,对于链表来说,如果想要根据索引查找元素,只能从头开始,时间复杂度O(N).
如果在Node中增加了前驱节点,那么就会成为双向链表。
Java中的LinkedList就是典型的双向链表。
如果在LinkedList上结合HashMap(Set)就是LinkedHashMap(Set),既保证了元素的有序性,有可以O1获取元素。
一个简单的链表实现如下
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
| package table; import java.util.Iterator;
public class LinkList<T> implements Iterable<T>{ private Node head; private int N; public class Node<T> { T item; Node next; public Node(T item, Node next){ this.item = item; this.next = next; } } public LinkList(){ this.head = new Node(null,null); this.N = 0; } public void clear(){ N=0; head.next = null; } public boolean isEmpty(){ return N==0; } public int length(){ return N; } public T get(int i){ Node n = head.next; for (int index =0;index <i;index++){ n = n.next; } return (T) n.item; } public void insert(T t){ Node n = head; while(n.next!=null){ n = n.next; } Node newNode = new Node(t,null); n.next =newNode; N++; } public void insert(int i,T t){ Node pre = head; for (int index = 0;index<=i-1;index++){ pre = pre.next; } Node curr = pre.next; Node newNode = new Node(t,curr); pre.next = newNode; N++; } public T remove (int i){ Node pre = head; for (int index = 0;index<=i-1;index++){ pre = pre.next; } Node curr = pre.next; Node fur = curr.next; pre.next = fur; N--; return (T) curr.item;
} public int indexOf(T t){ Node n = head; for (int i =0;n.next!=null;i++){ n = n.next; if (n.item.equals(t)){ return i; } } return -1; } public void reverse(){ if (isEmpty()){ return; } else{ reverse(head.next); } } public Node reverse(Node curr){ if(curr.next==null){ head.next = curr; return curr; } Node per = reverse(curr.next); per.next = curr; curr.next = null; return curr; }
@Override public Iterator iterator() {
return new LIterator(); } private class LIterator implements Iterator { private Node n; public LIterator(){ this.n = head; } @Override public boolean hasNext() { return n.next!=null; }
@Override public Object next() { n = n.next; return n.item; } } }
|
算法题中,链表经常出现,比较基础的题型包括:链表的翻转,环判断,环入口,多链表求第K大/小元素等。链表也是实现跳表的基础。
队列/栈
链表和队列本质上是一种特殊的单链表,不同之处在于他们限制了元素的插入/删除顺序。
队列:
对于队列来说,元素从一端进入,从另一端出去,也就是先入的元素先被删除,英文叫做:First In,First Out,简写FIFO。
队列比较经典的使用是在广度优先搜索当中(树的层序遍历其实也是广度优先搜索)。除此之外,队列也可以拥有顺序,称之为优先队列,在java已经有实现,称之为PriorityQueue。
队列实现:
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
| package zhan; import java.util.Iterator;
public class Queue<T> implements Iterable<T> { private class Node<T>{ public T item; public Node next; public Node(T item,Node next){ this.item = item; this.next = next; } } private Node head; private int N; private Node last; public Queue(){ this.head = new Node(null,null); this.last = null; this.N = 0; } public boolean isEmpty(){ return N==0; } public int size(){ return N; } public void enqueue(T t){ if (last == null){ last= new Node(t,null); head.next = last; } else{ Node oldlast = last; last = new Node(t,null); oldlast.next = last; } N++; } public T dequeue(){ if (isEmpty()){ return null; } Node oldeFirst = head.next; head.next = oldeFirst.next; N--; if (isEmpty()){ last = null; } return (T)oldeFirst.item; } @Override public Iterator<T> iterator(){ return new QIterator(); } private class QIterator implements Iterator{ private Node n; public QIterator(){ this.n = head; } @Override public boolean hasNext() { return n.next!=null; }
@Override public Object next() { n = n.next; return (T)n.item; } } }
|
栈:
栈则相反,元素从一端进,就要从一端出。也就是先进后出,英文叫做:First In,Last Out,简称FILO。
栈在算法中经常使用到,诸如括号标点匹配问题,单调栈问题等,递归也是一种特殊的对栈的使用。
stack实现:
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
| package zhan; import java.util.Iterator;
public class Stack<T> implements Iterable<T>{
private class Node<T>{ public T item; public Node next; public Node(T item,Node next){ this.item =item; this.next = next; } } private int N; private Node head; public Stack(){ this.N = N; this.head = new Node(null,null); } public boolean isEmpty(){ return N==0; } public int size(){ return N; } public void push(T t){ Node oldNode = head.next; Node newNode = new Node(t,null); head.next = newNode; newNode.next = oldNode; N++; } public T pop(){ Node oldFirst = head.next; if (oldFirst==null){ return null; } head.next = oldFirst.next; N--; return (T)oldFirst.item; } @Override public Iterator<T> iterator() { return new LIterator(); } private class LIterator implements Iterator{ private Node n; public LIterator(){ this.n = head; } @Override public boolean hasNext() { return n.next!=null; } @Override public Object next() { n = n.next; return n.item; } }
}
|