使用单向链表实现LinkedList
来源:互联网 发布:mysql数据库ip怎么查询 编辑:程序博客网 时间:2024/06/01 21:58
单向链表是指节点中的指针域只有一个,指针域只能沿着同一个方向移动的链表。Java.util包中提供了LinkedList,此LinkedList是基于双向链表实现的。本文基于单向链表实现LinkedList中的某些方法,主要是学习使用下单向链表这种数据结构。
首先给出节点类,节点类中包含数据域value,和指针域next,以及三个构造函数。
class Entry { E value;//数据域 Entry next;//指针域 Entry() {} Entry (E value){ this.value = value; } Entry (E value, Entry next){ this.value = value; this.next = next; }}
为了方便处理链表中的插入,删除和查找操作,在链表的开始结点之前,增加一个head节点,此head节点指向开始结点。这样好处为:
- 开始结点的地址存放在了head节点中,这样开始结点的操作和其他节点的操作一样,无需特殊处理。
- 不论链表是否为空,其头结点的指针是指向开始节点的非空节点(只不过空链表时,头结点的指针域next为null)。空链表的处理和非空链表一样了。
我们将LinkedList类实现java.util.List<E>接口,尽可能的实现java.util.List<E>中的方法。实现的java.util.List<E>接口方法如下
indexOf(Object o)
返回元素o在链表中第一次出现的索引位置,未出现返回-1booleancontains(Object o)如果List中包含元素o则,返回true;否则falsebooleancontainsAll(Collection<?> c)List中是否包含集合c中的全部元素,是返回true,否则falsevoidclear()清空List中的值Object[]toArray()将链表转换为数组,返回Object[]T[]toArray(T[] a)将链表转换为类型为T的数组intlastIndexOf(Object o) 返回链表中value等于o的倒数第一个索引值。booleanretainAll(Collection<?> c)从链表中移除所有不在集合c中的元素。Iterator<E>iterator()返回链表的迭代子下面看下LinkedList类的具体实现。
LinkedList类成员域
LinkedList中除了有包含开始节点的head节点之外,还需要一个整型域count,此属性记录了链表中的节点个数。LinkedList类的成员域如下。
//头指针。private Entry head = new Entry();//节点个数private int count = 0;
add(E e)
向链表中插入节点时,是从开始节点插入:将新增节点指向开始节点,head指向新增节点
public boolean add(E e) { //新增节点 Entry addE = new Entry(e); addE.next = head.next; head.next = addE; count++; return true; }
add(int index, E element)
在特定位置,加入某个元素。
使用变量tmp表示当前处理的节点,变量pre表示当前节点的前趋,用i记录移动的元素个数。当i=index时,将前趋节点指针域指向新节点,新节点的指针域指向当前节点。
/* * 特定位置加入某个元素 */ @Override public void add(int index, E element) { if(index < 0 || index >= count) { throw new RuntimeException("index越界"); } int i = 0; Entry tmp = head.next; Entry pre = head; while(i != index) { tmp = tmp.next; pre = pre.next; i++; } Entry add = new Entry(element); pre.next = add; add.next = tmp; count++; }
addAll(Collection<?extendsE> c)
将集合c中的所有元素添加到链表中。利用集合c的迭代子循环增加元素
public boolean addAll(Collection<? extends E> c) { Iterator<? extends E> it = c.iterator(); while(it.hasNext()) { add(it.next()); } return true;
addAll(intindex, Collection<?extendsE> c)
在特定位置,向链表中添加集合c中的元素.
分两种情况:1、index<count,记录下前趋节点,将c中的元素追加到前趋节点的末尾,将追加的最后一个元素的指针域指向原index处的节点
2、index=count,即在末尾节点添加集合c中的元素。循环将c中的元素追加到末尾节点
public boolean addAll(int index, Collection<? extends E> c) { if(index < 0 || index > count) { throw new RuntimeException("index越界"); } /* * 如果index等于count大小,需要单独处理 */ if(index == count) { Entry tmp = head; while(null != tmp.next) { tmp = tmp.next; } //循环将c中的元素追加到末尾 Iterator<? extends E> it = c.iterator(); while(it.hasNext()) { Entry add = new Entry(it.next()); tmp.next = add; tmp = tmp.next; count++; } return true; } /* * 如果index < count,则按以下逻辑处理。 * 记录下前趋节点,移动到index处时,将c中的元素追加到前趋节点末尾 */ int i = 0; Entry tmp = head.next; Entry pre = head; while(i != index) { tmp = tmp.next; pre = pre.next; i++; } //循环将c中的元素追加到pre的末尾 Iterator<? extends E> it = c.iterator(); while(it.hasNext()) { Entry add = new Entry(it.next()); pre.next = add; pre = pre.next; count++; } //将pre的指针域指向原index处的节点tmp pre.next = tmp; return true; }
size()
返回链表中的元素个数
public int size() { return count; }
get(int index)
获取下标为index的元素。
1 通过head指针,循环去访问后继元素
2 因为插入时,是从开始结点插入的。获取时,后插入的先获取(栈)
/** 获取下标为index的元素*/public E get(int index) { if(index < 0 || index >= size()){ throw new RuntimeException("IndexOutOfBounds"); } //获取头指针 Entry headTemp = head; //开始节点 Entry target = headTemp.next; int i = 0; while(i != index) { target = target.next; i++; } return target.value; }
isEmpty()
空链表判断
public boolean isEmpty() { return size() == 0; }
remove(Object o)
移除链表中第一个元素值为o的元素。
记下当前节点的前趋节点,循环判断,如果移除的o与value相同,则将当前前趋节点的next指向
当前节点的next.
public boolean remove(Object o) { Entry tmp = head.next; if(null == tmp || null == o) { return false; } //tmp的前趋节点 Entry pre = head; while(null != tmp) { Object v = tmp.value; if(o.equals(v)) { pre.next = tmp.next; count--; return true; } pre = tmp; tmp = tmp.next; } return false; }
remove(intindex)
删除index处的元素
public E remove(int index) { if(index < 0 || index >= count) { throw new RuntimeException("index越界"); } //开始节点 Entry tmp = head.next; int i = 0; while(i != index) { tmp = tmp.next; i++; } return tmp.value; }
removeAll(Collection<?> c)
从链表中移除c中所有的元素。
利用集合c的迭代子,循环移除
public boolean removeAll(Collection<?> c) { Iterator<?> it = c.iterator(); while(it.hasNext()) { boolean re = remove(it.next()); if(re != true) { return false; } } return true; }
set(int index, E element)
将index处的值设置为元素element。
public E set(int index, E element) { if(index < 0 || index >= size()){ throw new RuntimeException("IndexOutOfBounds"); } //获取头指针 Entry headTemp = head; //开始节点 Entry target = headTemp.next; int i = 0; while(i != index) { target = target.next; i++; } E oldValue = target.value; target.value = element; return oldValue; }
indexOf(Object o)
获取某个值的索引。
元素o为null和不为null时分开处理。
public int indexOf(Object o) { Entry tmp = head.next; int index = 0; if(o == null) {//o为null while(tmp != null && tmp.value != null) { tmp = tmp.next; index++; } } else {//o不为null while(tmp != null && !o.equals(tmp.value)) { tmp = tmp.next; index++; } } if(null == tmp) { return -1; } else { return index; } }
contains(Object o)和containsAll(Collection<?> c)
链表中是否包含某个元素
public boolean contains(Object o) { return indexOf(o) != -1; }
链表中是否包含集合c中的所有元素
public boolean containsAll(Collection<?> c) { Iterator<?> it = c.iterator(); while(it.hasNext()) { boolean re = contains(it.next()); if(re != true) { return false; } } return true; }
clear()
清空链表。只是让头节点指向了null。内存中真正的节点,并为消失
public void clear() { head.next = null; count = 0; }
toArray()和toArray(T[] a)
将链表转换为数组
public Object[] toArray() { Object[] arr = new Object[count]; Entry tmp = head.next; int i = 0; while(null != tmp) { arr[i] = tmp.value; tmp = tmp.next; } return arr; }
将链表转换为类型为T的数组,如果给定的a长度不够,则将重新实例化一个T数组。
public <T> T[] toArray(T[] a) { //如果a的长度不够,则重新实例化一个数组 if (a.length < count) a = (T[])java.lang.reflect.Array.newInstance( a.getClass().getComponentType(), count); Object[] re = a; Entry tmp = head.next; int i = 0; while(null != tmp) { re[i] = tmp.value; i++; tmp = tmp.next; } //多出部分填充为null if(a.length > count) { a[count] = null; } return a; }
lastIndexOf(Object o)
返回链表中value等于o的倒数第一个索引值。
逻辑:将链表向后移动判断每个value值,并使用一个变量lastIndex存储value与o最后一次相等的索引地址,当链表移动到末尾时,如果lastIndex值为-1,说明链表中不存在value为o的节点,否则,返回lastIndex的值。o为null时和不为null时,分开处理
public int lastIndexOf(Object o) { Entry tmp = head.next; int index = 0; int lastIndex = -1; if(o == null) { while(tmp != null) { if(tmp.value != null) { tmp = tmp.next; index++; } else { lastIndex = index; tmp = tmp.next; index++; } } } else { while(tmp != null) { if(!o.equals(tmp.value)) {//如果元素o与value不相等,则继续向后移动。 tmp = tmp.next; index++; } else {//如果元素o与value相等,则记录下此处的索引,继续向后移动,寻找是否还有值与o相等。 lastIndex = index; tmp = tmp.next; index++; } } } if(-1 == lastIndex) { return -1; } else { return lastIndex; } }
retainAll(Collection<?> c)
从链表中移除所有不在集合c中的元素。
public boolean retainAll(Collection<?> c) { Entry tmp = head.next; Entry pre = head;//tmp的前趋节点,移除时使用 while(null != tmp) { E value = tmp.value; if(!c.contains(value)) {//如果c中不包含value,则移除对应的节点,并将tmp指向tmp.next,pre指针不动。 pre.next = tmp.next; count--; tmp = tmp.next; continue; } //如果c中包含value,则将tmp指向tmp.next,pre指向tmp。 pre = tmp; tmp = tmp.next; } return true; }
iterator()
获取链表的迭代子
public Iterator<E> iterator() { class Itr implements Iterator<E> { //迭代类中,所处理元素的当前索引位置。起始为-1 private int cur = -1; @Override public boolean hasNext() { return cur + 1 < size(); } //获取迭代类中当前索引的元素 @Override public E next() { cur++; E tmp = get(cur); return tmp; } @Override public void remove() { //必须调用过next()方法 if(cur < 0) { throw new RuntimeException("cur<0"); } //移除cur处的元素 Entry tmp = head.next; Entry pre = head; int i = 0; while(cur != i && tmp != null) {//cur与i不相等且没有移动到末尾 tmp = tmp.next; pre = pre.next; i++; } //当移动到当前处理的节点cur时,进行移除处理 if(cur == i) { if(tmp != null) { //移除的为非末尾节点 pre.next = tmp.next; count--; cur--;//迭代子处理的元素位置减1 return; } else { //移除的为末尾节点 pre.next = null; count--; cur--;//迭代子处理的元素位置减1 return; } } else { throw new RuntimeException("找不到remove的元素"); } } } return new Itr(); }
阅读全文
0 0
- 使用单向链表实现LinkedList
- 单向链表LinkedList的使用
- LinkedList 单向链表
- 自己实现单向链表讨论一下LinkedList的效率
- 使用C++实现单向链表
- C++ 使用单向链表实现Stack
- 单向链表实现
- 单向链表实现
- 使用C++实现的单向循环链表
- C#实现单向链表
- 单向链表实现源代码
- java 实现单向链表
- 单向链表实现反转
- java实现单向链表
- C++实现单向链表
- 单向链表的实现
- java 单向链表实现
- C#实现单向链表
- 关于最近NOIP提高组复赛的总结
- C语言开发小练习2
- Java6集合类源码解读-----ArrayList中一个有趣的变量oldData
- 线程同步的资料参考和之前有些疑问的补充
- 手把手教你深度定制tiny4412安卓5.0系统(一)---开发板如何预置文件到android系统
- 使用单向链表实现LinkedList
- Python——浅拷贝/深拷贝/赋值
- Openface在Ubuntu系统下的环境搭建(使用Anaconda管理,在Ubuntu14.04与16.04上都有效)
- String使用equals方法和==分别比较的是什么?(转)
- 用AI赋能Predix边缘计算平台
- angular 创建组件报错
- 一.ARM裸机学习之ARM汇编
- URL编码转UTF-8
- 模板整理——图论·最小生成树·Kruskal