简单使用java创建出单向链表类

简单使用java创建出单向链表类

1、链表的概述虽然顺序表的查询快,时间复杂度为O(1),但是增删的效率是比较低的,因为每一次增删操作都伴随着大量的数据元素移动。

链表是一种物理存储单元上非连续,非顺序的存储结构,其物理结构不能只管的表示数据元素的逻辑顺序,数据元素的逻辑顺序是通过链表中的指针连接次序实现的。

链表由一系列的节点(链表中的每一个元素称为节点)组成,节点可以在运行时动态生成。

线性表的数据存储可以是顺序存储也可以是链式存储,按照存储方式的不同,可以把线性表分为顺序表和链表。

2、单向链表单向链表是链表的一种,它由多个节点组成,每个节点都由一个数据与和一个指针域组成;数据域存储数据,指针域用来指向其他后继节点。

链表的头结点的数据域不存储数据,指针域指向第一个真正存储数据的节点

如下图所示:

3、API设计类名

LinkList

构造方法

LinkList():创建LinkList对象

成员方法

1. public void clear():空置线性表2. public boolean isEmpty():判断线性表是否为空,是返回true,否则反之3. public int length():返回线性表中的元素个数4. public T get(int i):读取并返回线性表中的第i个元素5. public void insert(T t):往线性表中添加一个元素6. public void insert(int i,T t):在线性表的第i个元素之前插入一个值为t的数据元素7. public T remove(int i):删除并返回线性表中第i个数据元素8. public int indexOf(T t):返回线性表中首次出现的指定的数据元素的位序号,若不存在,则返回-1

成员内部类

private class Node:节点类

成员变量

1. private Node head:记录首节点2. private int N:记录链表的长度

4、代码实现4.1 创建成员变量与节点类成员变量和节点类需要先进行创建,因为这两个东西是在链表中不可或缺的。

成员变量直接声明即可。

代码语言:javascript代码运行次数:0运行复制private Node head;// 记录头节点

private int N;// 元素个数4.1.1 节点类节点类可以用private修饰。毕竟只是在内部使用。

每个节点都需要有一个存储内容的变量,所以这里声明一个T泛型的item变量。

而每个节点都需要有指针,因为每个节点所指向的就是节点,所以这里声明一个Node节点类的next变量。

最后给这个类配置好构造方法即可。

代码语言:javascript代码运行次数:0运行复制private class Node {

public T item;// 存储元素

public Node next;// 指向下一个节点

public Node(T item, Node next) {

this.item = item;

this.next = next;

}

}4.2 初始化构造和基础信息获取4.2.1 构造方法我们的链表,需要在声明时就进行头结点和元素个数的初始化,意味着这需要一个构造方法

这里直接用this指向head和N进行初始化,节点为一个null节点,毕竟存储的内容不知道,也不知道指向谁。N为0

代码语言:javascript代码运行次数:0运行复制// 实现构造,初始化头结点和元素个数

public LinkListDemo(){

this.head = new Node(null,null);

this.N = 0;

}4.2.2 清除链表我们如何清除链表呢?我们知道链表由头节点开始,那么将头结点的指针清空不就清空链表了?

说着就做,将head头结点的指针改为null值,让它的指向为null。

同时,N记录元素个数的变量也改为0,都没内容了个数也要清空。

代码语言:javascript代码运行次数:0运行复制// 清除链表

public void clear(){

head.next = null;

this.N = 0;

}4.2.3 获得元素个数获取链表中的元素个数,直接返回N就好,因为N就是记录着链表中的元素个数的变量。

代码语言:javascript代码运行次数:0运行复制// 获得链表的元素总个数

public int length(){

return N;

}4.2.4 判断链表是否为空如何判断链表为空?我们只需要判断N变量是否为0就好了,如果链表元素个数为0,那么就会自动返回true

代码语言:javascript代码运行次数:0运行复制// 判断元素链表是否为空

public boolean isEmpty(){

return N==0;

}4.3 获得元素或元素所在位置4.3.1 根据索引获得元素方法中,由于传进来的是int类型也就是索引,那么我们可以根据该索引使用for循环进行遍历链表,但链表的遍历如何遍历?我们知道链表由头节点开始,那么我们也可以从头结点开始对下一个元素进行获取,当循环结束时,那么元素就找到了。

这里需要用辅助节点来记录循环得到的节点。

经过循环,o.next 赋值 o,最后返回o的内容即可。

代码语言:javascript代码运行次数:0运行复制// 根据索引得到元素

public T get(int i){

// 通过循环,从头节点开始往后找,依次找i次,既可找到对应的元素

Node o = head.next;

for (int index = 0;index

o = o.next;

}

return (T) o.item;

}4.3.2 获得元素首次出现在链表中的位置与查找元素类似,但在循环中要操作的步骤变多了,我们需要判断方法传入的内容与当前遍历元素的内容是否一致,如果一致那么元素就找到了。找到元素返回当前遍历的索引即可。

这里与查找元素不一样的是,在声明辅助节点变量时,不需要head.next,因为我们的索引是从0开始的,当然如果加上head.next把索引改为1即可。

在for循环内部判断内容元素是否一致,一致则返回当前循环的索引值

代码语言:javascript代码运行次数:0运行复制// 获得元素首次出现在链表中的位置

public int indexOf(T t){

// 从头节点开始,依次找到每一个节点和t比较

Node n = head;

for (int index = 0; n.next != null; index++) {

n = n.next;

if (n.item.equals(t)){

return index;

}

}

return -1;

}4.4 插入元素4.4.1 向链表中插入一个元素如何插入一个元素呢?1. 我们需要找到当前链表的最后一个元素 2. 创建新节点 3. 让最后一个节点指向我们创建好的新节点即可 4. 元素个数+1

由于没有索引,所以用while循环从头开始遍历链表。当节点的下一个节点为空就停止遍历。

创建新节点,内容就是方法中传入的内容,指针为null毕竟是添加到链表末尾的元素。

老末尾元素的指针指向新节点进行赋值。

元素个数N++即可。

代码语言:javascript代码运行次数:0运行复制// 向链表中插入数据

public void insert(T t){

// 找到当前最后一个节点

Node n = head;

while (n.next != null){

n = n.next;

}

// 创建新节点,保存元素t

Node newNode = new Node(t, null);

// 让当前最后一个节点指向新节点

n.next = newNode;

// 元素的个数+1

N++;

}4.4.2 向表中指定元素前插入一个元素由于方法中传入了i索引,所以我们可以根据i索引获得到对应的元素,步骤与在末尾插入元素是一致的,同时查找get方法的遍历也是一致的,所以这里直接套用。

代码语言:javascript代码运行次数:0运行复制// 向表中的第i处元素前插入t元素

public void insert(int i,T t){

// 找到i位置的前一个节点

Node pre = head;

for (int index = 0; index <= i-1; index++) {

pre = pre.next;

}

// 找到i位置的节点

Node curr = pre.next;

// 创建新节点,并且新节点要指向原来i位置的节点

Node tNode = new Node(t, curr);

// 原来i位置的前一个节点指向新节点

pre.next = tNode;

// 元素的个数+1

N++;

}4.5 删除指定索引处的元素删除有以下步骤:

1.找到索引处的前一个元素

2.找到索引处的元素

3.找到元素的下一个元素

4.索引处的元素前一个元素指向元素的下一个元素

5.元素个数-1

6.返回元素

第一步的我们需要对链表进行遍历,与get方法的遍历不一样,由于获得的是前一个元素,所以辅助节点直接等于head头结点即可然后由它开始遍历。

第二步,找到前一个元素了直接.next就拿到了索引处的元素

第三步,找到索引处的元素直接.next就拿到了索引处元素的下一个元素

第四步,前一个元素指向下一个元素即可。

第五步,元素个数N–即可。

第六步,返回索引处的元素内容

代码语言:javascript代码运行次数:0运行复制// 删除指定i处的元素

public T remove(int i){

// 找到i位置的前一个节点

Node pre = head;

for (int index = 0; index <= i-1; index++) {

pre = pre.next;

}

// 找到i位置的节点

Node curr = pre.next;

// 找到i位置的下一个节点

Node curr2 = curr.next;

// 前一个节点指向下一个节点

pre.next = curr2;

// 元素个数-1

N--;

return (T) curr.item;

}5.总结:每一次查询,都需要从链表的头部开始,依次向后查找,随着数据元素N的增多,比较的元素越多,时间复杂度为:O(n)

每一次插入,需要先找到位置的前一个元素,然后完成插入操作,随着数据元素N的增多,查找的元素越多,时间复杂度为:O(n)

每一次移除,需要先找到位置的前一个元素,然后完成移除操作,随着数据元素N的增多,查找的元素越多,时间复杂度为:O(n)

相比较顺序表,链表的插入和移除的时间复杂度虽然一样,但是仍有很大的优势,因为链表的物理地址是不连续的,它不需要预先指定存储空间大小,或者在存储过程中设计到扩容等操作,同时它并没有涉及到元素的交换。

链表的查询操作性能会比较低,因此,如果我们的程序中查询操作比较多,建议使用顺序表;如果增删操作比较多,建议使用链表

相关推荐