LinkedList(链表)
动态数组有个明显的缺点:
动态数组可能会造成内存空间的大量浪费
能否用到多少内存就申请多少内存呢?链表就可以办到这一点,链表是一种链式存储的线性表,所有元素的内存地址不一定是连续的。
节点类(Node)
/**
* 节点类
*/
private static class Node<E>{
/**
* 存储的元素
*/
E element;
/**
* 下一个节点
*/
Node<E> next;
/**
* 构造函数
*/
public Node(E element, Node<E> next) {
this.element = element;
this.next = next;
}
}
接口设计
由于链表与动态数组可以抽象出共同的方法,所以我们可以实现接口来优化代码。
抽象接口之后创建对象的方法变为:
List<Interger> list = new LinkedList();
接口设计为:
package 链式结构;
public interface List<E> {
static final int ELEMENT_NOT_FOUND = -1;
/**
* 清除所有元素
*/
void clear();
/**
* 元素的数量
* @return
*/
int size();
/**
* 是否为空
* @return
*/
boolean isEmpty();
/**
* 是否包含某个元素
* @param element
* @return
*/
boolean contains(E element);
/**
* 添加元素到尾部
* @param element
*/
void add(E element);
/**
* 获取index位置的元素
* @param index
* @return
*/
E get(int index);
/**
* 设置index位置的元素
* @param index
* @param element
* @return 原来的元素ֵ
*/
E set(int index, E element);
/**
* 在index位置插入一个元素
* @param index
* @param element
*/
void add(int index, E element);
/**
* 删除index位置的元素
* @param index
* @return
*/
E remove(int index);
/**
* 查看元素的索引
* @param element
* @return
*/
int indexOf(E element);
}
手写LinkedList
LinkedList
package 链式结构.linkedlist;
import org.w3c.dom.Node;
import 链式结构.List;
/**
* @ClassName: LinkedList
* @Description: 链表
* @author: wangz48
* @date: 2021-12-27 9:57
*/
public class LinkedList<E> implements List {
/*==============成员变量================*/
/**
* 链表长度
*/
private int size;
/**
* 头结点
*/
private Node first;
/*===============构造方法===============*/
/**
* 默认无参构造,因为不需要传容量
*/
public LinkedList(){
}
/*===============成员方法===============*/
/**
* 清空链表
* size = 0;
* first = null
*/
@Override
public void clear() {
size = 0;
first = null;
}
@Override
public int size() {
return size;
}
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public boolean contains(Object element) {
return indexOf(element) != ELEMENT_NOT_FOUND;
}
@Override
public void add(Object element) {
add(size,element);
}
@Override
public Object get(int index) {
Node<E> node = node(index);
return node.element;
}
@Override
public Object set(int index, Object element) {
Node<E> node = node(index);
E old = node.element;;
node.element = (E) element;
return old;
}
/**
* 添加元素。需要找index-1的元素
* @param index
* @param element
*/
@Override
public void add(int index, Object element) {
if (index == 0){
first = new Node<>(element, first);
}else {
//前一个节点
Node<E> preNode = node(index - 1);
//新节点
Node<E> node = (Node<E>) new Node(element, preNode.next);
//前一个节点指向新的
preNode.next = node;
}
//长度增加
size++;
}
private Node<E> node(int index){
rangeCheck(index);
Node<E> node = first;
for (int i = 0; i < index; i++) {
node = node.next;
}
return node;
}
/**
* 获取前面的元素,用next指向index+1的节点
* @param index
* @return
*/
@Override
public Object remove(int index) {
rangeCheck(index);
Node<E> node = first;
if (index == 0){
first = first.next;
}else {
Node<E> prevNode = node(index - 1);
prevNode.next = prevNode.next.next;
}
size--;
return node.element;
}
@Override
public int indexOf(Object element) {
if (element == null){
Node<E> node = first;
for (int i = 0; i < size; i++) {
if (node.element == null){return i;}
node = node.next;
}
}else {
Node<E> node = first;
for (int i = 0; i < size; i++){
if (element.equals(node.element)){return i;}
node = node.next;
}
}
return ELEMENT_NOT_FOUND;
}
@Override
public String toString(){
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("size=").append(size).append(",[");
Node<E> node = first;
for (int i = 0; i < size; i++) {
if(i != 0){
stringBuilder.append(",");
}
stringBuilder.append(node.element);
node = node.next;
}
stringBuilder.append("]");
return stringBuilder.toString();
}
/*===============其他方法===============*/
/**
* 边界检查
*/
private void outOfBounds(int index){
throw new IndexOutOfBoundsException("Index"+index+",Size:"+size);
}
/**
* 权限检查
*/
private void rangeCheck(int index){
if (index < 0 || index >= size){
outOfBounds(index);
}
}
/**
* add检查索引越界
*/
private void rangeCheckForAdd(int index){
if (index < 0 || index > size){
outOfBounds(index);
}
}
/*===============节点内部类===============*/
/**
* 节点类
*/
private static class Node<E>{
/**
* 存储的元素
*/
E element;
/**
* 下一个节点
*/
Node<E> next;
/**
* 构造函数
*/
public Node(E element, Node<E> next) {
this.element = element;
this.next = next;
}
}
}
练习
1.删除链表中的节点
分析:
当前节点的值 = .next的值
当前节点的next= .next.next;
class Solution {
public void deleteNode(ListNode node) {
node.val = node.next.val;
node.next = node.next.next;
}
}
2.反转链表
递归解法
class Solution {
public ListNode reverseList(ListNode head) {
//返回条件
if(head == null || head.next == null){return head;}
ListNode newHead = reverseList(head.next);
head.next.next = head;
head.next = null;
return newHead;
}
}
迭代法
class Solution {
public ListNode reverseList(ListNode head) {
if(head == null || head.next == null){return head;}
ListNode newHead = null;
while(head != null){
ListNode tmp = head.next;
head.next = newHead;
newHead = head;
head = tmp;
}
return newHead;
}
}