链表
之前看过了动态数组,栈和队列,虽然我们把第一个叫做动态数组,但是,他们的底层实质上还是静态数组。靠
resize来实现动态数组。而链表是真正的数据结构
- 链表需要一个节点。
- 数据存储在链表中
相当于是一串火车,将数据放在车厢中,两个车厢之间还需要一个个节点来相互串联。
优点:实现了真正的动态。
缺点:无法进行随机访问
public class LinkedList<E> {
private class Node {
public E e;
public Node next;
public Node(E e) {
this(e, null);
}
public Node(E e, Node next) {
this.e = e;
this.next = next;
}
public Node() {
this(null, null);
}
@Override
public String toString() {
return e.toString();
}
}
private Node head;
private int size;
public LinkedList(Node head, int size) {
head = null;
this.size = 0;
}
//获取链表中的元素个数
public int getSize() {
return size;
}
//返回链表是否为空
public boolean isEmpty() {
return size == 0;
}
//链表添加新的元素
public void addFirst(E e) {
// Node newNode = new Node((E) node);
// newNode.next = head;
// head = newNode;
head = new Node(e, head);
size++;
}
//在链表的index位置添加新的元素e
//在链表中不是一个常用的操作 :)
public void add(int index, E e) {
if (index < 0 || index > size) {
throw new IllegalArgumentException("Add failed,Illegal index");
}
if (index == 0) {
addFirst(e);
} else {
Node prev = new Node(e);
for (int i = 0; i < index - 1; i++) {
prev.next = prev;
}
// Node node = new Node(e);
// prev.next = node.next;
// prev.next = node;
prev.next = new Node(e,prev.next);
size++;
}
}
//在末尾添加元素
public void addLast(E e){
add(size,e);
}
这是自己建立的链表,在此处,一定要注意几点
- 在增加或删除元素时,不要忘了维护size
- 再添加链表时,一定不要忘了顺序的问题,一定是先prev.next = node.next.之后才是prev.next = node;
- 一开始的时候 head = prev
再添加操作时,由于头结点的上一个节点时null,所以我们需要特殊处理,为了解决这个问题,我们增加了一个虚拟
头结点。这个节点不存出任何数据。
public class LinkedList<E> {
private class Node {
public E e;
public Node next;
public Node(E e) {
this(e, null);
}
public Node(E e, Node next) {
this.e = e;
this.next = next;
}
public 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 LinkedList(Node head, int size) {
head = null;
this.size = 0;
}
//获取链表中的元素个数
public int getSize() {
return size;
}
//返回链表是否为空
public boolean isEmpty() {
return size == 0;
}
//在链表的index位置添加新的元素e
//在链表中不是一个常用的操作 :)
public void add(int index, E e) {
if (index < 0 || index > size) {
throw new IllegalArgumentException("Add failed,Illegal index");
}
Node prev = dummyHead;
for (int i = 0; i < index; i++) {
prev.next = prev;
}
// Node node = new Node(e);
// prev.next = node.next;
// prev.next = node;
prev.next = new Node(e, prev.next);
size++;
}
//链表添加新的元素
public void addFirst(E e) {
// Node newNode = new Node((E) node);
// newNode.next = head;
// head = newNode;
add(0,e);
size++;
}
//在末尾添加元素
public void addLast(E e) {
add(size, e);
}
}
链表的遍历,增 删 改 查。
public class LinkedList<E> {
private class Node {
public E e;
public Node next;
public Node(E e) {
this(e, null);
}
public Node(E e, Node next) {
this.e = e;
this.next = next;
}
public Node() {
this(null, null);
}
@Override
public String toString() {
return e.toString();
}
}
private Node dummyHead;
private int size;
public LinkedList() {
dummyHead = new Node();
size = 0;
}
//获取链表中的元素个数
public int getSize() {
return size;
}
//返回链表是否为空
public boolean isEmpty() {
return size == 0;
}
//在链表的index位置添加新的元素e
//在链表中不是一个常用的操作 :)
public void add(int index, E e) {
if (index < 0 || index > size) {
throw new IllegalArgumentException("Add failed,Illegal index");
}
Node prev = dummyHead;
for (int i = 0; i < index; i++) {
prev= prev.next ;
}
// Node node = new Node(e);
// prev.next = node.next;
// prev.next = node;
prev.next = new Node(e, prev.next);
size++;
}
//链表添加新的元素
public void addFirst(E e) {
// Node newNode = new Node((E) node);
// newNode.next = head;
// head = newNode;
add(0, e);
}
//在末尾添加元素
public void addLast(E e) {
add(size, e);
}
/**
* 遍历整个列表
* 实际过程中不会这么用
* 仅供联系
*
* @param index
* @return
*/
public E get(int index) {
if (index < 0 || index > size) {
throw new IllegalArgumentException("Get failed Illegal index");
}
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);
}
//修改链表的第index(0-based)个位置的元素为e
//在链表中不是一个常用的操作,练习用 :)
public void set(int index, E e) {
if (index < 0 || index >= size) {
throw new IllegalArgumentException("Set Failed,illegal index");
}
Node cur = dummyHead.next;
for (int i = 0; i < index; i++) {
cur = cur.next;
}
cur.e = 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;
}
@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 E remove(int index) {
if (index > 0 || index < size) {
throw new IllegalArgumentException("remove failed");
}
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);
}
链表的时间复杂度
- addLast(e):O(n)
- addFirst(e):O(1)
- add(index,e):O(n)
- setIndex(e):O(n)
- get(index):O(n)
- contains(e):O(n)
如果只对链表头进行操作,那么他的时间复杂度是O(1),所以我们来尝试一下利用链表来做栈的可能性。
import java.util.List;
/**
* @author shkstart
* @create 2019-11-29 13:03
*/
public class LinkedListStack<E> implements Stack<E>{
private LinkedList<E> list;
public LinkedListStack() {
list = new LinkedList<E>();
}
@Override
public int getSize() {
return getSize();
}
@Override
public void push(E e) {
list.addFirst(e);
}
@Override
public boolean isEmpty() {
return isEmpty();
}
@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 static void main(String[] args) {
LinkedListStack<Integer> stack = new LinkedListStack<Integer>();
for (int i = 0; i < 5; i++) {
stack.push(i);
System.out.println(stack);
}
stack.pop();
System.out.println(stack);
}
}
做完了栈,同样的 我们试验一下利用链表实现队列。
private class Node {
public E e;
public Node next;
public Node(E e, Node next) {
this.e = e;
this.next = next;
}
public Node(E e) {
this(e, null);
}
public Node() {
this(null, null);
}
@Override
public String toString() {
return e.toString();
}
}
private Node tail, head;
private int size;
public LinkedListQueue(Node tail, Node head, int size) {
this.tail = null;
this.head = null;
this.size = 0;
}
public LinkedListQueue() {
}
@Override
public int getSize() {
return getSize();
}
@Override
public boolean isEmpty() {
return isEmpty();
}
@Override
public void enqueue(E e) {
if (tail.next == null) {
Node node = new Node(e);
tail = head;
} else {
tail.next = new Node(e);
tail = tail.next;
}
size++;
}
@Override
public E dequeue() {
if (isEmpty()) {
throw new IllegalArgumentException("dequeue出错!");
}
Node ret = head;
head = head.next;
ret.next = null;
if (head == null) {
tail = head;
}
size--;
return ret.e;
}
@Override
public E getFront() {
if (isEmpty()) {
throw new IllegalArgumentException("Queue is empty");
}
return head.e;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Queue:");
builder.append("front [");
Node cur = head;
while (cur != null) {
cur = cur.next;
}
builder.append("Null tail");
return builder.toString();
}
public static void main(String[] args) {
LinkedListQueue<Integer> LinkedListQueue = new LinkedListQueue<Integer>();
for (int i = 0; i < 10; i++) {
LinkedListQueue.enqueue(i);
System.out.println(LinkedListQueue);
if (i % 3 == 2) {
LinkedListQueue.dequeue();
System.out.println(LinkedListQueue);
}
}
}
在这里的链表我们写了尾指针!
来源:https://www.cnblogs.com/xiaobaoa/p/11960642.html