单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。其存储的各节点不一定连续,链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),next指向下一个节点
1.定义单链
package List;
//链节点,有数据域和指针域构成
public class Node {
public long data; //数据域
public Node next; //指针域
public Node(long value) {
this.data = value;
}
public void display() {
System.out.print(data+" ");
}
}
2.链表实现
package List;
//链表,
public class Linklist {
private Node first;// 首个链接点,相当于车头
public Linklist() {
first = null; //其链默认指向null
}
//在头节点前插入一个节点
public void insertfirst(long value) {
Node curr = new Node(value);
curr.next = first; //插入节点指向首节点指向的节点
first = curr; //首节点更新
}
//在头节点后删除一个节点
public Node removefirst() {
Node temp = first; //定义当前节点
first = temp.next; //直接跳过first.next,从而指向第三个节点
return temp;
}
//显示链表
public void display1() {
Node curr = first;
while(curr != null) //判断当前有元素存在
{
curr.display(); //调用Node里面的显示方法
curr = curr.next;//继续遍历下个节点
}
System.out.println();
}
//查找链节点
public Node find(long value) {
Node curr = first;
while(curr.data!=value) {
if(curr.next==null) {
return null;
}
curr = curr.next;
}
return curr;
}
//删除节点
public Node delete(long value) {
Node curr = first;
Node prev = first;
while(curr.data!=value) {
if(curr.next==null) {
return null;
}
prev = curr; //之前的要指向当前的链接点
curr = curr.next;//当前的链接点要指向下一个
if(curr==first) //判断删除节点是否为首节点
{
first = first.next;
}
else {
prev.next = curr.next; //删除当前的节点prev(prev.next)》curr(curr.next)》node
}
}
return curr;
}
}
3.测试代码
package List;
public class TestLinklist {
public static void main(String[] args) {
Linklist l1 = new Linklist();
l1.insertfirst(25);
l1.insertfirst(36);
l1.insertfirst(18);
l1.insertfirst(43);
l1.display1();
l1.removefirst();
l1.display1();
//查找某个值
Node t1 = l1.find(36);
t1.display();
System.out.println();
//删除某个值
Node t2 = l1.delete(36);
t2.display();
System.out.println();
l1.display1();
}
}
4.写在一起便于阅读
这里构建水浒传里面的英雄,参数列表:排名,名字,昵称
通过创建节点类属性来管理节点,创建链表属性来构建链表
package List;
public class singlelinklist {
public static void main(String[] args) {
HeroNode hero1 = new HeroNode(1,"宋江","及时雨");
HeroNode hero2 = new HeroNode(2,"卢俊义","玉麒麟");
HeroNode hero3 = new HeroNode(3,"吴用","智多星");
HeroNode hero4 = new HeroNode(4,"林冲","豹子头");
HeroNode hero5 = new HeroNode(5,"史进","九纹龙");
//创建单链表
Singlelist st =new Singlelist();
st.add(hero1); //添加节点数据
st.add(hero2);
st.add(hero3);
st.add(hero4);
st.add(hero5);
st.show(); //显示数据
}
}
//创建单链表属性
class Singlelist{
//初始化一个头节点,好在后部添加数据
HeroNode head = new HeroNode(0,"","");
//添加节点方法
public void add(HeroNode hero) {
//要找到链尾,向其添加数据,然后将其next指向下一个节点
HeroNode temp = head; //指向了head
while(true) {
//找到链表的最后
if(temp.next==null) {
break;//找到了最后节点结束
}
temp = temp.next; //指针后移,继续查找
}//退出循环就指向了最后节点,将该节点指向新节点
temp.next = hero; //添加进去
}
public void show() {
if(head.next==null) {
System.out.println("无节点数据");
return;//找到了最后节点结束
}
HeroNode temp = head.next; //指向了head
while(true) {
if(temp ==null) {
break;
}
System.out.println(temp); //打印当前节点
temp = temp.next; //指针后移,继续遍历
}//退出循环就指向了最后节点,将该节点指向新节点
}
}
//创建节点属性
class HeroNode {
public int num; //编号
public String name; //名字
private String pname; //昵称
public HeroNode next;//指向下一节点
//构造方法
public HeroNode(int numb,String nameb,String pnameb ) {
this.num = numb;
this.name = nameb;
this.pname= pnameb;
}
//重写toString方法,方便输出信息
@Override
public String toString() {
return "HeroNode [num=" + num + ", name=" + name + ", pname=" + pname + "]";
}
}
测试结果:
4.2按排名的方式进行节点插入
重写添加方法与新插入的节点进行序号比较,按排序顺序进行插入,思路如下:
方法重写如下:
//根据num编号排名进行添加到节点
public void add2(HeroNode hero) {
boolean flag = false;//定义排名大小标记,默认新加的节点大
HeroNode temp = head; //指向了head节点
while(true){
if(temp.next==null) {break;}//已经在链表的最后,还要进行序号判断
//下面进行序号判断
if(temp.next.num>hero.num) {
break;//找到插入的位置,在temp与temp.next之间插入
}
else if(temp.next.num==hero.num) {
flag = true;
break;
}
temp =temp.next;//指针后移,进行遍历
}
if(flag) { System.out.println("此号码已插入过: num="+hero.num);}
//下面进行插入操作,插在temp与temp.next之间
else { hero.next =temp.next; //新节点指向上一个节点
temp.next =hero; //temp的指向由新节点
}
}
根据编号匹配进行信息修改:
//根据编号进行数据更新,编号是一定的
public void update(HeroNode newhero) {
if(head.next==null) {System.out.println("链表为空");
return;} //判断是否为空,为空不用更新数据
boolean flag = false; //匹配的标记
HeroNode temp = head.next;
while(true) {
if(temp==null) {
break; //已经遍历完
}if(newhero.num ==temp.num) {
flag = true;//找到修改的地方
break;
}
temp= temp.next; //继续遍历搜索
}
if(flag) {
newhero.name = temp.name;
newhero.pname = temp.pname;
}else {System.out.println("无修改信息");}
}
删除节点:依据编号相同进行删除
//删除节点
public void delete(int num) {
boolean flag = false; //匹配的标记
HeroNode temp = head;
while(true) {
if(temp.next==null) {
break; //已经遍历完
}if(temp.next.num ==num) {
flag = true;//找到修改的地方
break;
}
temp= temp.next; //继续遍历搜索
}
if(flag) {
temp.next =temp.next.next;//跳过需要删除的节点
}else {System.out.println("无修改信息");}
}
统计节点的有效个数,不包括头结点:传入参数为头节点
//统计节点的有效个数,不包含头节点
public static int getLength(HeroNode head) {
//判断为不为空
if( head.next==null) {return 0;}
int length = 0;//标记个数
HeroNode temp = head.next; //指向头结点的下一个节点
while(temp!=null) {
length++;
temp = temp.next; //向下进行遍历
}
return length;
}
找出链表倒数第k个节点,思路:先统计链表有效个数,然后匹配倒数第k个
传入参数为头结点和k
//查找单链表的倒数第K个节点,先统计有效个数,然后查找第K个
public static void search(HeroNode head,int k) {
//判断为不为空
if( head.next==null) {
System.out.println("链表无节点");
return;}
int length = 0;//标记有效个数
int count = 0;//标记查找个数
HeroNode temp = head.next;
HeroNode cur = head.next;
while(temp!=null) {
length++;
temp = temp.next; //向下进行遍历
}//退出循环后找到有效节点数length
if(k<=length) { //不能超过边界
while(cur!=null) {
count++;
if(count==length+1-k) {
System.out.println(cur);
break;
}//找到倒数第k个
cur = cur.next; //向下进行遍历
}
}else {System.out.println("输入超过了,有效数据为:"+length);}
}
//统计节点的有效个数,不包含头节点
public static int getLength(HeroNode head) {
//判断为不为空
if( head.next==null) {return 0;}
int length = 0;//标记个数
HeroNode temp = head.next;
while(temp!=null) {
length++;
temp = temp.next; //向下进行遍历
}
return length;
}
将单链表进行反转,(百度题)
思路:重新连接一条链,首先创建一个新节 点reverseHead = new HeroNode();
从头开始遍历原来的链表,每遍历一个节点,将其取出,放入新节点的链路
即变为:head.next = reverseHead.next;每次添加后都将后面的节点放在前面了
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200515170418616.png
//反转链表,改变原有的结构,如下所示
//统计节点的有效个数,不包含头节点
public static void reverse(HeroNode head) {
//判断为不为空
if( head.next==null||head.next.next==null) {return ;}
HeroNode newNode = new HeroNode(0,"","");//创建新链表的链头
HeroNode cur = head.next; // 指向head的下一个节点
HeroNode temp = null;
while(cur!=null) {
temp= cur.next ; //保留当前节点的下一节点,便于下次的遍历
cur.next = newNode.next; //转向新链路,建立头节点与下一节点连接
newNode.next = cur; //将它的地址用cur来替代,取出cur
cur =temp; //往下进行遍历
}
head.next = newNode.next;//将链头节点加入
}
逆序打印链表
这里采用栈的方式进行,首先给出栈的应用示例:
//逆序打印,通过栈来实现
public static void showresvest(HeroNode head) {
if(head.next==null) {System.out.println("空链表");}
Stack<HeroNode> st = new Stack();
HeroNode temp = head.next;
while(temp!=null) {
st.push(temp); //进栈,add也可以
temp = temp.next;
}
//出栈
while(st.size()>0) {
System.out.println(st.pop());
}
}
所有整合的代码
package List;
import java.util.Stack;
public class singlelinklist {
public static void main(String[] args) {
/*
* HeroNode hero1 = new HeroNode(1,"宋江","及时雨"); HeroNode hero2 = new
* HeroNode(2,"卢俊义","玉麒麟"); HeroNode hero3 = new HeroNode(3,"吴用","智多星");
* HeroNode hero4 = new HeroNode(4,"林冲","豹子头"); HeroNode hero5 = new
* HeroNode(5,"史进","九纹龙"); //创建单链表 Singlelist st =new Singlelist();
* st.add(hero1); //添加节点数据 st.add(hero2); st.add(hero3); st.add(hero4);
* st.add(hero5); st.show(); //显示数据
*/
HeroNode hero1 = new HeroNode(1,"宋江","及时雨");
HeroNode hero2 = new HeroNode(2,"卢俊义","玉麒麟");
HeroNode hero3 = new HeroNode(3,"吴用","智多星");
HeroNode hero4 = new HeroNode(4,"林冲","豹子头");
HeroNode hero5 = new HeroNode(5,"史进","九纹龙");
//创建单链表
Singlelist st =new Singlelist();
st.add2(hero4); //添加节点数据
st.add2(hero1);
st.add2(hero3);
st.add2(hero5);
st.add2(hero2);
st.add2(hero5);
st.show(); //显示数据
//显示有效个数,将头结点传进去
System.out.println(getLength(st.getHead()));
//查找倒数第k个节点
search(st.getHead(),2);
//反转链表结构
System.out.println("反转链表");
reverse(st.getHead());
st.show(); //显示数据
//逆序输出
showresvest(st.getHead());
}
//查找单链表的倒数第K个节点,先统计有效个数,然后查找第K个
public static void search(HeroNode head,int k) {
//判断为不为空
if( head.next==null) {
System.out.println("链表无节点");
return;}
int length = 0;//标记有效个数
int count = 0;//标记查找个数
HeroNode temp = head.next;
HeroNode cur = head.next;
while(temp!=null) {
length++;
temp = temp.next; //向下进行遍历
}//退出循环后找到有效节点数length
if(k<=length) { //不能超过边界
while(cur!=null) {
count++;
if(count==length+1-k) {
System.out.println(cur);
break;
}//找到倒数第k个
cur = cur.next; //向下进行遍历
}
}else {System.out.println("输入超过了,有效数据为:"+length);}
}
//统计节点的有效个数,不包含头节点
public static int getLength(HeroNode head) {
//判断为不为空
if( head.next==null) {return 0;}
int length = 0;//标记个数
HeroNode temp = head.next;
while(temp!=null) {
length++;
temp = temp.next; //向下进行遍历
}
return length;
}
//反转链表,改变结构如下所示
//统计节点的有效个数,不包含头节点
public static void reverse(HeroNode head) {
//判断为不为空
if( head.next==null||head.next.next==null) {return ;}
//创建新链表的链头
HeroNode newNode = new HeroNode(0,"","");
HeroNode cur = head.next; // 指向head的下一个节点
HeroNode temp = null;
while(cur!=null) {
temp= cur.next ; //保留当前节点的下一节点,便于下次的遍历
cur.next = newNode.next; //转向新链路,建立头节点与下一节点连接
newNode.next = cur; //将它的地址用cur来替代,取出cur
cur =temp; //往下进行遍历
}
head.next = newNode.next;//将链头节点加入
}
//逆序打印,通过栈来实现
public static void showresvest(HeroNode head) {
if(head.next==null) {System.out.println("空链表");}
Stack<HeroNode> st = new Stack();
HeroNode temp = head.next;
while(temp!=null) {
st.add(temp); //进栈
temp = temp.next;
}
//出栈
while(st.size()>0) {
System.out.println(st.pop());
}
}
}
//创建单链表属性
class Singlelist{
//初始化一个头节点,好在后部添加数据
HeroNode head = new HeroNode(0,"","");
//返回头结点
public HeroNode getHead() {
return head;
}
//单节点进行,添加节点方法
public void add(HeroNode hero) {
//要找到链尾,向其添加数据,然后将其next指向下一个节点
HeroNode temp = head; //指向了head
while(true) {
//找到链表的最后
if(temp.next==null) {
break;//找到了最后节点结束
}
temp = temp.next; //指针后移,继续查找
}//退出循环就指向了最后节点,将该节点指向新节点
temp.next = hero; //添加进去
}
//根据num编号排名进行添加到节点
public void add2(HeroNode hero) {
boolean flag = false;//定义排名大小标记,默认新加的节点大
HeroNode temp = head; //指向了head
while(true){
if(temp.next==null) {break;}//已经在表的最后
if(temp.next.num>hero.num) {
break;//找到插入的位置,在temp与temp.next之间插入
}
else if(temp.next.num==hero.num) {
flag = true;
break;
}
temp =temp.next;//指针后移,进行遍历
}
if(flag) { System.out.println("此号码已插入过: num="+hero.num);}
//下面进行插入操作,插在temp与temp.next之间
else { hero.next =temp.next; //新节点指向上一个节点
temp.next =hero; //temp的指向由新节点
}
}
//根据编号进行数据更新,编号是一定的
public void update(HeroNode newhero) {
if(head.next==null) {System.out.println("链表为空");
return;} //判断是否为空,为空不用更新数据
boolean flag = false; //匹配的标记
HeroNode temp = head.next; //表示下一位数据
while(true) {
if(temp==null) {
break; //已经遍历完
}if(newhero.num ==temp.num) {
flag = true;//找到修改的地方
break;
}
temp= temp.next; //继续遍历搜索
}
if(flag) {
newhero.name = temp.name;
newhero.pname = temp.pname;
}else {System.out.println("无修改信息");}
}
//删除节点
public void delete(int num) {
boolean flag = false; //匹配的标记
HeroNode temp = head;
while(true) {
if(temp.next==null) {
break; //已经遍历完
}if(temp.next.num ==num) {
flag = true;//找到修改的地方
break;
}
temp= temp.next; //继续遍历搜索
}
if(flag) {
temp.next =temp.next.next;//跳过需要删除的节点
}else {System.out.println("无修改信息");}
}
public void show() {
if(head.next==null) {
System.out.println("无节点数据");
return;//找到了最后节点结束
}
HeroNode temp = head.next; //指向了head
while(true) {
if(temp ==null) {
break;
}
System.out.println(temp); //打印当前节点
temp = temp.next; //指针后移,继续遍历
}//退出循环就指向了最后节点,将该节点指向新节点
}
}
//创建节点属性
class HeroNode {
public int num; //编号
public String name; //名字
public String pname; //昵称
public HeroNode next;//指向下一节点
//构造方法
public HeroNode(int numb,String nameb,String pnameb ) {
this.num = numb;
this.name = nameb;
this.pname= pnameb;
}
//重写toString方法,方便输出信息
@Override
public String toString() {
return "HeroNode [num=" + num + ", name=" + name + ", pname=" + pname + "]";
}
}