双向链表

public class LinkedList implements List {
/**
* 内部类,定义结点类
*/
private class Node {
Node pre;//前一个结点
Node next;//后一个结点
Object data;//储存数据

    public Node(Node pre, Node next, Object data) {
        this.pre = pre;
        this.next = next;
        this.data = data;
    }
}

private Node first;//指向第一个元素
private Node last;//指向最后一个元素
private int size;//LinkedList的长度

/**
 * 空构造函数,所有成员均为null
 */
public LinkedList() {
}

@Override
public int size() {
    return size;
}

@Override
public Object get(int i) {
    //先判断是否越界
    checkElementIndex(i, false);
    //获取指定索引的结点
    return this.getNode(i).data;
}

/**
 * 获取指定索引的结点
 *
 * @param i
 * @return
 */
private Node getNode(int i) {
    //为了提高效率,可以先让索引值i与中间值比较,再确定是从前到后遍历还是从后到前遍历
    if (i < (this.size >> 1)) {
        //从前到后遍历
        Node p = this.first;
        for (int j = 0; j < i; j++) {
            p = p.next;
        }
        return p;
    } else {
        //从后往前遍历
        Node p = this.last;
        for (int j = this.size - 1; j > i; j--) {
            p = p.pre;
        }
        return p;
    }
}

/**
 * 判断索引是否越界
 *
 * @param i     索引
 * @param isAdd 是否是添加元素操作
 */
private void checkElementIndex(int i, boolean isAdd) {
    if (!isAdd) {
        //如果不是添加操作,不能索引到size
        if (i < 0 || i >= this.size) {
            throw new MyIndexOutOfBoundsException("无效的索引:" + i);
        }
    } else {
        //如果是添加操作,在索引size出添加相当于在末尾追加
        if (i < 0 || i > this.size) {
            throw new MyIndexOutOfBoundsException("无效的索引:" + i);
        }
    }
}

@Override
public boolean isEmpty() {
    return size > 0;
}

@Override
public boolean contains(Object e) {
    //调用indexOf()函数,如果返回值不是-1就说明在LinkedList中没有找到e
    return this.indexOf(e) != -1;
}

@Override
public int indexOf(Object e) {
    Node p = this.first;
    int index = 0;
    //先判断e是否为空
    if (e == null) {
        while (p != null) {
            if (p.data == null) {
                return index;
            }
            index++;
            p = p.next;
        }
    } else {
        while (p != null) {
            if (p.data.equals(e)) {
                return index;
            }
            index++;
            p = p.next;
        }
    }
    return -1;
}

@Override
public void add(int i, Object e) {
    //先检查索引是否越界
    checkElementIndex(i, true);

    //判断如果索引值和size相同,就调用add(Object e)方法,省去了遍历链表的操作,提高了效率
    if (i == size) {
        this.add(e);
    } else {
        Node node = getNode(1);//索引为i的结点
        Node p = node.pre;//索引为i的结点的前一个结点
        Node newNode = new Node(p, node, e);//带插入的新结点
        node.pre = newNode;//将原来索引为i的结点的前驱指向新的结点
        //判断是否是第一次插入
        if (p == null) {
            this.first = newNode;
        } else {
            p.next = newNode;
        }
        //将size加一
        size++;
    }

}

@Override
public void add(Object e) {
    //1.新建一个节点,将其前驱节点设置为last,后继节点设置为null,数据域设为e
    Node newNode = new Node(this.last, null, e);
    //2.储存旧尾指针
    Node l = this.last;
    //3.修改尾指针
    this.last = newNode;
    //4.判断l是否为空
    if (l == null) {
        //如果为空就代表是第一次添加,要将头指针指向newNode
        this.first = newNode;
    } else {
        //如果非空就代表不是第一次添加,不用只用将原来的尾指针的next指向newNode即可
        l.next = newNode;
    }
    //5.将长度加一
    this.size++;
}

@Override
public Object remove(int i) {
    //先检查索引是否越界
    checkElementIndex(i, false);

    Node p = this.first;
    //遍历找到要删除的结点
    for (int j = 0; j < i; j++) {
        p = p.next;
    }
    return unlink(p);
}

@Override
public boolean remove(Object e) {
    //先判断是否为null
    Node p = this.first;
    if (e == null) {
        while (p != null) {
            if (p.data == null) {
                //如果找到结点就调用删除结点的方法
                unlink(p);
                return true;
            }
            p = p.next;
        }
    } else {
        while (p != null) {
            if (p.data.equals(e)) {
                //如果找到结点就调用删除结点的方法
                unlink(p);
                return true;
            }
            p = p.next;
        }
    }
    return false;
}

/**
 * 删除结点p
 *
 * @param p 要删除的结点
 */
private Object unlink(Node p) {
    Node preNode = p.pre;
    Node nextNode = p.next;

    //先处理要删除结点的前一个结点
    if (preNode == null) {
        this.first = nextNode;
    } else {
        preNode.next = nextNode;
        p.pre = null;
    }

    //处理后一个结点
    if (nextNode == null) {
        this.last = preNode;
    } else {
        p.next = null;
        nextNode.pre = preNode;
    }

    this.size--;
    return p.data;
}

@Override
public Object replace(int i, Object e) {
    //先检查索引是否越界
    checkElementIndex(i, false);

    Node p = this.first;
    //遍历找到要替换的结点
    for (int j = 0; j < i; j++) {
        p = p.next;
    }
    Object temp = p.data;
    p.data = e;
    return temp;
}

@Override
public String toString() {
    StringBuffer sb = new StringBuffer();
    sb.append("[");
    Node p = this.first;
    int index = 0;
    while (p != null) {
        if (index != size - 1) {
            sb.append(p.data.toString() + ",");
        } else {
            sb.append(p.data.toString());
        }
        p = p.next;
        index++;
    }
    sb.append("]");
    return sb.toString();
}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值