链表中的每一个元素都包含一个称为节点的结构,每向链表中增加一个元素,就会产生一个与之相关的节点,每个节点与它相邻的节点相连接(这是基础吧,不过在看c的时候没认真看,呼)。

定义节点类如下(使用了泛型,下面有个简单的具体实例):

  class Node<E>{
   E element ;
   Node<E> next;
   public Node(E e){
   element = e;
   }
  }

下面讲解一个储存3个元素的链表的例子,每一个节点储存一个字符串;

1、先声明head(指向第一个节点) 和tai(指向最后一个节点),刚开始时都是null

Node<E> head  =  null;
Node<E> tail = null;
//链表为空

2、追加第一个节点

head = new Node<E>("Chicgo");
last = head;

3、追加第二个节点

tail.next  = new Node<E>("Denver");
tail = tail.next;

3、追加第三个节点

tail.next = new Node<E>("Dallas");
tail = tail.next;

每一个节点都包含元素和一个名为next的数据域,next指向下一个元素。如果元素是链表中的最后一个元素。则它的next所包含的为null,用这个特性可以检测某个节点是否为最后一个节点,例如下面的遍历程序:

Node current  = head;
while()current !=null){
System.out.println(current.element);
current = current.next;
}

下面就结合上面的知识给个简单的int类型事例:

//一个节点类,每一个元素都包含了一个称为节点的结构
public class Node{
int element;
Node next ;
public Node(int n){ //元素赋值
element = n;
}
public static void main(String[] args) {
Node head , tail; //申明head和tail
head = new Node(1); //插入第一个元素
tail = head; //head和tail在一起
System.out.println(head.element); //输出第一个元素
tail.next = new Node(2); //插入第二个元素
tail = tail.next;
tail.next =new Node(3);
tail = tail.next;
Node current = head ;
while (current != null){ //遍历寻遍输出
System.out.print(current.element);
current = current.next;
}
}
}

java中有提供LinkedList的类,可以通过导入 java.util.LinkedList来使用,不过书本上有教我们写一个自己的MyLinkedList,便于理解,这对我们掌握链表还是很有必要的。下面我们可以来仔细研究一下MyLinkedList了,有好多方法,不像MyArrayList容易理解,书本上也只是讲了几个方法,剩下的就自己去理解了,也不是很难,这里讲3个吧,就当练习打字。

(补充:head始终指向链表的第一个节点,而tail则始终指向最后一个节点)

1、实现addFirst(e)方法,就是创建第一个节点:

//创建一个包含e元素节点,并放在第一个节点
public void addFirst(E e) {
Node<E> newNode = new Node<E>(e); // 创建一个的节点
newNode.next = head; //新节点的next数据域指向head
head = newNode; // head 指向新的节点
size++; if (tail == null) // 若链表为空,则head和tail都指向新节点
tail = head;
}

(书本上的那个图很好看,但是画不下来==)

2、实现add(index,e)方法,当index为0或则是在最后一个元素时就不说了,直接调用方法addFirst(e)或则addLast(e)就行了,若插入到中间时,假设为current和temp节点之间,则首先从head开始前进找到current的next,并被新节点赋给它,在把新节点的next指向temp,画个图就很容易理解了。

public void add(int index, E e) {
if (index == 0) {
addFirst(e);
}
else if (index >= size) {
addLast(e);
}
else {
Node<E> current = head;
for (int i = 1; i < index; i++) {
current = current.next;
}
Node<E> temp = current.next;
current.next = new Node<E>(e);
(current.next).next = temp;
size++;
}
}

3、实现removeLast()方法,如果链表为空就返回null,如果只有一个节点就销毁并且head和tail都变为null,否则最后一个节点销毁,tail指向倒数第二个节点,size减一。

public E removeLast() {
if (size == 0) {
return null;
}
else if (size == 1) {
Node<E> temp = head;
head = tail = null;
size = 0;
return temp.element;
}
else {
Node<E> current = head; //要从head开始遍历,增加了时间
for (int i = 0; i < size - 2; i++) {
current = current.next; //找到倒数第二个节点
} Node<E> temp = tail; //临时引用temp
tail = current;
tail.next = null;
size--;
return temp.element;
}
}

最后在给出MyLinkedList的实现(仅有部分方法实现,还有部分,做作业):

 public class MyLinkedList<E> extends MyAbstractList<E> {
private Node<E> head, tail; //创建默认链表
public MyLinkedList() {
} public MyLinkedList(E[] objects) {
super(objects);
} //获得链表的头
public E getFirst() {
if (size == 0) {
return null;
}
else {
return head.element;
}
} //获得链表的尾
public E getLast() {
if (size == 0) {
return null;
}
else {
return tail.element;
}
} //创建一个包含e元素节点,并放在第一个节点
public void addFirst(E e) {
Node<E> newNode = new Node<E>(e); // 创建一个的节点
newNode.next = head; //新节点的next数据域指向head
head = newNode; // head 指向新的节点
size++; if (tail == null) // 若链表为空,则head和tail都指向新节点
tail = head;
} //创建一个包含e元素节点,并放在最后一个节点
public void addLast(E e) {
Node<E> newNode = new Node<E>(e); if (tail == null) {
head = tail = newNode;
}
else {
tail.next = newNode;
tail = tail.next;
}
size++;
} //将一个元素插入到链表的指定下标处
public void add(int index, E e) {
if (index == 0) {
addFirst(e);
}
else if (index >= size) {
addLast(e);
}
else {
Node<E> current = head;
for (int i = 1; i < index; i++) {
current = current.next;
}
Node<E> temp = current.next;
current.next = new Node<E>(e);
(current.next).next = temp;
size++;
}
} //删除链表中的的首个元素
public E removeFirst() {
if (size == 0) {
return null;
}
else {
Node<E> temp = head;
head = head.next;
size--;
if (head == null) {
tail = null;
}
return temp.element;
}
} //删除最后一个元素
public E removeLast() {
if (size == 0) {
return null;
}
else if (size == 1) {
Node<E> temp = head;
head = tail = null;
size = 0;
return temp.element;
}
else {
Node<E> current = head; //要从head开始遍历,增加了时间
for (int i = 0; i < size - 2; i++) {
current = current.next; //找到倒数第二个节点
} Node<E> temp = tail; //临时引用temp
tail = current;
tail.next = null;
size--;
return temp.element;
}
} //删除指定下标的元素
public E remove(int index) {
if (index < 0 || index >= size) {
return null;
}
else if (index == 0) {
return removeFirst();
}
else if (index == size - 1) {
return removeLast();
}
else {
Node<E> previous = head; for (int i = 1; i < index; i++) {
previous = previous.next;
} Node<E> current = previous.next;
previous.next = current.next;
size--;
return current.element;
}
} public String toString() {
StringBuilder result = new StringBuilder("["); Node<E> current = head;
for (int i = 0; i < size; i++) {
result.append(current.element);
current = current.next;
if (current != null) {
result.append(", "); // 插入歌逗号
}
else {
result.append("]"); // 插入]
}
} return result.toString();
} //清空
public void clear() {
head = tail = null;
} /** Return true if this list contains the element o */
public boolean contains(E o) {
System.out.println("Implementation left as an exercise");
return true;
} /** Return the element from this list at the specified index */
public E get(int index) {
System.out.println("Implementation left as an exercise");
return null;
} /** Return the index of the head matching element in this list.
* Return -1 if no match. */
public int indexOf(E o) {
System.out.println("Implementation left as an exercise");
return 0;
} /** Return the index of the last matching element in this list
* Return -1 if no match. */
public int lastIndexOf(E o) {
System.out.println("Implementation left as an exercise");
return 0;
} /** Replace the element at the specified position in this list
* with the specified element. */
public Object set(int index, E o) {
System.out.println("Implementation left as an exercise");
return null;
} private static class Node<E> {
E element;
Node<E> next; public Node(E element) {
this.element = element;
}
}
}

在附上一个测试程序:

 public class TestLinkedList {
/** Main method */
public static void main(String[] args) {
// Create a list for strings
MyLinkedList<String> list = new MyLinkedList<String>(); // Add elements to the list
list.add("America"); // Add it to the list
System.out.println("(1) " + list); list.add(0, "Canada"); // Add it to the beginning of the list
System.out.println("(2) " + list); list.add("Russia"); // Add it to the end of the list
System.out.println("(3) " + list); list.addLast("France"); // Add it to the end of the list
System.out.println("(4) " + list); list.add(2, "Germany"); // Add it to the list at index 2
System.out.println("(5) " + list); list.add(5, "Norway"); // Add it to the list at index 5
System.out.println("(6) " + list); list.add(0, "Poland"); // Same as list.addFirst("Poland")
System.out.println("(7) " + list); // Remove elements from the list
list.remove(0); // Same as list.remove("Australia") in this case
System.out.println("(8) " + list); list.remove(2); // Remove the element at index 2
System.out.println("(9) " + list); list.remove(list.size() - 1); // Remove the last element
System.out.println("(10) " + list);
}
}

关于MyArrayList和MyLinkedList的方法的复杂度,看下面的图

java线性表学习笔记(二)的更多相关文章

  1. java线性表学习笔记(一)

    线性表是一种按顺序储存数据是的常用结构,大多数的线性表都支持以下的典型操作: 从线性表提取插入删除一个数据: 找出线性表中的某一个元素: 找出线性表中的元素: 确定线性表中是否包含某一个元素,确定线性 ...

  2. java之jvm学习笔记二(类装载器的体系结构)

    java的class只在需要的时候才内转载入内存,并由java虚拟机的执行引擎来执行,而执行引擎从总的来说主要的执行方式分为四种, 第一种,一次性解释代码,也就是当字节码转载到内存后,每次需要都会重新 ...

  3. 《深入理解Java虚拟机》学习笔记(二)

    垃圾回收的前提是判断对象是否存活,对象不再存活时将会被回收,下面是2种判断的方法. 引用计数法: 主流的Java虚拟机并没有使用引用计数法来管理内存,重要的原因就是循环引用的问题难以解决. 可达性分析 ...

  4. Java多线程技术学习笔记(二)

    目录: 线程间的通信示例 等待唤醒机制 等待唤醒机制的优化 线程间通信经典问题:多生产者多消费者问题 多生产多消费问题的解决 JDK1.5之后的新加锁方式 多生产多消费问题的新解决办法 sleep和w ...

  5. java之jvm学习笔记六-十二(实践写自己的安全管理器)(jar包的代码认证和签名) (实践对jar包的代码签名) (策略文件)(策略和保护域) (访问控制器) (访问控制器的栈校验机制) (jvm基本结构)

    java之jvm学习笔记六(实践写自己的安全管理器) 安全管理器SecurityManager里设计的内容实在是非常的庞大,它的核心方法就是checkPerssiom这个方法里又调用 AccessCo ...

  6. Java IO学习笔记二

    Java IO学习笔记二 流的概念 在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据的时候要使用输入流读取数据,而当程序需要将一些数据保存起来的时候,就要使用输出流完成. 程序中的输入输 ...

  7. 学习笔记(二)--->《Java 8编程官方参考教程(第9版).pdf》:第七章到九章学习笔记

    注:本文声明事项. 本博文整理者:刘军 本博文出自于: <Java8 编程官方参考教程>一书 声明:1:转载请标注出处.本文不得作为商业活动.若有违本之,则本人不负法律责任.违法者自负一切 ...

  8. Java IO学习笔记二:DirectByteBuffer与HeapByteBuffer

    作者:Grey 原文地址:Java IO学习笔记二:DirectByteBuffer与HeapByteBuffer ByteBuffer.allocate()与ByteBuffer.allocateD ...

  9. 《深入理解Java虚拟机》学习笔记

    <深入理解Java虚拟机>学习笔记 一.走近Java JDK(Java Development Kit):包含Java程序设计语言,Java虚拟机,JavaAPI,是用于支持 Java 程 ...

随机推荐

  1. java.io.InvalidClassException: com.master.CurrentMessages; local class incompatible:

    报错信息如下: java.io.InvalidClassException: com.master.CurrentMessages; local class incompatible: stream ...

  2. DataGridView导出Excel

    将DataGridView里面的数据,导出到表格里面去. 首先,需要添加三个引用 直接在解决方案里,右键添加引用,找到路径即可.然后再把这三个文件复制到项目的根目录下. 然后定义导出表格的函数: pu ...

  3. codeforces 450 B Jzzhu and Sequences

    题意:给出f1=x,f2=y,f(i)=f(i-1)+f(i+1),求f(n)模上10e9+7 因为 可以求出通项公式:f(i)=f(i-1)-f(i-2) 然后 f1=x; f2=y; f3=y-x ...

  4. web前端调试工具

    1.firebug入门指南 http://www.ruanyifeng.com/blog/2008/06/firebug_tutorial.html 2. Console命令详解,让调试js代码变得更 ...

  5. putty保持Session链接不断开的方法

    利用Putty登陆到远程主机后,如果长时间没有做任何操作,服务器会与本地客户端断开连接 假如设置了会话连接功能,就会每隔多少秒,客户端会发送一个空数据包给服务器,保持连接. 1. 打开putty.ex ...

  6. mysql里group by按照分组里的内容的排序

    得到一张表里按u_id分组,按count(id)排序,每个分组的pub_time最大的哪些记录,只取count(id)最大的4条 select a.u_id,a.name,a.u_name,a.id, ...

  7. Heritrix源码分析(四) 各个类说明(转)

    Heritrix的类的确很繁琐,往往继承了一层又一层,最多的继承好像有7层.下面就一个包一个包的说明每个类的作用,由于里面Heritrix组件分明,很多组件没用到的同时该组件的类我也没怎么接触,所以这 ...

  8. mysql利用存储过程批量插入数据

    最近需要测试一下mysql单表数据达到1000W条以上时增删改查的性能.由于没有现成的数据,因此自己构造,本文只是实例,以及简单的介绍. 首先当然是建表: [sql]view plaincopy CR ...

  9. Java反射基本玩法

    三个主要的反射类 Class反射对象描述类语义结构,可以从Class对象中获取构造函数.成员变量.方法类等元素的反射对象,并以编程的方式通过这些反射对象对目标类对象进行操作.这些反射对象类在java. ...

  10. Oracle数据库备份手册

    1         故障类型 l  实例故障 由ORACLE内部异常.操作系统故障或其它相关软件引起,导致ORACLE实例中的进程或内存区出现故障或数据库无法正常关闭,这种故障称为实例故障.实例故障没 ...