双向链表
前言
单向链表:只能按照一个方向,从前到后
双向链表:既可以从前走也可以从后走
一、双向链表
package seqlist.doublelink;
/**
* 双链表类
*/
public class DoubleLinkedList {
//当前链表中有效的元素个数
private int size;
//头节点
private Node head;
//尾节点
private Node tail;
}
/**
* 双链表的节点类
*/
class Node{
Node prev;
int val;
Node next;
//构造方法
public Node(int val){
this.val=val;
}
public Node (Node prev,int val,Node next) {
this.prev=prev;
this.val=val;
this.next=next;
}
}
①.插入
1.头插法
public void addFist(int val){
Node node =new Node(null,val,head);
//链表为空
if (head==null){
tail=node;
}else {
head.prev = node;
}
head=node;
size++;
}
2.尾插法
//尾插法
public void addLast(int val){
Node node=new Node(tail,val,null);
if(tail==null){
head=node;
}else {
tail.next=node;
}
tail=node;
size++;
}
3.※找到前驱节点
/**
* 找到index索引对应的节点
* @param index
* @return index对应的节点Node
*/
private Node node(int index) {
Node ret=null;
//index<size的一半(从头找)
if (index<(size>>1)){
ret=head;
for (int i = 0; i < index; i++) {
ret=ret.next;
}
}else {
//从后向前找
ret=tail;
for (int i = size-1; i > index; i--) {
ret= tail.prev;
}
}
return ret;
}
4.输出
@Override
public String toString() {
String ret="";
Node node=head;
while (node!=null){
ret+=node.val+"->";
node=node.next;
}
ret+="NULL";
return ret;
}
5.中间插
public void addIndex(int index,int val){
if (index<0||index>size){
System.err.println("add index illegal!");
return;
}else if (index==0) addFist(val);
else if (index==size) addLast(val);
else {
//在中间位置插入要找到前驱节点
//找到节点CURD全都要用,抽象成一个方法,快捷键CTRL+enter
Node prev=node(index-1);
//连接四根线
Node newNode=new Node(prev,val,prev.next);
prev.next.prev=newNode;
prev.next=newNode;
size++;
}
}
②.查询
1.判断合法性
public boolean rangeIndex(int index){
if (index<0||index>=size){
return false;
}
return true;
}
2. get(int index)
public int get(int index) {
//合法性
if (rangeIndex(index)) {
return node(index).val;
} else {
System.err.println("get index illegal");
}
return -1;
}
3.contains(int val)
public boolean contains(int val){
for (Node x=head;x!=null;x=x.next){
if (x.val==val){
return true;
}
}
return false;
}
③.修改
1.set(int index,int newVal)
/**
* 根据index修改之前的元素
* @param index
* @param newVal
* @return 修改前的值
*/
public int set(int index,int newVal){
if (rangeIndex(index)){
Node node =node(index);
int oldVal= node.val;;
node.val=newVal;
return oldVal;
}else{
System.err.println("set index illegal!");
return -1;
}
③.删除
删除具体节点//将node节点从当前双向链表中删除
private void unlink(Node node) { } ;
1.※unlink(Node node):分治思想
/**
* 删除链表中指定的节点
* @param node
*/
private void unlink(Node node) {
//分治思想
Node prev=node.prev;
Node next=node.next;
//先处理前驱节点
if (prev==null){
//此时是个头节点
head=next;
}else {
prev.next=next;
node.prev=null;
}
//此时处理后继节点
if (next==null){
//此时要删除的是个尾节点
tail=prev;
}else{
next.prev=prev;
node.next=null;
}
size--;
}
2.removeIndex(int index)等
public void removeIndex(int index){
if (rangeIndex(index)){
Node node =node(index);
unlink(node);
}else{
System.err.println("remove index illegal!");
}
}
public void removeFirst(){
removeIndex(0);
}
public void removeLast(){
removeIndex(size-1);
}
3.removeValueOnce(int val)
public void removeValueOnce(int val){
for (Node x=head;x!=null;x=x.next){
if (x.val==val){
unlink(x);
break;
}
}
}
4.※removeValueAll(int val)
public void removeValueAll(int val){
//注意,因为上面写的删除方法指向空
//因此,删除之前需要暂存一下下一个节点的地址
for (Node x=head;x!=null;x=x.next){
if (x.val==val){
Node next =x.next;
//删除之后,x.next=x.prev=null
unlink(x);
x=next;
}else {
x=x.next;
}
}
}