LinkedList本质上是链表,此次只是实现了LinkedList里面几个基础简单的方法,为了便于理解LinkedList
节点类
节点类里面包括指向上一个节点的指针,指向下一个节点的指针,和保存数据的Object类,以及两个构造方法。
/**
* 节点类
* TODO
* @version 1.0
* @author 王星宇
*/
class Node{
Node previous; //上一个节点
Node next; //下一个节点
Object element; //数据
public Node(Node previouse,Node next,Object element) {
this.previous = previouse;
this.next = next;
this.element = element;
}
public Node(Object element) {
this.element = element;
}
}
需要的变量
- 头指针first
- 尾指针last
- 容器大小size;
private Node first;
private Node last;
private int size;
checkIndex()
检查索引是否合法,如果不合法,则抛出异常
/**
* 检查索引是否合法
* @param index
*/
public void checkIndex(int index) {
if(index < 0||index >= size)
throw new RuntimeException("索引不合法:" + index);
}
get()和getNode()
- getNode(int index):获得索引处的节点,当索引小于长度的一半时,从前面开始查找,当索引大于长度的一半时,从后面开始查找。
- get(int index):获得索引处节点的数据,检查索引是否合法,调用getNode()获得索引处的节点,返回节点的数据。
/**
* get方法
* 如果是前半部分,从前面开始找
* 如果是后半部分,从后面开始找
* @param index
* @return
*/
public E get(int index) {
checkIndex(index);
Node temp = getNode(index);
return (E)temp.element;
}
/**
* 获得索引处的对象
* @param index
* @return
*/
public Node getNode(int index) {
Node temp = null;
if(index <= (size >> 1)) {
temp = first;
for(int i = 0;i < index;i++)
temp = temp.next;
}else {
temp = last;
for(int i = size - 1;i > index;i--)
temp = temp.previous;
}
return temp;
}
add()方法
- add(E element):在容器最后添加一个对象,如果容器内没有对象,直接将头指针,尾指针都指向新建的节点,size++。
- add(E element,int index):在指定索引处添加一个对象(如果容器内没有对象则抛出异常),调用getNode()获得索引处的节点,让down指向它,让up等于索引出前一个节点,之后让新节点的previous,next分别指向up和down,up.next,down.previous都指向新节点,最后size++;
/**
* 在链表最后里面添加一个对象
* @param obj 对象
*/
public void add(E element) {
Node node = new Node(element);
if(first == null) {
first = node;
last = node;
}else {
node.previous = last;
node.next = null;
last.next = node;
last = node;
}
size++;
}
/**
* 在索引位置出添加节点
* @param obj 对象
* @param index 索引
*/
public void add(E element,int index) {
checkIndex(index);
Node newNode = new Node(element);
Node down = getNode(index);
Node up = down.previous;
down.previous = newNode;
newNode.next = down;
if(up != null)
up.next = newNode;
else
first = newNode;
size++;
}
toString()
为了打印容器时能直接打印容器内的数据,重写toString()方法(System.out.println(myLinkedList); 实际上是调用的toString()方法)。
/**
* 返回链表中的数据
*/
@Override
public String toString() {
StringBuffer ms = new StringBuffer("");
Node temp = first;
ms.append("[");
for(int i = 0;i < size;i++) {
ms.append((temp.element).toString() + ",");
temp = temp.next;
}
ms.setCharAt(ms.length() - 1, ']');
return ms.toString();
}
remove()
从容器中移除索引位置处的节点(对象本身并未删除)。首先检查索引是否合法,然后调用getNode()获得索引处的节点,up指向上一个节点,down指向下一个节点。
- 如果up为null,则这个节点是头节点,移除的话直接将头指针指向dwon,down的previous等于null
- 如果down为null,则这个节点是尾节点,移除的话直接将尾指针指向up,up的next等于null
- 其他情况,up的下一个指向down,down的上一个指向up
- size减一
/**
* 移除索引位置处的节点
* @param index
*/
public void remove(int index) {
checkIndex(index);
Node temp = getNode(index);
if(temp != null) {
Node up = temp.previous;
Node down = temp.next;
if(up == null) {
first = down;
down.previous = null;
}else if(down == null) {
last = up;
up.next = null;
}else {
up.next = down;
down.previous = up;
}
size--;
}
}
全部代码
package myCollection;
/**
* 手写linkedList
* TODO
* @version 1.0
* @author 王星宇
*/
public class myLinkedList <E>{
private Node first;
private Node last;
private int size;
/**
* 在链表最后里面添加一个对象
* @param obj 对象
*/
public void add(E element) {
Node node = new Node(element);
if(first == null) {
first = node;
last = node;
}else {
node.previous = last;
node.next = null;
last.next = node;
last = node;
}
size++;
}
/**
* 返回链表中的数据
*/
@Override
public String toString() {
StringBuffer ms = new StringBuffer("");
Node temp = first;
ms.append("[");
for(int i = 0;i < size;i++) {
ms.append((temp.element).toString() + ",");
temp = temp.next;
}
ms.setCharAt(ms.length() - 1, ']');
return ms.toString();
}
/**
* get方法
* 如果是前半部分,从前面开始找
* 如果是后半部分,从后面开始找
* @param index
* @return
*/
public E get(int index) {
checkIndex(index);
Node temp = getNode(index);
return (E)temp.element;
}
/**
* 获得索引处的对象
* @param index
* @return
*/
public Node getNode(int index) {
Node temp = null;
if(index <= (size >> 1)) {
temp = first;
for(int i = 0;i < index;i++)
temp = temp.next;
}else {
temp = last;
for(int i = size - 1;i > index;i--)
temp = temp.previous;
}
return temp;
}
/**
* 检查索引是否合法
* @param index
*/
public void checkIndex(int index) {
if(index < 0||index >= size)
throw new RuntimeException("索引不合法:" + index);
}
/**
* 移除索引位置处的节点
* @param index
*/
public void remove(int index) {
checkIndex(index);
Node temp = getNode(index);
if(temp != null) {
Node up = temp.previous;
Node down = temp.next;
if(up == null) {
first = down;
down.previous = null;
}else if(down == null) {
last = up;
up.next = null;
}else {
up.next = down;
down.previous = up;
}
size--;
}
}
/**
* 在索引位置出添加节点
* @param obj 对象
* @param index 索引
*/
public void add(E element,int index) {
checkIndex(index);
Node newNode = new Node(element);
Node down = getNode(index);
Node up = down.previous;
down.previous = newNode;
newNode.next = down;
if(up != null)
up.next = newNode;
else
first = newNode;
size++;
}
}
/**
* 节点类
* TODO
* @version 1.0
* @author 王星宇
*/
class Node{
Node previous; //上一个节点
Node next; //下一个节点
Object element; //数据
public Node(Node previouse,Node next,Object element) {
this.previous = previouse;
this.next = next;
this.element = element;
}
public Node(Object element) {
this.element = element;
}
}