链表的5种操作及单链表逆置
鉴于本人对写作真的没有任何兴趣,从小学开始写作文完全是凑字数,写小说也半途而废,所以从这篇文章开始我要放飞自我,怎么开心怎么写,不要严肃,要沙雕。(突然发现居然有人会看我的文章,为了不误人子弟,我决定痛改前非,好好写!!!)
为什么有链表
众所周知,我们平时最爱用数组存储数据,那么为什么还有链表这个东西呢??让我们来看看链表是什么?数组和链表有什么区别。
数组和链表都可以用来存储数据,但是二者在内存中存储数据的空间形式有很大区别。
数组的存储空间连续的,不可更改的
但是链表就不同了
又称
链表灵活随意的存储方式注定了链表的存储难度远低于数组,他更优秀的地方在于,他的各种操作真的很方便,也就是代码真的很少。
先给大家展示一下链表的样子
链表,有节点和节点间的联系(也就是链表中的那条链子),节点又分数据域和引用域,数据域用来存储链表中的数据,引用域用来记录下一个节点的存储位置(就是那条链子)
节点的种类分为,头结点和尾节点,和普通节点,尾节点最后要指向空。
接下来,我将结合代码,像大家讲一下链表各项功能的实现以及链表他到底方便在哪里
前提所需
在c语言中,链表的实现靠结构体和指针,但是这些东西java里通通没有,通通没有!!所以,用Java怎么实现呢??
我们要用类!
首先我们来根据链表的特性建两个类(为了大家方便复制代码【虽然我觉得有人疯了才会复制我的代码】,也为了满足我想敲键盘的快感,我会打很多代码的)。
一个是Node类,来封装节点的属性,一个是Linked类,实现链表功能
public class Node<E>{ //这里,我们要用到泛型,因为不知道会存进来什么样的数据
public E e; //数据域中的数据
public Node<E> next; //这个就是最重要的那个链,记住下一个节点的位置,就是那个箭头,又称后继
public Node<E>(){}
public Node<E>(e){
this.e=e;
}
public class LInked<E>{
public Node<E> root; //声明一个头结点
public Node<E> tail; //声明一个尾节点
int size; //定义链表的大小
public Linked(){
root=new Node<E>(); //实例化头结点
}
功能一,添加
将传入的数据加入整个链表的末尾
public void add(E e){ //传入一个数据
Node<E> node=new Node<E>(e); //生成一个以e为数据的节点
if(root.next==null){ //此时链表为空,只有头结点(头结点内没有数据)
root.next=node; //让头结点的后继变为新生成的node这个节点,也就是让root的箭头指向node
tail=node; //让新生成的node节点变成尾节点
size++; //链表大小加一
}
else{
tail.next=node; //让尾节点的后继变为node
tail=node; //node变成心得尾节点
size++;
}
(在这里我不得不感叹我的数据结构老师真的教的太好了,很可惜人家回去生宝宝了,一定是一个很温柔的宝宝,随妈妈!)
删除
删除链表中的任意一个节点,并返回删除元素的值
public E remove(int index){ //传过来一个想删除的位置
E e=null; //先声明一个e,设为null
if(index<0||index>size) //第一种情况,删除的位置比零小,比链表的长大
return e;
else if(index==size-1) {//第二种情况,删除尾节点
Node<E> node=new Node<E>(e); //先生成一个新的节点,用于记录尾节点的值
e=tail.e; //获取尾节点的值
Node<E> periodnode=new Node<E>(e); //再生成一个节点,用于获取被删节点的前一个节点
periodnode=getNode(index-1);//获取前一个节点,getNode是返回当前操作的节点,之后给出代码
periodnode.next=null;//将被删节点的前一个节点的后继设为空,即设为尾节点,原先的尾节点因为没有引用,java自动将其删除
size--;
}
else if(index==0){ //第二种情况,删除第一个节点
Node<E> node =new Node<E>(e); //生成一个新的节点,用于记录被删节点的值
node=getNode(index); //获取被删节点
e=node.e; //获取被删节点的值
root.next=node.next; //根节点的后继指向被删节点的后继
node.next=null; //被删节点的后继置为null,被java自动删除
size--;
return e;
}else{ //第三种情况,删除任意一个节点
Node<E> node=new Node<E>(e); //生成一个节点,用于记录被删节点的值
node=getNode(index); //获取被删节点
Node<E> periodnode=new Node<E>(e); //在生成一个节点
periodnode=getNode(index-1); //获取被删节点的前一个节点
Node<E> nextnode=new Node<E>(e); //再生成一个节点
nextnode=node.next; //获取被删节点的后一个节点
e=node.e; //获取被删节点的值
periodnode.next=node.next; //让被删节点的前一个节点的后继指向被删节点的后一个节点,即被删节点的前一个节点的后继指向被删节点的后继,即断开被删节点和前一个节点的联系
node.next=null; //被删节点置为空,即断开被删节点和后一个节点的联系
size--;
return e;
}
}
插入
将元素插入到任意一个位置
public void put(E e,int index){
if(index!=1){
Node<E> newnode=new Node<E>(e); //生成一个新的节点,把他加进去
Node<E> periodnode=getNode(index-1); //再生成一个节点,记录想加位置的前一个节点
Node<E> node=getNode(index); //再生成一个节点,记录想加位置的节点
newnode.next=node; //要加进去的新节点的后继指向已存在的在原位置的节点
periodnode.next=newnode; //想加位置的前一个节点的后继指向新节点
size++;
}
else{
Node<E> newnode=new Node<E>(e); //当想加入头结点后,同理
Node<E> node=getNode(index);
newnode.next=node;
root.next=newnode;
size++;
}
}
查找
查找任意一个值
public Node<E> getNode(int index) { //返回当前要操作的节点
Node<E> node = root.next;
for (int i = 0; i < index; i++) {
node=node.next;
}
return node;
}
public E get(int index){ //一个简单的循环即可
E e=null;
Node<E> node=new Node<E>(e);
node=getNode(index);
return node.e;
}
修改
修改任意一个值
public Node<E> getNode(int index) {//返回当前要操作的节点
Node<E> node = root.next;
for (int i = 0; i < index; i++) {
node=node.next;
}
return node;
}
public void change(int index,int a){
E e=null;
Node<E> node=new Node<E>(e);
node=getNode(index);
node.e=a;
}
单链表逆置
敲到这里,真心觉得,认真作一篇博客好累。
接下来就是链表逆置,挺经典的一道题,加油!!!
链表逆置就是把1234567变成7654321。又将是死亡的作图过程。
public void backput(){
E e=null;
Node<E> pnode=new Node<E>(e); //设置一个节点pnode
Node<E> qnode=new Node<E>(e); //设置另一个节点qnode
pnode=root.next; //让根节点的后继指向pnode
root.next=null; //根节点后继置为空
while(pnode!=null){ //pnode不空
qnode=pnode.next; //pnode的后继指向pnode
pnode.next=root.next; //根节点后继指向pnode的后继
root.next=pnode; //看图吧
pnode=qnode; //看图吧
}
}
代码中还有各位需要注意的index从零取这种小问题,这篇文章到此结束啦
画图真的太死亡了,希望那些点进我的博客的人能对你们有一些用处
啦啦啦啦啦啦,我是哈哈哈哈哈士奇,我们下期再见(应该不会有了吧)!