前置知识:
为了解决单链表只能单方向进行,既要存储下一个节点地址,还要存储前一个节点地址。
1.头插
public void addFirst(int val){
//引入一个局部变量,暂存头节点的地址
DoubleNode f = first;
DoubleNode node = new DoubleNode(val);
//判断链表是否为空
first = node;
if (f == null){
last = node;
}else{
node.next = f;
f.prev = node;
}
size ++;
}
public void addLast(int val){
DoubleNode l = last;
DoubleNode node = new DoubleNode(val);
//判断链表是否为空
last = node;
if (l == null){
first = node;
}else{
l.next = node;
node.prev = l;
}
}
/**
* 根据index与size的大小关系快定位指定index位置的节点(addIndex、get、set方法都需要用)
* @param index
* @return
*/
private DoubleNode node(int index) {
//根据index与size的大小关系来判断到底
// 从头向后走还是从后向头走
if (index < size / 2){
//此时从头向后走
DoubleNode node = first;
for (int i = 0; i < index; i++) {
node = node.next;
}
return node;
}else{
//此时index > size/2
//此时从后向头走
DoubleNode node = last;
for (int i = size - 1 ; i > index; i--) {
node = node.prev;
}
return node;
}
}
/**
* 在index位置插入元素
* @param index
* @param val
*/
public void addIndex(int index,int val){
//判断index的合法性
if(index < 0 || index > size){
System.err.println("add index illegal!");
}
else if(index == 0){
//头插
addFirst(val);
}
else if(index == size){
//尾插
addLast(val);
}else{
//此时 0
DoubleNode node = node(index);
//指向当前位置的前驱节点
DoubleNode prev = node.prev;
DoubleNode newNode = new DoubleNode(val);
//先处理后半部分
newNode.next = node;
node.prev = newNode;
//在处理前半部分
prev.next = newNode;
newNode.prev = prev;
size ++;
}
}
4.get与set方法
//判断Index是否合法
private boolean rangeCheck(int index){
if (index < 0 || index >= size){
return false;
}
return true;
}
/**
* 根据index索引取得节点值
* @param index
* @return
*/
public int get(int index){
if (rangeCheck(index)){
DoubleNode node = node(index);
return node.val;
}else{
System.err.println("get index illegal!");
return -1;
}
}
/**
* 修改index位置的值
* @param index
* @param newVal
*/
public void set(int index,int newVal){
if (rangeCheck(index)){
DoubleNode node = node(index);
node.val = newVal;
}else{
System.err.println("set index illegal!");
}
}
5.传入一个双向链表节点,将该结点从双向链表中删除
(1)删除前半部分
(2)删除后半部分
/**
* 传入一个双向链表节点,将该结点从双向链表中删除
* (分治思想,先处理前驱或后继,再处理另一半的情况)
* @param node
*/
private void UnlinkedNode(DoubleNode node){
//待删除结点前驱
DoubleNode prev = node.prev;
//待删除结点后继
DoubleNode next = node.next;
//判断边界
if (prev == null){
first = next;
}else{
//此时前驱节点不为空
prev.next = next;
node.prev = null;
}
if (next == null){
last = prev;
}else{
//此时后继节点不为空
next.prev = prev;
node.next = null;
}
size --;
}
6.删除第一次出现的节点值
public void removeValueOnce(int val){
for (DoubleNode x = first;x != null;x = x.next) {
if(x.val == val){
UnlinkedNode(x);
return;
}
}
}
7.删除所有的节点值
public void removeAllValue(int val){
for(DoubleNode x = first;x != null;){
if(x.val == val){
DoubleNode next = x.next;
UnlinkedNode(x);
x = next;
}else{
x = x.next;
}
}
}
最终代码实现如下:
package seqlist;
class DoubleNode{
//指向前驱节点
DoubleNode prev;
//存储具体元素
int val;
//指向后继节点
static DoubleNode next;
public DoubleNode(int val) {
this.val = val;
}
}
/**
* 基于int的双向链表
*/
public class DoubleLinkedList {
//具体车厢的个数
private int size;
//头节点
private DoubleNode first;
//尾节点
private DoubleNode last;
/**
* 头插
* @param val
*/
public void addFirst(int val){
//引入一个局部变量,暂存头节点的地址
DoubleNode f = first;
DoubleNode node = new DoubleNode(val);
//判断链表是否为空
first = node;
if (f == null){
last = node;
}else{
node.next = f;
f.prev = node;
}
size ++;
}
/**
* 尾节点插入
* @param val
*/
public void addLast(int val){
DoubleNode l = last;
DoubleNode node = new DoubleNode(val);
//判断链表是否为空
last = node;
if (l == null){
first = node;
}else{
l.next = node;
node.prev = l;
}
}
/**
* 在index位置插入元素
* @param index
* @param val
*/
public void addIndex(int index,int val){
//判断index的合法性
if(index < 0 || index > size){
System.err.println("add index illegal!");
}
else if(index == 0){
//头插
addFirst(val);
}
else if(index == size){
//尾插
addLast(val);
}else{
//此时 0
DoubleNode node = node(index);
//指向当前位置的前驱节点
DoubleNode prev = node.prev;
DoubleNode newNode = new DoubleNode(val);
//先处理后半部分
newNode.next = node;
node.prev = newNode;
//在处理前半部分
prev.next = newNode;
newNode.prev = prev;
size ++;
}
}
/**
* 根据index索引取得节点值
* @param index
* @return
*/
public int get(int index){
if (rangeCheck(index)){
DoubleNode node = node(index);
return node.val;
}else{
System.err.println("get index illegal!");
return -1;
}
}
/**
* 修改index位置的值
* @param index
* @param newVal
*/
public void set(int index,int newVal){
if (rangeCheck(index)){
DoubleNode node = node(index);
node.val = newVal;
}else{
System.err.println("set index illegal!");
}
}
public void removeValueOnce(int val){
for (DoubleNode x = first;x != null;x = x.next) {
if(x.val == val){
UnlinkedNode(x);
return;
}
}
}
public void removeAllValue(int val){
for(DoubleNode x = first;x != null;){
if(x.val == val){
DoubleNode next = x.next;
UnlinkedNode(x);
x = next;
}else{
x = x.next;
}
}
}
/**
* 传入一个双向链表节点,将该结点从双向链表中删除
* (分治思想,先处理前驱或后继,再处理另一半的情况)
* @param node
*/
private void UnlinkedNode(DoubleNode node){
//待删除结点前驱
DoubleNode prev = node.prev;
//待删除结点后继
DoubleNode next = node.next;
//判断边界
if (prev == null){
first = next;
}else{
//此时前驱节点不为空
prev.next = next;
node.prev = null;
}
if (next == null){
last = prev;
}else{
//此时后继节点不为空
next.prev = prev;
node.next = null;
}
size --;
}
private boolean rangeCheck(int index){
if (index < 0 || index >= size){
return false;
}
return true;
}
/**
* 根据index与size的大小关系快定位指定index位置的节点(addIndex、get、set方法都需要用)
* @param index
* @return
*/
private DoubleNode node(int index) {
//根据index与size的大小关系来判断到底
// 从头向后走还是从后向头走
if (index < size / 2){
//此时从头向后走
DoubleNode node = first;
for (int i = 0; i < index; i++) {
node = node.next;
}
return node;
}else{
//此时index > size/2
//此时从后向头走
DoubleNode node = last;
for (int i = size - 1 ; i > index; i--) {
node = node.prev;
}
return node;
}
}
@Override
public String toString() {
String ret = "";
DoubleNode node = first;
while (node != null){
ret += node.val + "->";
node = node.next;
}
ret += "NULL";
return ret;
}
public static void main(String[] args) {
DoubleLinkedList doubleLinkedList = new DoubleLinkedList();
doubleLinkedList.addLast(1);
doubleLinkedList.addLast(2);
doubleLinkedList.addLast(3);
System.out.println(doubleLinkedList);
//System.out.println(doubleLinkedList.get(1));
doubleLinkedList.set(1,22);
System.out.println(doubleLinkedList);
}
}