定义节点结构
//定义节点结构
static class Node<E>{
Node<E> prev; //定义头部
Node<E> next; //定义尾部
E element; //存储数据
//全参构造方法
public Node(Node<E> prev,E element,Node<E> next){
this.element = element;
this.next = next;
this.prev = prev;
}
}
定义链表结构
//定义双向链表结构
Node<E> first; //定义头结点
Node<E> last; //定于尾节点
int size; //记录双向链表中不为null的节点数
//双向链表的无参构造方法
public MyLinkedList01(){}
定义查找目标位置的方法,并返回节点
//定义查找指定位置的方法,并返回目标节点
//利用的是二分查找法
public Node<E> node(int index){
if (index < (size >> 1)){ //当索引小于长度的一半的时候在左边遍历
Node<E> x = first; //把头节点取出
for (int i = 0; i < index; i++) { //左半边遍历
x = x.next; //找出目标索引的下一个节点
}
return x; //返回该节点
}else {
Node<E> x = last; //把尾节点取出
for (int i = size - 1; i > index; i--) { //右半边遍历
x = x.prev; //找出目标索引的前一个节点
}
return x; //返回该节点
}
}
定义添加头结点的方法
//头部增加节点方法
public void addFirst(E element){
Node<E> f = first; //先取出原来的头结点
Node<E> newNode = new Node<>(null, element, f); //新建一个节点作为新的头结点:头部置null,尾部指向原来的头结点
first = newNode; //把新节点定义为头结点
if (f == null) { //如果之前的头结点为null,那么说明新建的节点既是头结点也是尾节点
last = newNode;
}else { //否则,原来的头结点的头部指向新建的头结点
f.prev = newNode;
}
size++; //节点数加1
}
定义添加尾节点的方法
//尾部添加方法
public void addLast(E element){
Node<E> l = last; //先取出尾部节点
Node<E> newNode = new Node<>(l, element, null); //新建一个节点作为新的尾节点:头部为原来的尾节点,尾部为null
last = newNode; //把新建的节点作为尾节点
if (l == null){ //如果原来的尾节点为空,那么新建的节点既是头结点也是尾节点
first = newNode;
}else { //否则,原来尾节点的尾部指向新建的节点的头部
l.next = newNode;
}
size++; //节点数加1
}
定义中间插入的方法
//中间插入方法
public void add(int index, E element){
if (!(index >= 0 && index <= size)){ //先判断索引是否越界
throw new RuntimeException("索引越界异常!");
}
if (index == size) { //index永远小于size,如果index == size则说明链表为空,此时我们可以使用头结点添加方法
addFirst(element);
}else { //链表不为空
Node<E> x = node(index); //先通过索引查找找出目标节点
Node<E> f = x.prev; //把目标节点的前一个节点取出
Node<E> newNode = new Node<>(f, element, x); //新建一个节点:头部为目标节点的前一个节点,尾部为目标节点
x.prev = newNode; //目标节点的头部指向新建的节点
if (f == null) { //如果目标节点的前一个节点为空,那么新建的节点就是链表的头部节点
first = newNode;
}else { //如果目标节点的前一个节点不为空,那么目标节点的前一个节点的尾部指向新建节点的头部
f.next = newNode;
}
size++; //节点个数加1
}
}
定义删除头结点的方法
//删除头结点方法
public E removeFirst(){
Node<E> f = first; //先取出头结点
if (f == null) { //如果头结点为空,则提示链表为空
throw new RuntimeException("链表为空,无法删除!");
}
E remove = first.element; //取出要删除的数据
Node<E> l = f.next; //取出目标节点的下一个节点
f.element = null; //把要删除节点的数据清空
f.next = null;
first = l; //要删除节点的下一个节点为新的头结点
if (l == null){ //如果要删除的下一个节点为空,则表示删除完之后的链表为空
last = null;
}else { //否则把新成为头部节点的头部置空
l.prev = null;
}
size--; //节点个数减1
return remove; //返回被删除节点的数据
}
定义删除尾节点的方法
//删除尾节点方法
public E removeLast(){
Node<E> l = last; //先取出尾节点
if (l == null) { //如果尾节点为空的话,说明链表为空
throw new RuntimeException("链表为空,无法删除!");
}
E remove = l.element; //先取出要删除节点的数据
Node<E> f = l.prev; //取出要删除节点的前一个节点
l.prev = null; //把要删除的节点的数据清空
l.element = null;
last = f; //把要删除的节点的前一个节点作为尾节点
if (f == null) { //如果要删除节点的前一个节点为空的话,那么删除节点之后链表就为空了
first = null;
}else { //不为空的话,就把要删除节点的尾部置空
f.next = null;
}
size--; //节点个数减1
return remove; //返回被删除的数据
}
定义中间删除的方法
//中间删除方法
public E remove(int index){
//先判断索引是否越界
if (!(index >= 0 && index <= size)){
throw new RuntimeException("索引越界异常!");
}
Node<E> x = node(index); //找出要删除的节点位置
E remove = x.element; //把要删除节点的数据取出
Node<E> f = x.prev; //把要删除节点的前一个节点取出
Node<E> l = x.next; //把要删除节点的后一个节点取出
if (f == null){ //如果要删除节点的前一个节点为空,那么要删除节点的后一个节点就是头结点
first = l;
}else { //不为空的话,把要删除节点的前一个节点的尾部指向要删除节点的后一个节点的头部
f.next = l;
x.prev = null; //并把要删除节点的头部置空
}
if (l == null) { //如果要删除节点的后一个节点为空,那么要删除节点的前一个节点就是尾节点
last = f;
}else { //不为空的话,就把要删除节点的后一个节点的头部指向要删除节点的前一个节点的尾部
l.prev = f;
x.next = null; //并把要删除节点额尾部置空
}
x.element = null; //把要删除节点的数据清空
size--; //节点数减1
return remove; //返回被删除的数据
}
定义修改节点数据的方法
//修改节点数据方法
public E set(int index,E element){
//先判断索引是否越界
if (!(index >= 0 && index <= size)){
throw new RuntimeException("索引越界异常!");
}
Node<E> x = node(index); //找出目标节点
E old = x.element; //取出目标节点的数据并赋给一个变量
x.element = element; //把新数据插进去
return old; //返回被修改的数据
}
定义取值器方法
//取值器
public E get(int index){
//先判断索引是否越界
if (!(index >= 0 && index <= size)){
throw new RuntimeException("索引越界异常!");
}
//返回目标节点的数据
return node(index).element;
}
定义获取节点数量方法
//定义获取节点数量方法
public int getSize(){
return size;
}
原码
public class MyLinkedList01<E> {
//定义双向链表结构
Node<E> first; //定义头结点
Node<E> last; //定于尾节点
int size; //记录双向链表中不为null的节点数
//双向链表的无参构造方法
public MyLinkedList01(){}
//定义节点结构
static class Node<E>{
Node<E> prev; //定义头部
Node<E> next; //定义尾部
E element; //存储数据
//全参构造方法
public Node(Node<E> prev,E element,Node<E> next){
this.element = element;
this.next = next;
this.prev = prev;
}
}
//定义查找指定位置的方法,并返回目标节点
//利用的是二分查找法
public Node<E> node(int index){
if (index < (size >> 1)){ //当索引小于长度的一半的时候在左边遍历
Node<E> x = first; //把头节点取出
for (int i = 0; i < index; i++) { //左半边遍历
x = x.next; //找出目标索引的下一个节点
}
return x; //返回该节点
}else {
Node<E> x = last; //把尾节点取出
for (int i = size - 1; i > index; i--) { //右半边遍历
x = x.prev; //找出目标索引的前一个节点
}
return x; //返回该节点
}
}
//头部增加节点方法
public void addFirst(E element){
Node<E> f = first; //先取出原来的头结点
Node<E> newNode = new Node<>(null, element, f); //新建一个节点作为新的头结点:头部置null,尾部指向原来的头结点
first = newNode; //把新节点定义为头结点
if (f == null) { //如果之前的头结点为null,那么说明新建的节点既是头结点也是尾节点
last = newNode;
}else { //否则,原来的头结点的头部指向新建的头结点
f.prev = newNode;
}
size++; //节点数加1
}
//尾部添加方法
public void addLast(E element){
Node<E> l = last; //先取出尾部节点
Node<E> newNode = new Node<>(l, element, null); //新建一个节点作为新的尾节点:头部为原来的尾节点,尾部为null
last = newNode; //把新建的节点作为尾节点
if (l == null){ //如果原来的尾节点为空,那么新建的节点既是头结点也是尾节点
first = newNode;
}else { //否则,原来尾节点的尾部指向新建的节点的头部
l.next = newNode;
}
size++; //节点数加1
}
//中间插入方法
public void add(int index, E element){
if (!(index >= 0 && index <= size)){ //先判断索引是否越界
throw new RuntimeException("索引越界异常!");
}
if (index == size) { //index永远小于size,如果index == size则说明链表为空,此时我们可以使用头结点添加方法
addFirst(element);
}else { //链表不为空
Node<E> x = node(index); //先通过索引查找找出目标节点
Node<E> f = x.prev; //把目标节点的前一个节点取出
Node<E> newNode = new Node<>(f, element, x); //新建一个节点:头部为目标节点的前一个节点,尾部为目标节点
x.prev = newNode; //目标节点的头部指向新建的节点
if (f == null) { //如果目标节点的前一个节点为空,那么新建的节点就是链表的头部节点
first = newNode;
}else { //如果目标节点的前一个节点不为空,那么目标节点的前一个节点的尾部指向新建节点的头部
f.next = newNode;
}
size++; //节点个数加1
}
}
//取值器
public E get(int index){
//先判断索引是否越界
if (!(index >= 0 && index <= size)){
throw new RuntimeException("索引越界异常!");
}
//返回目标节点的数据
return node(index).element;
}
//修改节点数据方法
public E set(int index,E element){
//先判断索引是否越界
if (!(index >= 0 && index <= size)){
throw new RuntimeException("索引越界异常!");
}
Node<E> x = node(index); //找出目标节点
E old = x.element; //取出目标节点的数据并赋给一个变量
x.element = element; //把新数据插进去
return old; //返回被修改的数据
}
//删除头结点方法
public E removeFirst(){
Node<E> f = first; //先取出头结点
if (f == null) { //如果头结点为空,则提示链表为空
throw new RuntimeException("链表为空,无法删除!");
}
E remove = first.element; //取出要删除的数据
Node<E> l = f.next; //取出目标节点的下一个节点
f.element = null; //把要删除节点的数据清空
f.next = null;
first = l; //要删除节点的下一个节点为新的头结点
if (l == null){ //如果要删除的下一个节点为空,则表示删除完之后的链表为空
last = null;
}else { //否则把新成为头部节点的头部置空
l.prev = null;
}
size--; //节点个数减1
return remove; //返回被删除节点的数据
}
//删除尾节点方法
public E removeLast(){
Node<E> l = last; //先取出尾节点
if (l == null) { //如果尾节点为空的话,说明链表为空
throw new RuntimeException("链表为空,无法删除!");
}
E remove = l.element; //先取出要删除节点的数据
Node<E> f = l.prev; //取出要删除节点的前一个节点
l.prev = null; //把要删除的节点的数据清空
l.element = null;
last = f; //把要删除的节点的前一个节点作为尾节点
if (f == null) { //如果要删除节点的前一个节点为空的话,那么删除节点之后链表就为空了
first = null;
}else { //不为空的话,就把要删除节点的尾部置空
f.next = null;
}
size--; //节点个数减1
return remove; //返回被删除的数据
}
//中间删除方法
public E remove(int index){
//先判断索引是否越界
if (!(index >= 0 && index <= size)){
throw new RuntimeException("索引越界异常!");
}
Node<E> x = node(index); //找出要删除的节点位置
E remove = x.element; //把要删除节点的数据取出
Node<E> f = x.prev; //把要删除节点的前一个节点取出
Node<E> l = x.next; //把要删除节点的后一个节点取出
if (f == null){ //如果要删除节点的前一个节点为空,那么要删除节点的后一个节点就是头结点
first = l;
}else { //不为空的话,把要删除节点的前一个节点的尾部指向要删除节点的后一个节点的头部
f.next = l;
x.prev = null; //并把要删除节点的头部置空
}
if (l == null) { //如果要删除节点的后一个节点为空,那么要删除节点的前一个节点就是尾节点
last = f;
}else { //不为空的话,就把要删除节点的后一个节点的头部指向要删除节点的前一个节点的尾部
l.prev = f;
x.next = null; //并把要删除节点额尾部置空
}
x.element = null; //把要删除节点的数据清空
size--; //节点数减1
return remove; //返回被删除的数据
}
//定义获取节点数量方法
public int getSize(){
return size;
}
}