/*
通过双向链表来实现线性表,增删改查功能(重点掌握:java的唯一值传递本质)
*/
//测试
public class MyListTest {
public static void main(String[] args) {
MyDBLinked myDBLinked = new MyDBLinked();
myDBLinked.add("a");
myDBLinked.add("b");
myDBLinked.add("c");
myDBLinked.add("d");
// myDBLinked.remove("d");
// System.out.println(myDBLinked.get(0));
// System.out.println(myDBLinked.set(3,"zs"));
// System.out.println(myDBLinked.contains("e"));
// System.out.println(myDBLinked.insert(4, "zs"));
myDBLinked.remove(3);
System.out.println(myDBLinked);
}
}
//双向链表类
class MyDBLinked {
private Node head;
private Node end;
private int size;
/**
* 尾结点添加元素的方法
* @param s:传入的节点数据
* @return 返回添加元素是否成功
*/
public boolean add(String s) {
if (s == null) throw new IllegalArgumentException("param is Illegal");
//如果链表为空,让头尾都等于新节点
if (head == null || size == 0) {
head = new Node(null, s, head);
end = head;
size++;
return true;
}
//如果不为空,直接在尾节点添加元素
Node node = new Node(null, s, null);
node.pre = end;
end.next = node;
end = node;
size++;
return true;
}
/**
*根据提供的内容删除指定元素
* @param s:查找的value
* @return 是否删除成功
*/
public boolean remove(String s){
//如果查找的值是空或者链表是空,直接抛出异常
if(s==null) throw new IllegalArgumentException("param is null");
if(head==null||size==0)throw new RuntimeException("Linked is null");
//如果需要删除的元素为头结点
if(head.value.equals(s)){
head = head.next;
//如果链表只有一个元素,删除唯一的头结点
if(head == null){
end = null;
}else {//链表不止一个元素
head.pre = null;
}
size--;
return true;
}
//要删除的节点不是头节点
Node mid = head;
while (mid.next!=null&&!mid.next.value.equals(s)){
mid = mid.next;
}
//如果找到最后一个节点还没有找到目标值元素,代表值不存在
if(mid.next==null) return false;
//mid 为要删除的节点的前一个节点
Node removeNode = mid.next;
//如果要删除的是尾结点
if(removeNode.next==null){
mid.next = null;
}else {
removeNode.pre.next = mid.next.next;
removeNode.next.pre = mid;
}
size--;
return true;
}
/**
* 判断链表元素是否包含某一个值
* @param s:要判断的value
* @return true存在
*/
public boolean contains(String s){
//如果查找的值是空或者链表是空,直接抛出异常
if(s==null) throw new IllegalArgumentException("param is null");
if(head==null||size==0)throw new RuntimeException("Linked is null");
if(head.value.equals(s)) return true;
Node mid = head;
while (mid.next!=null&&!mid.next.value.equals(s)){
mid = mid.next;
}
//如果判断到了mid.next == null退出循环,代表查找数据不存在
if(mid.next==null) return false;
//到此处代表查找数据存在
return true;
}
/**
* 按指定下标位置插入元素
* @param index:插入元素的下标位置 [0,size]
* @param s:插入元素的value
* @return 是否插入成功
*/
public boolean insert(int index,String s){
//如果查找的值是空或者链表是空,直接抛出异常
if(s==null||index<0||index>size) throw new IllegalArgumentException("param is null");
//如果插入点为头结点
if(index==0){
//如果链表为空
if(size==0){
head = new Node(null,s,null);
end = head;
}else {//链表不为空,size为1时head前移,end不变不用考虑
Node node = new Node(null, s, head);
head.pre = node;
head = node;
}
size++;
return true;
}
//插入的点不是头结点
//如果从尾部插入元素
if(index==size){
//调用前面的方法
return add(s);
}
Node mid;
//如果下标靠近头节点,从前往后遍历
if(index<size/2){
int tag = 1;//如果从0开始就会找到要插入间隙的后一个节点
mid = head;
//当找到要插入间隙的前节点mid时退出循环
while (index!=tag){
mid = mid.next;
tag++;
}
}else {//如果下标靠近尾节点,从后往前遍历
int tag = size;//如果从size-1开始就会找到要插入间隙的后一个节点
mid = end;
while (index!=tag){
mid = mid.next;
tag--;
}
}
//mid始终是要插入间隙的前一个节点元素
Node node = new Node(mid, s, mid.next);
mid.next = node;
mid.next.pre = node;
size++;
return true;
}
/**
* 按照指定下标删除节点
* @param index:删除节点的下标 [0,size)
* @return 被删除节点的value
*/
public String remove(int index){
if(head==null||size==0) throw new RuntimeException("Linked is null");
if(index<0||index>=size) throw new IllegalArgumentException("param is illegal : index="+index);
//如果删除的是头结点
if(index == 0){
//暂存头结点值
String oldValue = head.value;
//链表只有一个元素
if(head.next==null||size == 1) {
head = null;
end = null;
}else {//链表由两个或两个以上的元素
head = head.next;
head.pre = null;
}
return oldValue;
}
//要删除的不是头结点
//如果要删除的节点是尾结点
if(index==(size-1)){
String oldValue = end.value;
end.pre.next = null;
end = end.pre;
return oldValue;
}
Node mid = head;//mid就是要删除的节点
if(index<size/2){//如果下标离头结点近,向后遍历
int tag = 0;
mid = head;
while (index!= tag){
mid = mid.next;
tag++;
}
}else {//如果下标离尾结点近,向前遍历
int tag = size-1;
mid = end;
while (index!=tag){
mid = mid.pre;
tag--;
}
}
String oldValue = mid.value;
mid.pre.next = mid.next;
mid.next.pre = mid.pre;
return oldValue;
}
/**
* 根据下标查找对应节点的值
* @param index:要查询的元素下标
* @return 返回节点的value值
*/
public String get(int index) {
//如果链表为空
if (head == null || size == 0) throw new RuntimeException("Linked is null");
//如果下标小于0或者超过size-1
if (index < 0 || index >= size) throw new IllegalArgumentException("param is illegal:index=" + index);
Node mid;
//如果查询下标靠近头结点,从头结点向后遍历
if (index < size / 2) {
mid = head;
int tag = 0;
while (index != tag) {
mid = mid.next;
tag++;
}
}else {//如果查询下标靠近尾结点,从尾结点开始向前遍历
mid = end;
int tag = size-1;
while (index!=tag){
mid = mid.pre;
tag--;
}
}
return mid.value;
}
/**
* 根据下标和新的元素value替换原来的value
* @param index:需要修改的元素的下标
* @param newValue:需要替换的原来元素value值的新值
* @return 返回被修改的value值
*/
public String set(int index, String newValue) {
//如果链表为空
if (head == null || size == 0) throw new RuntimeException("Linked is null");
//如果下标小于0或者超过size-1
if (index < 0 || index >= size) throw new IllegalArgumentException("param is illegal:index=" + index);
Node mid;
//如果查询下标靠近头结点,从头结点向后遍历
if (index < size / 2) {
mid = head;
int tag = 0;
while (index != tag) {
mid = mid.next;
tag++;
}
}else {//如果查询下标靠近尾结点,从尾结点开始向前遍历
mid = end;
int tag = size-1;
while (index!=tag){
mid = mid.pre;
tag--;
}
}
//保存旧值并更新,返回旧值
String oldValue = mid.value;
mid.value = newValue;
return oldValue;
}
/**
* 求链表长度的方法
* @return
*/
public int size(){
return size;
}
/**
* 判断链表是否为空的方法
* @return ture就是链表为空
*/
public boolean isEmpty(){
return size==0;
}
//节点类
class Node {
Node pre;
String value;
Node next;
//节点构造器
private Node(Node pre, String value, Node next) {
this.pre = pre;
this.value = value;
this.next = next;
}
@Override
public String toString() {
//节点toString方法不能包含pre,不然会循环调用导致栈溢出
return "Node{" +
"v='" + value +
", next=" + next +
'}';
}
}
@Override
public String toString() {
return "{" +
"head=" + head +
'}';
}
}
04-28
1357
![](https://csdnimg.cn/release/blogv2/dist/pc/img/readCountWhite.png)