前言:小编这里将讨论无头单向非循环的单链表。
1.ArrayList的缺陷
在上一期中,小编模拟了列表的相关操作实现,可以发现在增删的过程中非常麻烦,每次增加,或者删除数据的时候,都需要将操作下标的后面所有数据进行前移或者后移。
上期博客:http://t.csdnimg.cn/VI2yz
所以:
由于其底层是一段连续空间,当 在 ArrayList 任意位置插入或者删除元素时,就需要将后序元素整体往前或者往后 搬移,时间复杂度为 O(n) ,效率比较低,因此 ArrayList 不适合做任意位置插入和删除比较多的场景 。因此: java集合中又引入了LinkedList ,即链表结构。
2链表的概念
带头或者不带头
循环或者非循环
当然小编这里将讨论单向非循环;
3.链表的实现
3.1.初始化链表
static class linknode{
public int val;
public linknode next;
public linknode(int val){
this.val=val;
}
}
public linknode head;
首先定义一个类代表链表,在类中定义一个静态内部类,代表一个节点,节点内有值域,以及一个指针域。并在在构造函数中声明数值,方便在函数实例化时进行赋值操作,最后初始话一个头节点
3.2.链表赋值
public void createList(){
linknode node1=new linknode(12);
linknode node2=new linknode(12);
linknode node3=new linknode(14);
linknode node4=new linknode(15);
linknode node5=new linknode(16);
linknode node6=new linknode(17);
node1.next=node2;
node2.next=node3;
node3.next=node4;
node4.next=node5;
node5.next=node6;
this.head=node1;
}
实例化多个节点,并通过指针域进行相邻节点相连,但是小编不建议这么编写。
3.3.链表的头插法
public void addFirst(int data){
linknode node=new linknode(data);
node.next=head;
this.head=node;
}
图解:
所以 节点的next就为头结点,然后将头结点给node.
3.4.链表的尾插法
public void addLast(int data){
linknode cur=head;
linknode node=new linknode(data);
while (cur.next!=null){
cur=cur.next;
}
cur.next=node;
}
与头插法相似,实例化节点,通过遍历链表,将cur节点next到链表末尾,最后通过cur节点指针域指向实例化的节点,实现尾插法。
3.5.在任意位置实现插入
public void addIndex(int index,int data){
linknode cur=head;
linknode node=new linknode(data);
if (index==0){
addFirst(data);
return;
}
if (index==size()){
addLast(data);
return;
}
for (int i = 0; i <index-1; i++) {
cur=cur.next;
}
node.next=cur.next;
cur.next=node;
}
判断插入位置是哪里,如果为0,即为头插法,如果为链表末尾,就是尾插法。
最后找到插入位置的前一个节点,通过改变指针域的指向地址,实现插入。
3.6.值是否存在链表中
public boolean contains(int key){
linknode cur=head;
while (cur.next!=null){
if (cur.val==key){
return true;
}
cur=cur.next;
}
return false;
}
通过遍历每个节点,然后通过比较每个节点的数值域,如果存在则返回true,反之遍历完后,不存在则返回false。
3.7.删除第一次遇到的数值
public void remove(int key){
linknode cur=head;
if (head.val==key){
head=head.next;
return;
}
while (cur.next!=null){
if(cur.next.val==key){
cur.next=cur.next.next;
return;
}
cur=cur.next;
}
}
首先判断头结点的数值域是否等于key,等于就将头结点等于下一个节点。
反之遍历链表,如果存在该数值,就应该在数值的前一个节点进行操作,实现要删除节点的跳过操作。
3.8.实现所有key数值的删除
public void removeAllKey(int key){
linknode cur=head;
linknode prve=head;
while (cur!=null){
if (cur.val==key){
prve.next=cur.next;
cur=cur.next;
}else {
prve=cur;
cur=cur.next;
}
}
if(head.val==key){
head=head.next;
}
}
图解
首先我们定义两个节点 等于头结点,其中cur每次循环都要指向下一个节点,且如果不存在key时,prve倒要保持在cur节点的前一个,如果发现了key,则通过prve进行跳过,若存在重复,则,再次通过cur进行判断,在次通过prve进行跳过实现链接。
最后由于,头结点没有判断,就要进行头结点的判断。
3.9.实现链表的长度以及打印
public int size(){
int size=1;
linknode cur=head;
while (cur.next!=null){
cur=cur.next;
size++;
}
return size;
}
public void clear() {
this.head=null;
}
public void display() {
linknode cur=head;
while (cur!=null){
System.out.print(cur.val+" ");
cur=cur.next;
}
}
通过遍历链表,在节点不为空的情况下,每次循环长度加一,并且进行每个节点数值域的打印。
4.结束语
小编下一期将进行单向链表的相关题目讲解,想了解的uu关注一下吧。
限于小编能力有限,可能存在一些错误,希望各位uu提出宝贵意见,望指正。
制作不易,麻烦给小编一个赞吧。