目录
(4)对头插法和尾插法代码进行简化(调用任意位置添加的方法)
一、链表
链表是真正的动态数据结构,也是最简单的动态数据结构。
动态数据结构还有:二叉树,trie等
优点:不需要处理固定容量的问题,真正的动态
缺点:丧失了随机访问的能力
学习链表有助于更深理解引用和递归
二、代码实现
1.创建结点
使用内部类来创建结点
//使用内部类——创建结点
class Node<T>{
T data;//节点本身
Node next;//指向下个节点
2.构造函数
两个构造函数(传入的参数不同)
public Node(T data){
this.data=data;
this.next=null;
}
public Node(T data,Node next){
this.data=data;
this.next=null;
}
}
3.链表的相关属性
头结点和结点个数(链表长度)
private Node head;//头结点
private int size;//表示链表中有多少个结点
4.添加虚拟节点
public SelfLinkedList(){
//创建一个虚拟头结点
Node dummyHead=new Node(Integer.MIN_VALUE);
this.head=dummyHead;
this.size=0;
dummyHead.next=head;
}
5.判断链表是否为空
public boolean isEmpty(){
return this.size==0;
}
6.添加方法
(1)在头部添加
public void addHead(T data){
//创建一个节点
Node node= new Node(data);
//挂接
node.next=this.head;
this.head=node;
//更新size
this.size++;
}
(2)在尾部添加
public void addTail(T data){
Node node=new Node(data);
//针对空链表做处理
if(this.head==null){
this.head=node;
this.size++;
return;
}
Node curNode=this.head;
while(curNode.next!=null){
curNode=curNode.next;
}
curNode.next=node;
this.size++;
}
(3)在索引位置添加
//在任意位置添加
public void add(int index,T data){
//判断index是否有效
if(index<0||index>this.size){
throw new IllegalArgumentException("index is invalid");
}
//创建一个节点
Node node= new Node(data);
//特殊处理1:如果索引为0,
if(index==0){
this.head=new Node(data,this.head);
this.size++;
return;
}
//特殊处理2:链表为空(异常已抛出)
//找前驱结点,从头开始找,让索引移动index-1次
Node pre=this.head;
for(int i=1;i<=index;i++){
pre=pre.next;
}
//开始进行结点的挂接
node.next=pre.next;
pre.next=node;
this.size++;
}
(4)对头插法和尾插法代码进行简化(调用任意位置添加的方法)
//在头部添加
public void addHead(T data){
add(0,data);
}
//在尾部添加
public void addTail(T data){
add(this.size,data);
}
7.打印链表(遍历,重写toString方法)
//打印整个链表
@Override
public String toString() {
//从this。head开始一直向后
Node curNode=this.head.next;
StringBuilder sb=new StringBuilder();
while(curNode!=null){
sb.append(curNode.data+"-->");
curNode=curNode.next;
}
sb.append("null");
return sb.toString();
}
8.获取链表元素个数(链表长度)
//获取链表中元素的个数
public int getSize(){
return this.size;
}
9.获取链表结点
(1)获取头结点
//获取链表的头结点
public Optional getFirst(){
if(this.head.next==null){
return Optional.empty();
}
return Optional.ofNullable(this.head.next.data);
}
(2)获取尾结点
//获取链表的尾结点
public Optional getLast(){
if(this.head.next==null){
return Optional.empty();
}
Node<T> curNode=this.head;
while(curNode.next!=null){
curNode=curNode.next;
}
return Optional.of(curNode.data);
}
(3)获取指定位置结点
//从链表中获取任意位置的结点
public T get(int index) {
if (index < 0 || index >= this.size) {
throw new IllegalArgumentException("index is invalid");
}
Node<T> curNode = this.head.next;
int i = 0;
while (i < index) {
curNode = curNode.next;
i++;
}
return curNode.data;
}
10.判断结点是否存在
//从链表中查找指定位置元素是否存在
public boolean contains(T data) {
Node curNode = this.head.next;
while (curNode != null) {
if (curNode.data.equals(data)) {
return true;
}
}
return false;
}
11.删除结点
(1)删除头结点
//从链表的头部删除元素
public T removeHead() {
if (this.isEmpty()) {
return null;
}
Node<T> delNode = this.head.next;
this.head.next = delNode.next;
delNode.next = null;
//更新size;
this.size--;
return delNode.data;
}
(2)删除尾节点
//链表的尾部删除元素
public T removeTail() {
if (this.isEmpty()) {
return null;
}
Node<T> pre = this.head;
while (pre.next.next != null) {
pre = pre.next;
}
Node<T> delNode = pre.next;
pre.next = delNode.next;
delNode.next = null;
//更新size;
this.size--;
return delNode.data;
}
(3)在指定位置删除结点
//删除任意位置的结点
public T remove(int index){
if(index<0||index>=this.size){
throw new IllegalArgumentException("index is invalid");
}
//找删除结点的前驱
Node<T>pre=this.head;
int i=0;
while(i<index){
pre=pre.next;
i++;
}
Node<T>delNode=pre.next;
pre.next=delNode.next;
delNode.next=null;
this.size--;
return delNode.data;
}
(4)删除元素
//根据值从链表中删除元素
public int removeByValue(T value){
int count=0;
//定义前驱结点
Node<T>pre=this.head;
while(pre.next!=null){
Node curNode=pre.next;
if(curNode.data.equals(value)){
pre.next=pre.next.next;
curNode.next=null;
this.size--;
count++;
}else{
pre=pre.next;
}
}
return count;
}
(5)不使用虚拟节点删除
//不使用虚拟头结点
public int removeByValue2(T val){
int count = 0;
Node<T> realHead = this .head.next;
while(realHead!=null&&realHead.data.equals(val)){
realHead=realHead.next;
this.size--;
count++;
}
//判断链表是否为空
if(realHead==null){
return count;
}
//头结点不是删除的点
Node pre = realHead;
while(pre.next!=null){
Node<T> delNode = pre.next;
if(delNode.equals(val)){
pre.next = delNode .next;
delNode.next = null;
this.size--;
count++;
}else{
pre = pre .next;
}
}
return count;
}
三、完整代码
package com.algo.lesson.lesson03;
import java.util.Optional;
import java.util.Random;
public class SelfLinkedList<T> {
//使用内部类——创建结点
class Node<T> {
T data;//节点本身
Node next;//指向下个节点
public Node(T data) {
this.data = data;
this.next = null;
}
public Node(T data, Node next) {
this.data = data;
this.next = null;
}
}
//链表相关的属性和方法
private Node head;//头结点
private int size;//表示链表中有多少个结点
public SelfLinkedList() {
//创建一个虚拟头结点
Node dummyHead = new Node(Integer.MIN_VALUE);
this.head = dummyHead;
this.size = 0;
dummyHead.next = head;
}
//判断链表是否为空
public boolean isEmpty() {
return this.size == 0;
}
//向链表中添加结点
//在头部添加
public void addHead(T data) {
/*//创建一个节点
Node node= new Node(data);
//挂接
node.next=this.head;
this.head=node;
//更新size
this.size++;*/
add(0, data);
}
//在尾部添加
public void addTail(T data) {
/*Node node=new Node(data);
//针对空链表做处理
if(this.head==null){
this.head=node;
this.size++;
return;
}
Node curNode=this.head;
while(curNode.next!=null){
curNode=curNode.next;
}
curNode.next=node;
this.size++;*/
add(this.size, data);
}
//在任意位置添加
public void add(int index, T data) {
//判断index是否有效
if (index < 0 || index > this.size) {
throw new IllegalArgumentException("index is invalid");
}
//创建一个节点
Node node = new Node(data);
//特殊处理1:如果索引为0,
if (index == 0) {
this.head = new Node(data, this.head);
this.size++;
return;
}
//特殊处理2:链表为空(异常已抛出)
//找前驱结点,从头开始找,让索引移动index-1次
Node pre = this.head;
for (int i = 1; i <= index; i++) {
pre = pre.next;
}
//开始进行结点的挂接
node.next = pre.next;
pre.next = node;
this.size++;
}
//打印整个链表
@Override
public String toString() {
//从this。head开始一直向后
Node curNode = this.head.next;
StringBuilder sb = new StringBuilder();
while (curNode != null) {
sb.append(curNode.data + "-->");
curNode = curNode.next;
}
sb.append("null");
return sb.toString();
}
//从链表中查找指定位置元素是否存在
public boolean contains(T data) {
Node curNode = this.head.next;
while (curNode != null) {
if (curNode.data.equals(data)) {
return true;
}
}
return false;
}
//获取链表中元素的个数
public int getSize() {
return this.size;
}
//获取链表的头结点
public Optional getFirst() {
if (this.head.next == null) {
return Optional.empty();
}
return Optional.ofNullable(this.head.next.data);
}
//获取链表的尾结点
public Optional getLast() {
if (this.head.next == null) {
return Optional.empty();
}
Node<T> curNode = this.head;
while (curNode.next != null) {
curNode = curNode.next;
}
return Optional.of(curNode.data);
}
//从链表中获取任意位置的结点
public T get(int index) {
if (index < 0 || index >= this.size) {
throw new IllegalArgumentException("index is invalid");
}
Node<T> curNode = this.head.next;
int i = 0;
while (i < index) {
curNode = curNode.next;
i++;
}
return curNode.data;
}
//从链表的头部删除元素
public T removeHead() {
if (this.isEmpty()) {
return null;
}
Node<T> delNode = this.head.next;
this.head.next = delNode.next;
delNode.next = null;
//更新size;
this.size--;
return delNode.data;
}
//链表的尾部删除元素
public T removeTail() {
if (this.isEmpty()) {
return null;
}
Node<T> pre = this.head;
while (pre.next.next != null) {
pre = pre.next;
}
Node<T> delNode = pre.next;
pre.next = delNode.next;
delNode.next = null;
//更新size;
this.size--;
return delNode.data;
}
//删除任意位置的结点
public T remove(int index){
if(index<0||index>=this.size){
throw new IllegalArgumentException("index is invalid");
}
//找删除结点的前驱
Node<T>pre=this.head;
int i=0;
while(i<index){
pre=pre.next;
i++;
}
Node<T>delNode=pre.next;
pre.next=delNode.next;
delNode.next=null;
this.size--;
return delNode.data;
}
//根据值从链表中删除元素
public int removeByValue(T value){
int count=0;
//定义前驱结点
Node<T>pre=this.head;
while(pre.next!=null){
Node curNode=pre.next;
if(curNode.data.equals(value)){
pre.next=pre.next.next;
curNode.next=null;
this.size--;
count++;
}else{
pre=pre.next;
}
}
return count;
}
//不使用虚拟头结点
public int removeByValue2(T val){
int count = 0;
Node<T> realHead = this .head.next;
while(realHead!=null&&realHead.data.equals(val)){
realHead=realHead.next;
this.size--;
count++;
}
//判断链表是否为空
if(realHead==null){
return count;
}
//头结点不是删除的点
Node pre = realHead;
while(pre.next!=null){
Node<T> delNode = pre.next;
if(delNode.equals(val)){
pre.next = delNode .next;
delNode.next = null;
this.size--;
count++;
}else{
pre = pre .next;
}
}
return count;
}