目录
单链表介绍和内存布局
链表是有序的列表,它在内存中存储结构如下:
下图是带头结点的链表
简单的描述一下:
头指针head 指向地址150的data域a1,a1的next域指向110的地址的data域a2,,依次类推。
从上图我们可以得到如下信息:
- 链表是以节点的方式来存储,是链式存储。
- 每个节点包含data域,next域:指向下一个节点。
- 如上图:发现链表的各个节点不一定是连续存储。
- 链表分带头节点的链表和没有头节点的链表,根据实际的需求来确定。
单链表(带头结点)逻辑结构示意图如下:
单链表的应用实例
使用带 head头的单向链表实现–水浒英雄排行榜管理完成对英雄人物的增删改查操作。
单链表的创建和和遍历分析
单链表的创建和和遍历代码
package LinkList;
/**
* 单链表
*/
public class SingleLinkListTest {
public static void main(String[] args) {
SingleLinkList singleLinkList = new SingleLinkList();
HeroNode heroNode1 = new HeroNode(1,"宋江","及时雨");
HeroNode heroNode2 = new HeroNode(2,"卢俊义","玉麒麟");
HeroNode heroNode3 = new HeroNode(3,"鲁智深","花和尚");
singleLinkList.insert(heroNode1);
singleLinkList.insert(heroNode2);
singleLinkList.insert(heroNode3);
singleLinkList.show();
}
}
/**
* 定义SingleLinkList管理 管理节点
*/
class SingleLinkList{
/**
* 初始化一个头结点,不存放具体的数据。
*/
private HeroNode head = new HeroNode(0,"","");
/**
* 添加结点
*
* 不考虑当前编号,找到当前链表的最后一个节点,最后一个节点为NULL。
* 将最后这个节点的next 指向新的节点。
*/
public void insert(HeroNode heroNode){
//因为头结点不动,我们需要一个辅助遍历
HeroNode temp = head;
//遍历链表
while (true){
//当temp的next==null 则找到了最后一个节点。
if (temp.next == null){
break;
}
//若没有找到,就将temp后移下一个节点
temp = temp.next;
}
//退出循环时,temp指向了链表的最后,就可以将这个节点的next,指向新的节点。
temp.next = heroNode;
}
/**
* 遍历链表
*/
public void show(){
//通过一辅助遍历 遍历整个链表。
//判断链表是否为空
if (isEmpty()){
System.out.println("链表当前没有元素");
return;
}
HeroNode temp = head.next;
while (true){
// 是否到了最后一个节点
if (temp == null){
break;
}
//输出节点信息
System.out.println(temp);
//将next后移
temp = temp.next;
}
}
/**
* 链表是否为空
* @return
*/
public boolean isEmpty(){
return head.next == null;
}
}
/**
* 定义HeroNode 每个HeroNode 对象就是一个节点
*/
class HeroNode{
/**
* 编号
*/
public int no;
/**
* 名字
*/
public String name;
/**
* 昵称
*/
public String nickName;
/**
* 指向下一个节点
*/
public HeroNode next;
/**
* 构造器
* @param no 编号
* @param name 名字
* @param nickName 昵称
*/
public HeroNode(int no,String name,String nickName){
this.no = no;
this.name = name;
this.nickName = nickName;
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
", nickName='" + nickName + '\'' +
'}';
}
}
输出结果
目前insert插入没有考虑编号,怎么根据no排序了?
单链表按顺序插入节点
添加结点的时候,根据排名将结点插入到指定的位置(如果这个位置有人,则添加失败,并提示。)
代码实现
package LinkList;
import java.awt.image.BufferStrategy;
import java.beans.beancontext.BeanContext;
/**
* 单链表
*/
public class SingleLinkListTest {
public static void main(String[] args) {
SingleLinkList singleLinkList = new SingleLinkList();
HeroNode heroNode1 = new HeroNode(1,"宋江","及时雨");
HeroNode heroNode2 = new HeroNode(6,"卢俊义","玉麒麟");
HeroNode heroNode3 = new HeroNode(5,"鲁智深","花和尚");
HeroNode heroNode4 = new HeroNode(4,"杨志","青面兽");
HeroNode heroNode5 = new HeroNode(2,"吴用","智多星");
/* singleLinkList.insert(heroNode1);
singleLinkList.insert(heroNode2);
singleLinkList.insert(heroNode3);*/
singleLinkList.insertByOrder(heroNode1);
singleLinkList.insertByOrder(heroNode2);
singleLinkList.insertByOrder(heroNode3);
singleLinkList.insertByOrder(heroNode4);
singleLinkList.insertByOrder(heroNode5);
singleLinkList.show();
}
}
/**
* 定义SingleLinkList管理 管理节点
*/
class SingleLinkList{
/**
* 初始化一个头结点,不存放具体的数据。
*/
private HeroNode head = new HeroNode(0,"","");
/**
* 添加结点
*
* 不考虑当前编号,找到当前链表的最后一个节点,最后一个节点为NULL。
* 将最后这个节点的next 指向新的节点。
*/
public void insert(HeroNode heroNode){
//因为头结点不动,我们需要一个辅助遍历
HeroNode temp = head;
//遍历链表
while (true){
//当temp的next==null 则找到了最后一个节点。
if (temp.next == null){
break;
}
//若没有找到,就将temp后移下一个节点
temp = temp.next;
}
//退出循环时,temp指向了链表的最后,就可以将这个节点的next,指向新的节点。
temp.next = heroNode;
}
/**
* 按照no大小按升序序插入节点
* @param heroNode
*/
public void insertByOrder(HeroNode heroNode){
//因为头结点不动,需要借助一个辅助,来帮助找到合适添加位置
//单链表,temp是位于添加位置的前一个结点,否则插入失败, 因为我们可以根据上一个结点找到下一个节点位置,但是不能根据下一个节点找到上一个结点位置。
HeroNode temp = head;
// 添加no是否存在,默认为false
boolean flag = false;
while (true){
// 找到链表结尾
if (temp.next == null){
break;
}
// 找到插入位置,就在temp的后面
if (temp.next.no > heroNode.no){
break;
}else if (temp.next.no == heroNode.no){ //要添加的no已经存在
flag = true; //说明编号存在
break;
}
temp = temp.next;
}
if (flag){
throw new RuntimeException("待插入的编号:"+ heroNode.no + ",已经存在,插入失败。");
}else {
//将结点插入到链表,temp的后面
heroNode.next = temp.next;
temp.next = heroNode;
}
}
/**
* 遍历链表
*/
public void show(){
//通过一辅助遍历 遍历整个链表。
//判断链表是否为空
if (isEmpty()){
System.out.println("链表当前没有元素");
return;
}
HeroNode temp = head.next;
while (true){
// 是否到了最后一个节点
if (temp == null){
break;
}
//输出节点信息
System.out.println(temp);
//将next后移
temp = temp.next;
}
}
/**
* 链表是否为空
* @return
*/
public boolean isEmpty(){
return head.next == null;
}
}
/**
* 定义HeroNode 每个HeroNode 对象就是一个节点
*/
class HeroNode{
/**
* 编号
*/
public int no;
/**
* 名字
*/
public String name;
/**
* 昵称
*/
public String nickName;
/**
* 指向下一个节点
*/
public HeroNode next;
/**
* 构造器
* @param no 编号
* @param name 名字
* @param nickName 昵称
*/
public HeroNode(int no,String name,String nickName){
this.no = no;
this.name = name;
this.nickName = nickName;
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
", nickName='" + nickName + '\'' +
'}';
}
}
输出结果
单链表结点的修改
修改结点的数据信息根据编号no来修改。
package LinkList;
import java.awt.image.BufferStrategy;
import java.beans.beancontext.BeanContext;
/**
* 单链表
*/
public class SingleLinkListTest {
public static void main(String[] args) {
SingleLinkList singleLinkList = new SingleLinkList();
HeroNode heroNode1 = new HeroNode(1,"宋江","及时雨");
HeroNode heroNode2 = new HeroNode(6,"卢俊义","玉麒麟");
HeroNode heroNode3 = new HeroNode(5,"鲁智深","花和尚");
HeroNode heroNode4 = new HeroNode(4,"杨志","青面兽");
HeroNode heroNode5 = new HeroNode(2,"吴用","智多星");
/* singleLinkList.insert(heroNode1);
singleLinkList.insert(heroNode2);
singleLinkList.insert(heroNode3);*/
//测试按照编号升序插入
singleLinkList.insertByOrder(heroNode1);
singleLinkList.insertByOrder(heroNode2);
singleLinkList.insertByOrder(heroNode3);
singleLinkList.insertByOrder(heroNode4);
singleLinkList.insertByOrder(heroNode5);
//测试修改
HeroNode heroNode6 = new HeroNode(2,"吴用","大笨蛋");
singleLinkList.update(heroNode6);
singleLinkList.show();
}
}
/**
* 定义SingleLinkList管理 管理节点
*/
class SingleLinkList{
/**
* 初始化一个头结点,不存放具体的数据。
*/
private HeroNode head = new HeroNode(0,"","");
/**
* 添加结点
*
* 不考虑当前编号,找到当前链表的最后一个节点,最后一个节点为NULL。
* 将最后这个节点的next 指向新的节点。
*/
public void insert(HeroNode heroNode){
//因为头结点不动,我们需要一个辅助遍历
HeroNode temp = head;
//遍历链表
while (true){
//当temp的next==null 则找到了最后一个节点。
if (temp.next == null){
break;
}
//若没有找到,就将temp后移下一个节点
temp = temp.next;
}
//退出循环时,temp指向了链表的最后,就可以将这个节点的next,指向新的节点。
temp.next = heroNode;
}
/**
* 按照no大小按升序序插入节点
* @param heroNode
*/
public void insertByOrder(HeroNode heroNode){
//因为头结点不动,需要借助一个辅助,来帮助找到合适添加位置
//单链表,temp是位于添加位置的前一个结点,否则插入失败, 因为我们可以根据上一个结点找到下一个节点位置,但是不能根据下一个节点找到上一个结点位置。
HeroNode temp = head;
// 添加no是否存在,默认为false
boolean flag = false;
while (true){
// 找到链表结尾
if (temp.next == null){
break;
}
// 找到插入位置,就在temp的后面
if (temp.next.no > heroNode.no){
break;
}else if (temp.next.no == heroNode.no){ //要添加的no已经存在
flag = true; //说明编号存在
break;
}
temp = temp.next;
}
if (flag){
throw new RuntimeException("待插入的编号:"+ heroNode.no + ",已经存在,插入失败。");
}else {
//将结点插入到链表,temp的后面
heroNode.next = temp.next;
temp.next = heroNode;
}
}
/**
* 根据结点的编号no来修改结点data信息
* @param newHeroNode
*/
public void update(HeroNode newHeroNode){
if (isEmpty()){
throw new RuntimeException("当前链表为空");
}
//找到需要修改修改的结点
HeroNode temp = head.next;
// 表示是否找到该结点
boolean flag = false;
while (true){
if (temp == null){ //找到了链表最后一个节点,遍历完该链表了。
break;
}
// 找到该结点
if (temp.no == newHeroNode.no){
flag = true;
break;
}
temp = temp.next;
}
//flag为true找到该结点,修改结点
if (flag){
temp.name = newHeroNode.name;
temp.nickName = newHeroNode.nickName;
}else {
throw new RuntimeException("当前链表没有结点no = "+ newHeroNode.no);
}
}
/**
* 遍历链表
*/
public void show(){
//通过一辅助遍历 遍历整个链表。
//判断链表是否为空
if (isEmpty()){
System.out.println("链表当前没有元素");
return;
}
HeroNode temp = head.next;
while (true){
// 是否到了最后一个节点
if (temp == null){
break;
}
//输出节点信息
System.out.println(temp);
//将next后移
temp = temp.next;
}
}
/**
* 链表是否为空
* @return
*/
public boolean isEmpty(){
return head.next == null;
}
}
/**
* 定义HeroNode 每个HeroNode 对象就是一个节点
*/
class HeroNode{
/**
* 编号
*/
public int no;
/**
* 名字
*/
public String name;
/**
* 昵称
*/
public String nickName;
/**
* 指向下一个节点
*/
public HeroNode next;
/**
* 构造器
* @param no 编号
* @param name 名字
* @param nickName 昵称
*/
public HeroNode(int no,String name,String nickName){
this.no = no;
this.name = name;
this.nickName = nickName;
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
", nickName='" + nickName + '\'' +
'}';
}
}
输出结果
删除结点
删除结点的操作其实和修改操作比较类似。
package LinkList;
import java.awt.image.BufferStrategy;
import java.beans.beancontext.BeanContext;
/**
* 单链表
*/
public class SingleLinkListTest {
public static void main(String[] args) {
SingleLinkList singleLinkList = new SingleLinkList();
HeroNode heroNode1 = new HeroNode(1,"宋江","及时雨");
HeroNode heroNode2 = new HeroNode(6,"卢俊义","玉麒麟");
HeroNode heroNode3 = new HeroNode(5,"鲁智深","花和尚");
HeroNode heroNode4 = new HeroNode(4,"杨志","青面兽");
HeroNode heroNode5 = new HeroNode(2,"吴用","智多星");
/* singleLinkList.insert(heroNode1);
singleLinkList.insert(heroNode2);
singleLinkList.insert(heroNode3);*/
//测试按照编号升序插入
singleLinkList.insertByOrder(heroNode1);
singleLinkList.insertByOrder(heroNode2);
singleLinkList.insertByOrder(heroNode3);
singleLinkList.insertByOrder(heroNode4);
singleLinkList.insertByOrder(heroNode5);
//测试修改
HeroNode heroNode6 = new HeroNode(2,"吴用","大笨蛋");
singleLinkList.update(heroNode6);
singleLinkList.delete(2);
singleLinkList.show();
}
}
/**
* 定义SingleLinkList管理 管理节点
*/
class SingleLinkList{
/**
* 初始化一个头结点,不存放具体的数据。
*/
private HeroNode head = new HeroNode(0,"","");
/**
* 添加结点
*
* 不考虑当前编号,找到当前链表的最后一个节点,最后一个节点为NULL。
* 将最后这个节点的next 指向新的节点。
*/
public void insert(HeroNode heroNode){
//因为头结点不动,我们需要一个辅助遍历
HeroNode temp = head;
//遍历链表
while (true){
//当temp的next==null 则找到了最后一个节点。
if (temp.next == null){
break;
}
//若没有找到,就将temp后移下一个节点
temp = temp.next;
}
//退出循环时,temp指向了链表的最后,就可以将这个节点的next,指向新的节点。
temp.next = heroNode;
}
/**
* 按照no大小按升序序插入节点
* @param heroNode
*/
public void insertByOrder(HeroNode heroNode){
//因为头结点不动,需要借助一个辅助,来帮助找到合适添加位置
//单链表,temp是位于添加位置的前一个结点,否则插入失败, 因为我们可以根据上一个结点找到下一个节点位置,但是不能根据下一个节点找到上一个结点位置。
HeroNode temp = head;
// 添加no是否存在,默认为false
boolean flag = false;
while (true){
// 找到链表结尾
if (temp.next == null){
break;
}
// 找到插入位置,就在temp的后面
if (temp.next.no > heroNode.no){
break;
}else if (temp.next.no == heroNode.no){ //要添加的no已经存在
flag = true; //说明编号存在
break;
}
temp = temp.next;
}
if (flag){
throw new RuntimeException("待插入的编号:"+ heroNode.no + ",已经存在,插入失败。");
}else {
//将结点插入到链表,temp的后面
heroNode.next = temp.next;
temp.next = heroNode;
}
}
/**
* 根据结点的编号no来修改结点data信息
* @param newHeroNode
*/
public void update(HeroNode newHeroNode){
if (isEmpty()){
throw new RuntimeException("当前链表为空");
}
//找到需要修改修改的结点
HeroNode temp = head.next;
// 表示是否找到该结点
boolean flag = false;
while (true){
if (temp == null){ //找到了链表最后一个节点,遍历完该链表了。
break;
}
// 找到该结点
if (temp.no == newHeroNode.no){
flag = true;
break;
}
temp = temp.next;
}
//flag为true找到该结点,修改结点
if (flag){
temp.name = newHeroNode.name;
temp.nickName = newHeroNode.nickName;
}else {
throw new RuntimeException("当前链表没有结点no = "+ newHeroNode.no);
}
}
/**
* 删除结点
* 比较的时候,是temp.next.no 和需要删除结点的no
* @param no 待删除结点no
*/
public void delete(int no){
if (isEmpty()){
throw new RuntimeException("当前链表为空");
}
HeroNode temp = head;
boolean flag = false;
while (true){
//找到了结点最后位置,依旧没有找到该元素
if (temp.next == null){
break;
}
//找到待删除结点的前一个结点temp
if (temp.next.no == no){
flag = true;
break;
}
temp = temp.next;
}
if (flag){
System.out.println("成功删除结点:"+ temp.next);
temp.next = temp.next.next;
}
}
/**
* 遍历链表
*/
public void show(){
//通过一辅助遍历 遍历整个链表。
//判断链表是否为空
if (isEmpty()){
System.out.println("链表当前没有元素");
return;
}
HeroNode temp = head.next;
while (true){
// 是否到了最后一个节点
if (temp == null){
break;
}
//输出节点信息
System.out.println(temp);
//将next后移
temp = temp.next;
}
}
/**
* 链表是否为空
* @return
*/
public boolean isEmpty(){
return head.next == null;
}
}
/**
* 定义HeroNode 每个HeroNode 对象就是一个节点
*/
class HeroNode{
/**
* 编号
*/
public int no;
/**
* 名字
*/
public String name;
/**
* 昵称
*/
public String nickName;
/**
* 指向下一个节点
*/
public HeroNode next;
/**
* 构造器
* @param no 编号
* @param name 名字
* @param nickName 昵称
*/
public HeroNode(int no,String name,String nickName){
this.no = no;
this.name = name;
this.nickName = nickName;
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
", nickName='" + nickName + '\'' +
'}';
}
}
经典面试题
求单链表的结点个数
package LinkList;
import java.awt.image.BufferStrategy;
import java.beans.beancontext.BeanContext;
/**
* 单链表
*/
public class SingleLinkListTest {
public static void main(String[] args) {
SingleLinkList singleLinkList = new SingleLinkList();
HeroNode heroNode1 = new HeroNode(1,"宋江","及时雨");
HeroNode heroNode2 = new HeroNode(6,"卢俊义","玉麒麟");
HeroNode heroNode3 = new HeroNode(5,"鲁智深","花和尚");
HeroNode heroNode4 = new HeroNode(4,"杨志","青面兽");
HeroNode heroNode5 = new HeroNode(2,"吴用","智多星");
/* singleLinkList.insert(heroNode1);
singleLinkList.insert(heroNode2);
singleLinkList.insert(heroNode3);*/
//测试按照编号升序插入
singleLinkList.insertByOrder(heroNode1);
singleLinkList.insertByOrder(heroNode2);
singleLinkList.insertByOrder(heroNode3);
singleLinkList.insertByOrder(heroNode4);
singleLinkList.insertByOrder(heroNode5);
//测试修改
HeroNode heroNode6 = new HeroNode(2,"吴用","大笨蛋");
singleLinkList.update(heroNode6);
singleLinkList.delete(2);
singleLinkList.show();
System.out.println("有效元素个数:" + singleLinkList.listLength(singleLinkList.getHead()));
}
}
/**
* 定义SingleLinkList管理 管理节点
*/
class SingleLinkList{
/**
* 初始化一个头结点,不存放具体的数据。
*/
private HeroNode head = new HeroNode(0,"","");
/**
*
* @return 头结点
*/
public HeroNode getHead() {
return head;
}
/**
* 添加结点
*
* 不考虑当前编号,找到当前链表的最后一个节点,最后一个节点为NULL。
* 将最后这个节点的next 指向新的节点。
*/
public void insert(HeroNode heroNode){
//因为头结点不动,我们需要一个辅助遍历
HeroNode temp = head;
//遍历链表
while (true){
//当temp的next==null 则找到了最后一个节点。
if (temp.next == null){
break;
}
//若没有找到,就将temp后移下一个节点
temp = temp.next;
}
//退出循环时,temp指向了链表的最后,就可以将这个节点的next,指向新的节点。
temp.next = heroNode;
}
/**
* 按照no大小按升序序插入节点
* @param heroNode
*/
public void insertByOrder(HeroNode heroNode){
//因为头结点不动,需要借助一个辅助,来帮助找到合适添加位置
//单链表,temp是位于添加位置的前一个结点,否则插入失败, 因为我们可以根据上一个结点找到下一个节点位置,但是不能根据下一个节点找到上一个结点位置。
HeroNode temp = head;
// 添加no是否存在,默认为false
boolean flag = false;
while (true){
// 找到链表结尾
if (temp.next == null){
break;
}
// 找到插入位置,就在temp的后面
if (temp.next.no > heroNode.no){
break;
}else if (temp.next.no == heroNode.no){ //要添加的no已经存在
flag = true; //说明编号存在
break;
}
temp = temp.next;
}
if (flag){
throw new RuntimeException("待插入的编号:"+ heroNode.no + ",已经存在,插入失败。");
}else {
//将结点插入到链表,temp的后面
heroNode.next = temp.next;
temp.next = heroNode;
}
}
/**
* 根据结点的编号no来修改结点data信息
* @param newHeroNode
*/
public void update(HeroNode newHeroNode){
if (isEmpty()){
throw new RuntimeException("当前链表为空");
}
//找到需要修改修改的结点
HeroNode temp = head.next;
// 表示是否找到该结点
boolean flag = false;
while (true){
if (temp == null){ //找到了链表最后一个节点,遍历完该链表了。
break;
}
// 找到该结点
if (temp.no == newHeroNode.no){
flag = true;
break;
}
temp = temp.next;
}
//flag为true找到该结点,修改结点
if (flag){
temp.name = newHeroNode.name;
temp.nickName = newHeroNode.nickName;
}else {
throw new RuntimeException("当前链表没有结点no = "+ newHeroNode.no);
}
}
/**
* 删除结点
* 比较的时候,是temp.next.no 和需要删除结点的no
* @param no 待删除结点no
*/
public void delete(int no){
if (isEmpty()){
throw new RuntimeException("当前链表为空");
}
HeroNode temp = head;
boolean flag = false;
while (true){
//找到了结点最后位置,依旧没有找到该元素
if (temp.next == null){
break;
}
//找到待删除结点的前一个结点temp
if (temp.next.no == no){
flag = true;
break;
}
temp = temp.next;
}
if (flag){
System.out.println("成功删除结点:"+ temp.next);
temp.next = temp.next.next;
}
}
/**
* 获取到链表结点的个数(如果是带头结点的链表,不统计头结点)
* @param head 链表的头结点
* @return
*/
public int listLength(HeroNode head){
//空链表 返回0
if (head.next == null){
return 0;
}
int length = 0;
//定义一个辅助变量,不统计头结点
HeroNode cur = head.next;
while (cur != null){
length++;
cur = cur.next;//遍历,指向下一个节点。
}
return length;
}
/**
* 遍历链表
*/
public void show(){
//通过一辅助遍历 遍历整个链表。
//判断链表是否为空
if (isEmpty()){
System.out.println("链表当前没有元素");
return;
}
HeroNode temp = head.next;
while (true){
// 是否到了最后一个节点
if (temp == null){
break;
}
//输出节点信息
System.out.println(temp);
//将next后移
temp = temp.next;
}
}
/**
* 链表是否为空
* @return
*/
public boolean isEmpty(){
return head.next == null;
}
}
/**
* 定义HeroNode 每个HeroNode 对象就是一个节点
*/
class HeroNode{
/**
* 编号
*/
public int no;
/**
* 名字
*/
public String name;
/**
* 昵称
*/
public String nickName;
/**
* 指向下一个节点
*/
public HeroNode next;
/**
* 构造器
* @param no 编号
* @param name 名字
* @param nickName 昵称
*/
public HeroNode(int no,String name,String nickName){
this.no = no;
this.name = name;
this.nickName = nickName;
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
", nickName='" + nickName + '\'' +
'}';
}
}
查找单链表中倒数第K个结点
思路分析
- 编写一个方法,接收head头结点,一个location位置。
- location表示是倒数第index个结点。
- 先把链表从头到尾遍历,获取到链表的总长度。
- 得到总长度后,从链表的第一个开始遍历(size-index)个。
package LinkList;
import java.awt.image.BufferStrategy;
import java.beans.beancontext.BeanContext;
/**
* 单链表
*/
public class SingleLinkListTest {
public static void main(String[] args) {
SingleLinkList singleLinkList = new SingleLinkList();
HeroNode heroNode1 = new HeroNode(1,"宋江","及时雨");
HeroNode heroNode2 = new HeroNode(6,"卢俊义","玉麒麟");
HeroNode heroNode3 = new HeroNode(5,"鲁智深","花和尚");
HeroNode heroNode4 = new HeroNode(4,"杨志","青面兽");
HeroNode heroNode5 = new HeroNode(2,"吴用","智多星");
/* singleLinkList.insert(heroNode1);
singleLinkList.insert(heroNode2);
singleLinkList.insert(heroNode3);*/
//测试按照编号升序插入
singleLinkList.insertByOrder(heroNode1);
singleLinkList.insertByOrder(heroNode2);
singleLinkList.insertByOrder(heroNode3);
singleLinkList.insertByOrder(heroNode4);
singleLinkList.insertByOrder(heroNode5);
//测试修改
HeroNode heroNode6 = new HeroNode(2,"吴用","大笨蛋");
singleLinkList.update(heroNode6);
singleLinkList.delete(2);
singleLinkList.show();
System.out.println("有效元素个数:" + singleLinkList.listLength(singleLinkList.getHead()));
System.out.println("倒数第三个元素:" + singleLinkList.locateElem(singleLinkList.getHead(),3));
}
}
/**
* 定义SingleLinkList管理 管理节点
*/
class SingleLinkList{
/**
* 初始化一个头结点,不存放具体的数据。
*/
private HeroNode head = new HeroNode(0,"","");
/**
*
* @return 头结点
*/
public HeroNode getHead() {
return head;
}
/**
* 添加结点
*
* 不考虑当前编号,找到当前链表的最后一个节点,最后一个节点为NULL。
* 将最后这个节点的next 指向新的节点。
*/
public void insert(HeroNode heroNode){
//因为头结点不动,我们需要一个辅助遍历
HeroNode temp = head;
//遍历链表
while (true){
//当temp的next==null 则找到了最后一个节点。
if (temp.next == null){
break;
}
//若没有找到,就将temp后移下一个节点
temp = temp.next;
}
//退出循环时,temp指向了链表的最后,就可以将这个节点的next,指向新的节点。
temp.next = heroNode;
}
/**
* 按照no大小按升序序插入节点
* @param heroNode
*/
public void insertByOrder(HeroNode heroNode){
//因为头结点不动,需要借助一个辅助,来帮助找到合适添加位置
//单链表,temp是位于添加位置的前一个结点,否则插入失败, 因为我们可以根据上一个结点找到下一个节点位置,但是不能根据下一个节点找到上一个结点位置。
HeroNode temp = head;
// 添加no是否存在,默认为false
boolean flag = false;
while (true){
// 找到链表结尾
if (temp.next == null){
break;
}
// 找到插入位置,就在temp的后面
if (temp.next.no > heroNode.no){
break;
}else if (temp.next.no == heroNode.no){ //要添加的no已经存在
flag = true; //说明编号存在
break;
}
temp = temp.next;
}
if (flag){
throw new RuntimeException("待插入的编号:"+ heroNode.no + ",已经存在,插入失败。");
}else {
//将结点插入到链表,temp的后面
heroNode.next = temp.next;
temp.next = heroNode;
}
}
/**
* 根据结点的编号no来修改结点data信息
* @param newHeroNode
*/
public void update(HeroNode newHeroNode){
if (isEmpty()){
throw new RuntimeException("当前链表为空");
}
//找到需要修改修改的结点
HeroNode temp = head.next;
// 表示是否找到该结点
boolean flag = false;
while (true){
if (temp == null){ //找到了链表最后一个节点,遍历完该链表了。
break;
}
// 找到该结点
if (temp.no == newHeroNode.no){
flag = true;
break;
}
temp = temp.next;
}
//flag为true找到该结点,修改结点
if (flag){
temp.name = newHeroNode.name;
temp.nickName = newHeroNode.nickName;
}else {
throw new RuntimeException("当前链表没有结点no = "+ newHeroNode.no);
}
}
/**
* 删除结点
* 比较的时候,是temp.next.no 和需要删除结点的no
* @param no 待删除结点no
*/
public void delete(int no){
if (isEmpty()){
throw new RuntimeException("当前链表为空");
}
HeroNode temp = head;
boolean flag = false;
while (true){
//找到了结点最后位置,依旧没有找到该元素
if (temp.next == null){
break;
}
//找到待删除结点的前一个结点temp
if (temp.next.no == no){
flag = true;
break;
}
temp = temp.next;
}
if (flag){
System.out.println("成功删除结点:"+ temp.next);
temp.next = temp.next.next;
}
}
/**
* 获取到链表结点的个数(如果是带头结点的链表,不统计头结点)
* @param head 链表的头结点
* @return
*/
public int listLength(HeroNode head){
//空链表 返回0
if (head.next == null){
return 0;
}
int length = 0;
//定义一个辅助变量,不统计头结点
HeroNode cur = head.next;
while (cur != null){
length++;
cur = cur.next;//遍历,指向下一个节点。
}
return length;
}
/**
* 查找单链表中倒数第K个结点
* @param head 头结点
* @param location 第N个
* @return
*/
public HeroNode locateElem(HeroNode head,int location){
//链表为空,找不到 返回null
if (isEmpty()){
return null;
}
//第一次遍历,获取链表个数
int length = listLength(head);
//第二次遍历 length - location 就是倒数的第K个结点
if (location <= 0 || location > length){
return null;
}
//定义一个辅助变量,遍历
HeroNode cur = head.next;
for (int i = 0; i < length - location; i++) {
cur = cur.next;
}
return cur;
}
/**
* 遍历链表
*/
public void show(){
//通过一辅助遍历 遍历整个链表。
//判断链表是否为空
if (isEmpty()){
System.out.println("链表当前没有元素");
return;
}
HeroNode temp = head.next;
while (true){
// 是否到了最后一个节点
if (temp == null){
break;
}
//输出节点信息
System.out.println(temp);
//将next后移
temp = temp.next;
}
}
/**
* 链表是否为空
* @return
*/
public boolean isEmpty(){
return head.next == null;
}
}
/**
* 定义HeroNode 每个HeroNode 对象就是一个节点
*/
class HeroNode{
/**
* 编号
*/
public int no;
/**
* 名字
*/
public String name;
/**
* 昵称
*/
public String nickName;
/**
* 指向下一个节点
*/
public HeroNode next;
/**
* 构造器
* @param no 编号
* @param name 名字
* @param nickName 昵称
*/
public HeroNode(int no,String name,String nickName){
this.no = no;
this.name = name;
this.nickName = nickName;
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
", nickName='" + nickName + '\'' +
'}';
}
}
输出结果
单链表单转
package LinkList;
import java.awt.image.BufferStrategy;
import java.beans.beancontext.BeanContext;
/**
* 单链表
*/
public class SingleLinkListTest {
public static void main(String[] args) {
SingleLinkList singleLinkList = new SingleLinkList();
HeroNode heroNode1 = new HeroNode(1,"宋江","及时雨");
HeroNode heroNode2 = new HeroNode(6,"卢俊义","玉麒麟");
HeroNode heroNode3 = new HeroNode(5,"鲁智深","花和尚");
HeroNode heroNode4 = new HeroNode(4,"杨志","青面兽");
HeroNode heroNode5 = new HeroNode(2,"吴用","智多星");
/* singleLinkList.insert(heroNode1);
singleLinkList.insert(heroNode2);
singleLinkList.insert(heroNode3);*/
//测试按照编号升序插入
singleLinkList.insertByOrder(heroNode1);
singleLinkList.insertByOrder(heroNode2);
singleLinkList.insertByOrder(heroNode3);
singleLinkList.insertByOrder(heroNode4);
singleLinkList.insertByOrder(heroNode5);
//测试修改
/* HeroNode heroNode6 = new HeroNode(2,"吴用","大笨蛋");
singleLinkList.update(heroNode6);
singleLinkList.delete(2);
singleLinkList.show();
System.out.println("有效元素个数:" + singleLinkList.listLength(singleLinkList.getHead()));
System.out.println("倒数第三个元素:" + singleLinkList.locateElem(singleLinkList.getHead(),3));*/
//测试反转
System.out.println("原始单链表:");
singleLinkList.show();
singleLinkList.reverseList(singleLinkList.getHead());
System.out.println("反转后的单链表:");
singleLinkList.show();
}
}
/**
* 定义SingleLinkList管理 管理节点
*/
class SingleLinkList{
/**
* 初始化一个头结点,不存放具体的数据。
*/
private HeroNode head = new HeroNode(0,"","");
/**
*
* @return 头结点
*/
public HeroNode getHead() {
return head;
}
/**
* 添加结点
*
* 不考虑当前编号,找到当前链表的最后一个节点,最后一个节点为NULL。
* 将最后这个节点的next 指向新的节点。
*/
public void insert(HeroNode heroNode){
//因为头结点不动,我们需要一个辅助遍历
HeroNode temp = head;
//遍历链表
while (true){
//当temp的next==null 则找到了最后一个节点。
if (temp.next == null){
break;
}
//若没有找到,就将temp后移下一个节点
temp = temp.next;
}
//退出循环时,temp指向了链表的最后,就可以将这个节点的next,指向新的节点。
temp.next = heroNode;
}
/**
* 按照no大小按升序序插入节点
* @param heroNode
*/
public void insertByOrder(HeroNode heroNode){
//因为头结点不动,需要借助一个辅助,来帮助找到合适添加位置
//单链表,temp是位于添加位置的前一个结点,否则插入失败, 因为我们可以根据上一个结点找到下一个节点位置,但是不能根据下一个节点找到上一个结点位置。
HeroNode temp = head;
// 添加no是否存在,默认为false
boolean flag = false;
while (true){
// 找到链表结尾
if (temp.next == null){
break;
}
// 找到插入位置,就在temp的后面
if (temp.next.no > heroNode.no){
break;
}else if (temp.next.no == heroNode.no){ //要添加的no已经存在
flag = true; //说明编号存在
break;
}
temp = temp.next;
}
if (flag){
throw new RuntimeException("待插入的编号:"+ heroNode.no + ",已经存在,插入失败。");
}else {
//将结点插入到链表,temp的后面
heroNode.next = temp.next;
temp.next = heroNode;
}
}
/**
* 根据结点的编号no来修改结点data信息
* @param newHeroNode
*/
public void update(HeroNode newHeroNode){
if (isEmpty()){
throw new RuntimeException("当前链表为空");
}
//找到需要修改修改的结点
HeroNode temp = head.next;
// 表示是否找到该结点
boolean flag = false;
while (true){
if (temp == null){ //找到了链表最后一个节点,遍历完该链表了。
break;
}
// 找到该结点
if (temp.no == newHeroNode.no){
flag = true;
break;
}
temp = temp.next;
}
//flag为true找到该结点,修改结点
if (flag){
temp.name = newHeroNode.name;
temp.nickName = newHeroNode.nickName;
}else {
throw new RuntimeException("当前链表没有结点no = "+ newHeroNode.no);
}
}
/**
* 删除结点
* 比较的时候,是temp.next.no 和需要删除结点的no
* @param no 待删除结点no
*/
public void delete(int no){
if (isEmpty()){
throw new RuntimeException("当前链表为空");
}
HeroNode temp = head;
boolean flag = false;
while (true){
//找到了结点最后位置,依旧没有找到该元素
if (temp.next == null){
break;
}
//找到待删除结点的前一个结点temp
if (temp.next.no == no){
flag = true;
break;
}
temp = temp.next;
}
if (flag){
System.out.println("成功删除结点:"+ temp.next);
temp.next = temp.next.next;
}
}
/**
* 获取到链表结点的个数(如果是带头结点的链表,不统计头结点)
* @param head 链表的头结点
* @return
*/
public int listLength(HeroNode head){
//空链表 返回0
if (head.next == null){
return 0;
}
int length = 0;
//定义一个辅助变量,不统计头结点
HeroNode cur = head.next;
while (cur != null){
length++;
cur = cur.next;//遍历,指向下一个节点。
}
return length;
}
/**
* 查找单链表中倒数第K个结点
* @param head 头结点
* @param location 第N个
* @return
*/
public HeroNode locateElem(HeroNode head,int location){
//链表为空,找不到 返回null
if (isEmpty()){
return null;
}
//第一次遍历,获取链表个数
int length = listLength(head);
//第二次遍历 length - location 就是倒数的第K个结点
if (location <= 0 || location > length){
return null;
}
//定义一个辅助变量,遍历
HeroNode cur = head.next;
for (int i = 0; i < length - location; i++) {
cur = cur.next;
}
return cur;
}
/**
* 反转单链表
* @param head 头结点
*/
public void reverseList(HeroNode head){
//单链表为空或者只有一个节点,直接返回
if (head.next == null || head.next.next == null){
return;
}
//定义一个辅助变量,帮助我们遍历原来的链表
HeroNode cur = head.next;
//指向当前节点的下一个结点
HeroNode next = null;
HeroNode reverseHead = new HeroNode(0,"","");
//遍历原来的链表。遍历每一个结点,就将其取出,并放在新的链表reverseHead的前端。
while (cur != null){
//暂时保留当前节点的下一个节点,因为后面需要使用
next = cur.next;
//将cur的下一个结点指向新链表的最前端
cur.next = reverseHead.next;
//将cur连接到新的链表
reverseHead.next = cur;
//cur指向下一个节点 cur后移
cur = next;
}
//head.next 指向reverseHead.next,实现反转。
head.next = reverseHead.next;
}
/**
* 遍历链表
*/
public void show(){
//通过一辅助遍历 遍历整个链表。
//判断链表是否为空
if (isEmpty()){
System.out.println("链表当前没有元素");
return;
}
HeroNode temp = head.next;
while (true){
// 是否到了最后一个节点
if (temp == null){
break;
}
//输出节点信息
System.out.println(temp);
//将next后移
temp = temp.next;
}
}
/**
* 链表是否为空
* @return
*/
public boolean isEmpty(){
return head.next == null;
}
}
/**
* 定义HeroNode 每个HeroNode 对象就是一个节点
*/
class HeroNode{
/**
* 编号
*/
public int no;
/**
* 名字
*/
public String name;
/**
* 昵称
*/
public String nickName;
/**
* 指向下一个节点
*/
public HeroNode next;
/**
* 构造器
* @param no 编号
* @param name 名字
* @param nickName 昵称
*/
public HeroNode(int no,String name,String nickName){
this.no = no;
this.name = name;
this.nickName = nickName;
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
", nickName='" + nickName + '\'' +
'}';
}
}
输出结果
从尾带头打印单链表
两种方式:1、反向遍历。2、Stack 栈
package LinkList;
import com.sun.xml.internal.bind.v2.model.core.ID;
import java.awt.image.BufferStrategy;
import java.beans.beancontext.BeanContext;
import java.util.Stack;
/**
* 单链表
*/
public class SingleLinkListTest {
public static void main(String[] args) {
SingleLinkList singleLinkList = new SingleLinkList();
HeroNode heroNode1 = new HeroNode(1,"宋江","及时雨");
HeroNode heroNode2 = new HeroNode(6,"卢俊义","玉麒麟");
HeroNode heroNode3 = new HeroNode(5,"鲁智深","花和尚");
HeroNode heroNode4 = new HeroNode(4,"杨志","青面兽");
HeroNode heroNode5 = new HeroNode(2,"吴用","智多星");
/* singleLinkList.insert(heroNode1);
singleLinkList.insert(heroNode2);
singleLinkList.insert(heroNode3);*/
//测试按照编号升序插入
singleLinkList.insertByOrder(heroNode1);
singleLinkList.insertByOrder(heroNode2);
singleLinkList.insertByOrder(heroNode3);
singleLinkList.insertByOrder(heroNode4);
singleLinkList.insertByOrder(heroNode5);
//测试修改
/* HeroNode heroNode6 = new HeroNode(2,"吴用","大笨蛋");
singleLinkList.update(heroNode6);
singleLinkList.delete(2);
singleLinkList.show();
System.out.println("有效元素个数:" + singleLinkList.listLength(singleLinkList.getHead()));
System.out.println("倒数第三个元素:" + singleLinkList.locateElem(singleLinkList.getHead(),3));*/
//测试反转
/* System.out.println("原始单链表:");
singleLinkList.show();
singleLinkList.reverseList(singleLinkList.getHead());
System.out.println("反转后的单链表:");
singleLinkList.show();*/
//测试逆序打印
System.out.println("原始单链表:");
singleLinkList.show();
System.out.println("逆序输出单链表:");
singleLinkList.reversePrint(singleLinkList.getHead());
}
}
/**
* 定义SingleLinkList管理 管理节点
*/
class SingleLinkList{
/**
* 初始化一个头结点,不存放具体的数据。
*/
private HeroNode head = new HeroNode(0,"","");
/**
*
* @return 头结点
*/
public HeroNode getHead() {
return head;
}
/**
* 添加结点
*
* 不考虑当前编号,找到当前链表的最后一个节点,最后一个节点为NULL。
* 将最后这个节点的next 指向新的节点。
*/
public void insert(HeroNode heroNode){
//因为头结点不动,我们需要一个辅助遍历
HeroNode temp = head;
//遍历链表
while (true){
//当temp的next==null 则找到了最后一个节点。
if (temp.next == null){
break;
}
//若没有找到,就将temp后移下一个节点
temp = temp.next;
}
//退出循环时,temp指向了链表的最后,就可以将这个节点的next,指向新的节点。
temp.next = heroNode;
}
/**
* 按照no大小按升序序插入节点
* @param heroNode
*/
public void insertByOrder(HeroNode heroNode){
//因为头结点不动,需要借助一个辅助,来帮助找到合适添加位置
//单链表,temp是位于添加位置的前一个结点,否则插入失败, 因为我们可以根据上一个结点找到下一个节点位置,但是不能根据下一个节点找到上一个结点位置。
HeroNode temp = head;
// 添加no是否存在,默认为false
boolean flag = false;
while (true){
// 找到链表结尾
if (temp.next == null){
break;
}
// 找到插入位置,就在temp的后面
if (temp.next.no > heroNode.no){
break;
}else if (temp.next.no == heroNode.no){ //要添加的no已经存在
flag = true; //说明编号存在
break;
}
temp = temp.next;
}
if (flag){
throw new RuntimeException("待插入的编号:"+ heroNode.no + ",已经存在,插入失败。");
}else {
//将结点插入到链表,temp的后面
heroNode.next = temp.next;
temp.next = heroNode;
}
}
/**
* 根据结点的编号no来修改结点data信息
* @param newHeroNode
*/
public void update(HeroNode newHeroNode){
if (isEmpty()){
throw new RuntimeException("当前链表为空");
}
//找到需要修改修改的结点
HeroNode temp = head.next;
// 表示是否找到该结点
boolean flag = false;
while (true){
if (temp == null){ //找到了链表最后一个节点,遍历完该链表了。
break;
}
// 找到该结点
if (temp.no == newHeroNode.no){
flag = true;
break;
}
temp = temp.next;
}
//flag为true找到该结点,修改结点
if (flag){
temp.name = newHeroNode.name;
temp.nickName = newHeroNode.nickName;
}else {
throw new RuntimeException("当前链表没有结点no = "+ newHeroNode.no);
}
}
/**
* 删除结点
* 比较的时候,是temp.next.no 和需要删除结点的no
* @param no 待删除结点no
*/
public void delete(int no){
if (isEmpty()){
throw new RuntimeException("当前链表为空");
}
HeroNode temp = head;
boolean flag = false;
while (true){
//找到了结点最后位置,依旧没有找到该元素
if (temp.next == null){
break;
}
//找到待删除结点的前一个结点temp
if (temp.next.no == no){
flag = true;
break;
}
temp = temp.next;
}
if (flag){
System.out.println("成功删除结点:"+ temp.next);
temp.next = temp.next.next;
}
}
/**
* 获取到链表结点的个数(如果是带头结点的链表,不统计头结点)
* @param head 链表的头结点
* @return
*/
public int listLength(HeroNode head){
//空链表 返回0
if (head.next == null){
return 0;
}
int length = 0;
//定义一个辅助变量,不统计头结点
HeroNode cur = head.next;
while (cur != null){
length++;
cur = cur.next;//遍历,指向下一个节点。
}
return length;
}
/**
* 查找单链表中倒数第K个结点
* @param head 头结点
* @param location 第N个
* @return
*/
public HeroNode locateElem(HeroNode head,int location){
//链表为空,找不到 返回null
if (isEmpty()){
return null;
}
//第一次遍历,获取链表个数
int length = listLength(head);
//第二次遍历 length - location 就是倒数的第K个结点
if (location <= 0 || location > length){
return null;
}
//定义一个辅助变量,遍历
HeroNode cur = head.next;
for (int i = 0; i < length - location; i++) {
cur = cur.next;
}
return cur;
}
/**
* 反转单链表
* @param head 头结点
*/
public void reverseList(HeroNode head){
//单链表为空或者只有一个节点,直接返回
if (head.next == null || head.next.next == null){
return;
}
//定义一个辅助变量,帮助我们遍历原来的链表
HeroNode cur = head.next;
//指向当前节点的下一个结点
HeroNode next = null;
HeroNode reverseHead = new HeroNode(0,"","");
//遍历原来的链表。遍历每一个结点,就将其取出,并放在新的链表reverseHead的前端。
while (cur != null){
//暂时保留当前节点的下一个节点,因为后面需要使用
next = cur.next;
//将cur的下一个结点指向新链表的最前端
cur.next = reverseHead.next;
//将cur连接到新的链表
reverseHead.next = cur;
//cur指向下一个节点 cur后移
cur = next;
}
//head.next 指向reverseHead.next,实现反转。
head.next = reverseHead.next;
}
/**
* 逆序打印链表
* @param head 头结点
*/
public void reversePrint(HeroNode head){
//空链表不打印
if (head.next == null){
return;
}
//创建一个栈,将各个节点入栈
Stack<HeroNode> heroNodeStack = new Stack<>();
HeroNode cur = head.next;
while (cur != null){
heroNodeStack.push(cur);
cur = cur.next;
}
//出栈
while (heroNodeStack.size() > 0){
System.out.println(heroNodeStack.pop());//先进后出
}
}
/**
* 遍历链表
*/
public void show(){
//通过一辅助遍历 遍历整个链表。
//判断链表是否为空
if (isEmpty()){
System.out.println("链表当前没有元素");
return;
}
HeroNode temp = head.next;
while (true){
// 是否到了最后一个节点
if (temp == null){
break;
}
//输出节点信息
System.out.println(temp);
//将next后移
temp = temp.next;
}
}
/**
* 链表是否为空
* @return
*/
public boolean isEmpty(){
return head.next == null;
}
}
/**
* 定义HeroNode 每个HeroNode 对象就是一个节点
*/
class HeroNode{
/**
* 编号
*/
public int no;
/**
* 名字
*/
public String name;
/**
* 昵称
*/
public String nickName;
/**
* 指向下一个节点
*/
public HeroNode next;
/**
* 构造器
* @param no 编号
* @param name 名字
* @param nickName 昵称
*/
public HeroNode(int no,String name,String nickName){
this.no = no;
this.name = name;
this.nickName = nickName;
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
", nickName='" + nickName + '\'' +
'}';
}
}
合并两个有序的单链表
/**
* 单链表
*/
public class SingleLinkListTest {
public static void main(String[] args) {
SingleLinkList singleLinkList = new SingleLinkList();
SingleLinkList singleLinkList1 = new SingleLinkList();
SingleLinkList singleLinkList3 = new SingleLinkList();
HeroNode heroNode1 = new HeroNode(1,"宋江","及时雨");
HeroNode heroNode2 = new HeroNode(4,"卢俊义","玉麒麟");
HeroNode heroNode3 = new HeroNode(7,"鲁智深","花和尚");
HeroNode heroNode4 = new HeroNode(2,"杨志","青面兽");
HeroNode heroNode5 = new HeroNode(5,"吴用","智多星");
HeroNode heroNode6 = new HeroNode(8,"周通","小霸王");
//测试按照编号升序插入
singleLinkList.insertByOrder(heroNode1);
singleLinkList.insertByOrder(heroNode2);
singleLinkList.insertByOrder(heroNode3);
singleLinkList1.insertByOrder(heroNode4);
singleLinkList1.insertByOrder(heroNode5);
singleLinkList1.insertByOrder(heroNode6);
System.out.println("原始单链表1:");
singleLinkList.show();
System.out.println("原始单链表2:");
singleLinkList1.show();
System.out.println("合并后");
SingleLinkList.twoLinkedList(singleLinkList.getHead(),singleLinkList1.getHead(),singleLinkList3.getHead());
singleLinkList3.show();
}
}
/**
* 定义SingleLinkList管理 管理节点
*/
class SingleLinkList{
/**
* 初始化一个头结点,不存放具体的数据。
*/
private HeroNode head = new HeroNode(0,"","");
/**
*
* @return 头结点
*/
public HeroNode getHead() {
return head;
}
/**
* 添加结点
*
* 不考虑当前编号,找到当前链表的最后一个节点,最后一个节点为NULL。
* 将最后这个节点的next 指向新的节点。
*/
public void insert(HeroNode heroNode){
//因为头结点不动,我们需要一个辅助遍历
HeroNode temp = head;
//遍历链表
while (true){
//当temp的next==null 则找到了最后一个节点。
if (temp.next == null){
break;
}
//若没有找到,就将temp后移下一个节点
temp = temp.next;
}
//退出循环时,temp指向了链表的最后,就可以将这个节点的next,指向新的节点。
temp.next = heroNode;
}
/**
* 按照no大小按升序序插入节点
* @param heroNode
*/
public void insertByOrder(HeroNode heroNode){
//因为头结点不动,需要借助一个辅助,来帮助找到合适添加位置
//单链表,temp是位于添加位置的前一个结点,否则插入失败, 因为我们可以根据上一个结点找到下一个节点位置,但是不能根据下一个节点找到上一个结点位置。
HeroNode temp = head;
// 添加no是否存在,默认为false
boolean flag = false;
while (true){
// 找到链表结尾
if (temp.next == null){
break;
}
// 找到插入位置,就在temp的后面
if (temp.next.no > heroNode.no){
break;
}else if (temp.next.no == heroNode.no){ //要添加的no已经存在
flag = true; //说明编号存在
break;
}
temp = temp.next;
}
if (flag){
throw new RuntimeException("待插入的编号:"+ heroNode.no + ",已经存在,插入失败。");
}else {
//将结点插入到链表,temp的后面
heroNode.next = temp.next;
temp.next = heroNode;
}
}
/**
* 遍历链表
*/
public void show(){
//通过一辅助遍历 遍历整个链表。
//判断链表是否为空
if (isEmpty()){
System.out.println("链表当前没有元素");
return;
}
HeroNode temp = head.next;
while (true){
// 是否到了最后一个节点
if (temp == null){
break;
}
//输出节点信息
System.out.println(temp);
//将next后移
temp = temp.next;
}
}
/**
* 链表是否为空
* @return
*/
public boolean isEmpty(){
return head.next == null;
}
/**
* 合并两个有序链表
* @param head1 头结点1
* @param head2 头结点2
* @param newHeroNode 空头结点
*/
public static void twoLinkedList(HeroNode head1, HeroNode head2,HeroNode newHeroNode) {
// 如果两个链表均为空,则无需合并,直接返回
if (head1.next == null && head2.next == null) {
return;
}
// 如果链表1为空,则将head3.next指向head2.next,实现链表2中的节点连接到链表3
if (head1.next == null) {
newHeroNode.next = head2.next;
} else {
// 将head3.next指向head1.next,实现链表1中的节点连接到链表3
newHeroNode.next = head1.next;
// 定义一个辅助的指针(变量),帮助我们遍历链表2
HeroNode cur2 = head2.next;
// 定义一个辅助的指针(变量),帮助我们遍历链表3
HeroNode cur3 = newHeroNode;
HeroNode next = null;
// 遍历链表2,将其节点按顺序连接至链表3
while (cur2 != null) {
// 链表3遍历完毕后,可以直接将链表2剩下的节点连接至链表3的末尾
if (cur3.next == null) {
cur3.next = cur2;
break;
}
// 在链表3中,找到第一个大于链表2中的节点编号的节点
// 因为是单链表,找到的节点是位于添加位置的前一个节点,否则无法插入
if (cur2.no <= cur3.next.no) {
next = cur2.next; // 先暂时保存链表2中当前节点的下一个节点,方便后续使用
cur2.next = cur3.next; // 将cur2的下一个节点指向cur3的下一个节点
cur3.next = cur2; // 将cur2连接到链表3上
cur2 = next; // 让cur2后移
}
// 遍历链表3
cur3 = cur3.next;
}
}
}
}
/**
* 定义HeroNode 每个HeroNode 对象就是一个节点
*/
class HeroNode{
/**
* 编号
*/
public int no;
/**
* 名字
*/
public String name;
/**
* 昵称
*/
public String nickName;
/**
* 指向下一个节点
*/
public HeroNode next;
/**
* 构造器
* @param no 编号
* @param name 名字
* @param nickName 昵称
*/
public HeroNode(int no,String name,String nickName){
this.no = no;
this.name = name;
this.nickName = nickName;
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
", nickName='" + nickName + '\'' +
'}';
}
}
完整代码
package LinkList;
import com.sun.xml.internal.bind.v2.model.core.ID;
import java.awt.image.BufferStrategy;
import java.beans.beancontext.BeanContext;
import java.util.Stack;
/**
* 单链表
*/
public class SingleLinkListTest {
public static void main(String[] args) {
SingleLinkList singleLinkList = new SingleLinkList();
SingleLinkList singleLinkList1 = new SingleLinkList();
SingleLinkList singleLinkList3 = new SingleLinkList();
HeroNode heroNode1 = new HeroNode(1,"宋江","及时雨");
HeroNode heroNode2 = new HeroNode(4,"卢俊义","玉麒麟");
HeroNode heroNode3 = new HeroNode(7,"鲁智深","花和尚");
HeroNode heroNode4 = new HeroNode(2,"杨志","青面兽");
HeroNode heroNode5 = new HeroNode(5,"吴用","智多星");
HeroNode heroNode6 = new HeroNode(8,"周通","小霸王");
/* singleLinkList.insert(heroNode1);
singleLinkList.insert(heroNode2);
singleLinkList.insert(heroNode3);*/
//测试按照编号升序插入
singleLinkList.insertByOrder(heroNode1);
singleLinkList.insertByOrder(heroNode2);
singleLinkList.insertByOrder(heroNode3);
singleLinkList1.insertByOrder(heroNode4);
singleLinkList1.insertByOrder(heroNode5);
singleLinkList1.insertByOrder(heroNode6);
//测试修改
/* HeroNode heroNode6 = new HeroNode(2,"吴用","大笨蛋");
singleLinkList.update(heroNode6);
singleLinkList.delete(2);
singleLinkList.show();
System.out.println("有效元素个数:" + singleLinkList.listLength(singleLinkList.getHead()));
System.out.println("倒数第三个元素:" + singleLinkList.locateElem(singleLinkList.getHead(),3));*/
//测试反转
/* System.out.println("原始单链表:");
singleLinkList.show();
singleLinkList.reverseList(singleLinkList.getHead());
System.out.println("反转后的单链表:");
singleLinkList.show();*/
//测试逆序打印
/* System.out.println("原始单链表:");
singleLinkList.show();
System.out.println("逆序输出单链表:");
singleLinkList.reversePrint(singleLinkList.getHead());*/
System.out.println("原始单链表1:");
singleLinkList.show();
System.out.println("原始单链表2:");
singleLinkList1.show();
System.out.println("合并后");
SingleLinkList.twoLinkedList(singleLinkList.getHead(),singleLinkList1.getHead(),singleLinkList3.getHead());
singleLinkList3.show();
}
}
/**
* 定义SingleLinkList管理 管理节点
*/
class SingleLinkList{
/**
* 初始化一个头结点,不存放具体的数据。
*/
private HeroNode head = new HeroNode(0,"","");
/**
*
* @return 头结点
*/
public HeroNode getHead() {
return head;
}
/**
* 添加结点
*
* 不考虑当前编号,找到当前链表的最后一个节点,最后一个节点为NULL。
* 将最后这个节点的next 指向新的节点。
*/
public void insert(HeroNode heroNode){
//因为头结点不动,我们需要一个辅助遍历
HeroNode temp = head;
//遍历链表
while (true){
//当temp的next==null 则找到了最后一个节点。
if (temp.next == null){
break;
}
//若没有找到,就将temp后移下一个节点
temp = temp.next;
}
//退出循环时,temp指向了链表的最后,就可以将这个节点的next,指向新的节点。
temp.next = heroNode;
}
/**
* 按照no大小按升序序插入节点
* @param heroNode
*/
public void insertByOrder(HeroNode heroNode){
//因为头结点不动,需要借助一个辅助,来帮助找到合适添加位置
//单链表,temp是位于添加位置的前一个结点,否则插入失败, 因为我们可以根据上一个结点找到下一个节点位置,但是不能根据下一个节点找到上一个结点位置。
HeroNode temp = head;
// 添加no是否存在,默认为false
boolean flag = false;
while (true){
// 找到链表结尾
if (temp.next == null){
break;
}
// 找到插入位置,就在temp的后面
if (temp.next.no > heroNode.no){
break;
}else if (temp.next.no == heroNode.no){ //要添加的no已经存在
flag = true; //说明编号存在
break;
}
temp = temp.next;
}
if (flag){
throw new RuntimeException("待插入的编号:"+ heroNode.no + ",已经存在,插入失败。");
}else {
//将结点插入到链表,temp的后面
heroNode.next = temp.next;
temp.next = heroNode;
}
}
/**
* 根据结点的编号no来修改结点data信息
* @param newHeroNode
*/
public void update(HeroNode newHeroNode){
if (isEmpty()){
throw new RuntimeException("当前链表为空");
}
//找到需要修改修改的结点
HeroNode temp = head.next;
// 表示是否找到该结点
boolean flag = false;
while (true){
if (temp == null){ //找到了链表最后一个节点,遍历完该链表了。
break;
}
// 找到该结点
if (temp.no == newHeroNode.no){
flag = true;
break;
}
temp = temp.next;
}
//flag为true找到该结点,修改结点
if (flag){
temp.name = newHeroNode.name;
temp.nickName = newHeroNode.nickName;
}else {
throw new RuntimeException("当前链表没有结点no = "+ newHeroNode.no);
}
}
/**
* 删除结点
* 比较的时候,是temp.next.no 和需要删除结点的no
* @param no 待删除结点no
*/
public void delete(int no){
if (isEmpty()){
throw new RuntimeException("当前链表为空");
}
HeroNode temp = head;
boolean flag = false;
while (true){
//找到了结点最后位置,依旧没有找到该元素
if (temp.next == null){
break;
}
//找到待删除结点的前一个结点temp
if (temp.next.no == no){
flag = true;
break;
}
temp = temp.next;
}
if (flag){
System.out.println("成功删除结点:"+ temp.next);
temp.next = temp.next.next;
}
}
/**
* 获取到链表结点的个数(如果是带头结点的链表,不统计头结点)
* @param head 链表的头结点
* @return
*/
public int listLength(HeroNode head){
//空链表 返回0
if (head.next == null){
return 0;
}
int length = 0;
//定义一个辅助变量,不统计头结点
HeroNode cur = head.next;
while (cur != null){
length++;
cur = cur.next;//遍历,指向下一个节点。
}
return length;
}
/**
* 查找单链表中倒数第K个结点
* @param head 头结点
* @param location 第N个
* @return
*/
public HeroNode locateElem(HeroNode head,int location){
//链表为空,找不到 返回null
if (isEmpty()){
return null;
}
//第一次遍历,获取链表个数
int length = listLength(head);
//第二次遍历 length - location 就是倒数的第K个结点
if (location <= 0 || location > length){
return null;
}
//定义一个辅助变量,遍历
HeroNode cur = head.next;
for (int i = 0; i < length - location; i++) {
cur = cur.next;
}
return cur;
}
/**
* 反转单链表
* @param head 头结点
*/
public void reverseList(HeroNode head){
//单链表为空或者只有一个节点,直接返回
if (head.next == null || head.next.next == null){
return;
}
//定义一个辅助变量,帮助我们遍历原来的链表
HeroNode cur = head.next;
//指向当前节点的下一个结点
HeroNode next = null;
HeroNode reverseHead = new HeroNode(0,"","");
//遍历原来的链表。遍历每一个结点,就将其取出,并放在新的链表reverseHead的前端。
while (cur != null){
//暂时保留当前节点的下一个节点,因为后面需要使用
next = cur.next;
//将cur的下一个结点指向新链表的最前端
cur.next = reverseHead.next;
//将cur连接到新的链表
reverseHead.next = cur;
//cur指向下一个节点 cur后移
cur = next;
}
//head.next 指向reverseHead.next,实现反转。
head.next = reverseHead.next;
}
/**
* 逆序打印链表
* @param head 头结点
*/
public void reversePrint(HeroNode head){
//空链表不打印
if (head.next == null){
return;
}
//创建一个栈,将各个节点入栈
Stack<HeroNode> heroNodeStack = new Stack<>();
HeroNode cur = head.next;
while (cur != null){
heroNodeStack.push(cur);
cur = cur.next;
}
//出栈
while (heroNodeStack.size() > 0){
System.out.println(heroNodeStack.pop());//先进后出
}
}
/**
* 遍历链表
*/
public void show(){
//通过一辅助遍历 遍历整个链表。
//判断链表是否为空
if (isEmpty()){
System.out.println("链表当前没有元素");
return;
}
HeroNode temp = head.next;
while (true){
// 是否到了最后一个节点
if (temp == null){
break;
}
//输出节点信息
System.out.println(temp);
//将next后移
temp = temp.next;
}
}
/**
* 链表是否为空
* @return
*/
public boolean isEmpty(){
return head.next == null;
}
/**
* 合并两个有序链表
* @param head1 头结点1
* @param head2 头结点2
* @param newHeroNode 空头结点
*/
public static void twoLinkedList(HeroNode head1, HeroNode head2,HeroNode newHeroNode) {
// 如果两个链表均为空,则无需合并,直接返回
if (head1.next == null && head2.next == null) {
return;
}
// 如果链表1为空,则将head3.next指向head2.next,实现链表2中的节点连接到链表3
if (head1.next == null) {
newHeroNode.next = head2.next;
} else {
// 将head3.next指向head1.next,实现链表1中的节点连接到链表3
newHeroNode.next = head1.next;
// 定义一个辅助的指针(变量),帮助我们遍历链表2
HeroNode cur2 = head2.next;
// 定义一个辅助的指针(变量),帮助我们遍历链表3
HeroNode cur3 = newHeroNode;
HeroNode next = null;
// 遍历链表2,将其节点按顺序连接至链表3
while (cur2 != null) {
// 链表3遍历完毕后,可以直接将链表2剩下的节点连接至链表3的末尾
if (cur3.next == null) {
cur3.next = cur2;
break;
}
// 在链表3中,找到第一个大于链表2中的节点编号的节点
// 因为是单链表,找到的节点是位于添加位置的前一个节点,否则无法插入
if (cur2.no <= cur3.next.no) {
next = cur2.next; // 先暂时保存链表2中当前节点的下一个节点,方便后续使用
cur2.next = cur3.next; // 将cur2的下一个节点指向cur3的下一个节点
cur3.next = cur2; // 将cur2连接到链表3上
cur2 = next; // 让cur2后移
}
// 遍历链表3
cur3 = cur3.next;
}
}
}
}
/**
* 定义HeroNode 每个HeroNode 对象就是一个节点
*/
class HeroNode{
/**
* 编号
*/
public int no;
/**
* 名字
*/
public String name;
/**
* 昵称
*/
public String nickName;
/**
* 指向下一个节点
*/
public HeroNode next;
/**
* 构造器
* @param no 编号
* @param name 名字
* @param nickName 昵称
*/
public HeroNode(int no,String name,String nickName){
this.no = no;
this.name = name;
this.nickName = nickName;
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
", nickName='" + nickName + '\'' +
'}';
}
}