链表参考文章
代码参考文章
一些基本概念:
(1) 线性表分为两种,一种是顺序存储结构的顺序表,另一种是通过指针来描述其逻辑位置的链表。
(2)**节点(Node)**是由一个需要储存的对象及对下一个节点的引用组成的。也就是说,节点拥有两个成员:储存的对象、对下一个节点的引用.
(3)单向链表是一种线性表,实际上是由节点(Node)组成的,其数据在内存中存储是不连续的,它存储的数据分散在内存中,每个结点只能也只有它能知道下一个结点的存储位置。由N各节点(Node)组成单向链表,每一个Node记录本Node的数据及下一个Node。向外暴露的只有一个头节点(Head),我们对链表的所有操作,都是直接或者间接地通过其头节点来进行的。
(4) 双向链表
(4)每个链表都包括一个LinikedList对象和许多Node对象,LinkedList对象通常包含头和尾节点的引用,分别指向链表的第一个节点和最后一个节点。而每个节点对象通常包含数据部分data,以及对上一个节点的引用prev和下一个节点的引用next,只有下一个节点的引用称为单向链表,两个都有的称为双向链表。next值为null则说明是链表的结尾,如果想找到某个节点,我们必须从第一个节点开始遍历,不断通过next找到下一个节点,直到找到所需要的.
LinkedList底层实现
package testList;
/**
* 实现双向LinkedList的方法如下: add方法,get方法, indexOf方法, remove方法
* @author Administrator
*/
public class SimpleLinkedList<E> {
//构造方法
// public SimpleLinkedList() {//为什么没有构造方法
// }
private int size;
private Node<E> first;//双向链表中 的头结点尾节点
private Node<E> last;
//add
public boolean add(E e) {//不指定位置添加元素,则默认添加到了链表的最后
addAtLast(e);
return true;
}
//addAtLast
public void addAtLast(E element) {
Node<E> l=last;
Node<E> node=new Node<E>(element,l,null);//public Node(E item,Node<E> prev,Node<E> next)
last=node;
if(l==null) {
first=node;
}else {
l.next=node;
}
size++;
}
//add(int index ,E e),
public void add(int index ,E e) {
//检查index是否越界
checkRange(index);
if(index==size) {
addAtLast(e);
}else {//如果不是,则得到index所对应的Node元素,执行addBeforeNode。
Node<E> node=getNode(index);
addBeforeNode(e, node);
}
}
//检查越界
public void checkRange(int index) {
if(index<0||index>size) {
throw new IndexOutOfBoundsException("指定的index超过界限");
}
}
//得到index所对应的node元素,采用二分查找,节省查找时间
public Node<E> getNode(int index) {
if(index<(size<<1)) {//首先判断index如果是前一半范围,则游标Node初始为first,用游标Node元素的next,不断指向index所在的元素
Node<E> cursor=first;
for(int i=0;i<index;i++) {
cursor=cursor.next;
}
return cursor;
}else{//如果是后一半的范围内,如果是后一半,则游标Node初始为last,用游标Node元素的prev,不断指向index所在的元素。
Node<E> cursor=last;
for(int i=size-1;i>index;i--) {//链表的头尾节点是暴露在外面的,应用到了双向链表的特点,相当于已知,其他节点未知
cursor=cursor.prev;
}
return cursor;
}
}
//addBeforeNode,
public void addBeforeNode(E element, Node<E> specifiedNode) {
Node<E> prevNode=specifiedNode.prev;//新节点的prev是原index元素的prev,新节点的next是原index元素。
Node<E> newNode=new Node<E>(element,prevNode,specifiedNode);
if(prevNode==null) {//要判断preNode是不是空,是的话,表示newNode为第一个元素,就是first
first=newNode;
}else {
prevNode.next=newNode;
}
specifiedNode.prev=newNode;
size++;
}
//get 得到链表节点元素
public E getElement(int index) {
checkRange(index);
Node<E> node=getNode(index);
return node.item;
}
//indexOf(Object o)用来得到指定元素的下标
public int indexOf(E o) {//与ArrayList一样,从第一位开始查找,首先先判断element是不是null,分成两种情况。
//从第一位开始查找,自己写的不知道ok否
// Node<E> cursor=first;
if(o!=null) {
for(int i=0;i<size;i++) {
Node<E> node=getNode(i);
if(node.item.equals(o)) {
return i;
}
}
}else {
for(int i=0;i<size;i++) {
Node<E> node=getNode(i);
if(node.item==null) {
return i;
}
}
}
return -1;
}
/** public int indexOf(Object element) {//参考博文中的indexOf
Node<E> cursor = first;
int count = 0;
while (cursor != null) {
if (element != null) {
if (element.equals(cursor.item)) {
return count;
}
}else{
if (cursor.item == null) {
return count;
}
}
count ++;
cursor = cursor.next;
}
return -1;
}
*/
//remove(int index)方法
public E remove(int index) {//自己写的不知道ok否
checkRange(index);
if(index==size) {
E lelement=last.item;
last.prev.next=null;
size--;
return lelement;
}else if(index==0){
E felement=first.item;
first.next.prev=null;
size--;
return felement;
}else {
Node<E> nowNode=getNode(index);
nowNode.next.prev=nowNode.prev;
nowNode.prev.next=nowNode.next;
E nelement=nowNode.item;
nowNode.next=null;
nowNode.prev=null;
size--;
return nelement;
}
}
/**参考博客的remove(index)
* 先获得index对应的Node元素,得到该Node元素的前一个元素和后一个元素。
* 接下来,只需要将前一个元素和后一个元素直接相连即可,
* 其他只需要额外判断前一个元素和后一个元素是否为null就行。
public E remove(int index) {
checkRange(index);
return deleteLink(index);
}
private E deleteLink(int index) {
Node<E> l = node(index);
E item = l.item;
Node<E> prevNode = l.prev;
Node<E> nextNode = l.next;
if (prevNode == null) {
first = nextNode;
}else{
prevNode.next = nextNode;
l.next = null;
}
if (nextNode == null) {
last = prevNode;
}else{
nextNode.prev = prevNode;
l.prev = null;
}
size--;
l.item = null;
return item;
}
*/
//remove(Object o)
public boolean remove(E o) {
int index=indexOf(o);
if(index<0) {
return false;
}
remove(index);
return true;
}
}