链表
- 链表是以节点的方式存储
- 每个节点包含data域和next域,next域:指向下一个节点
- 链表的存储不一定是连续的存储
- 链表
- 带头节点链表
- 不带头节点的链表
单链表示意图:
添加节点到单链表(不排序)
添加(创建)
- 创建一个head头节点,作用就是表示链表头
- 后面每个节点就加入到链表的最后
遍历
- 通过一个辅助遍历,帮助遍历整个单链表
/**
* 添加节点到单链表
* 不考虑编号顺序
* 1.找到当前链表的最后节点
* 2.将最后这个节点的next指向新的节点
* @param heroNode
*/
public void add(HeroNode heroNode){
//创建辅助遍历节点temp
HeroNode temp = head;
//循环遍历找到最后一个节点
while (true){
if(temp.getNextNode() == null){
break;
}
temp = temp.getNextNode();
}
//将最后节点的next 指向新的节点
temp.setNextNode(heroNode);
}
//获取打印链表
public void list(){
//链表为空,直接返回
if(head.getNextNode() == null){
return;
}
//创建辅助遍历节点temp
HeroNode temp = head;
while (true){
System.out.println(temp.toString());
if(temp.getNextNode() == null){
break;
}
temp = temp.getNextNode();
}
}
添加节点到单链表(排序)
添加
- 找到新添加的节点的位置,通过辅助变量实现 temp,用遍历搞定
- 新节点.next=temp.next
- 将temp.next = 新节点
public void addBySort(HeroNode heroNode){
HeroNode temp = head;
boolean flag = false; //判断添加的标志是否存在
while (true){
if(temp.getNextNode() == null){//头节点直接返回
break;
}
if(temp.getNextNode().getNo() > heroNode.getNo()){
//插入位置
break;
}
if (temp.getNextNode().getNo() == heroNode.getNo()){
flag = true;//已经插入直接返回
break;
}
temp = temp.getNextNode();
}
if(!flag){
heroNode.setNextNode(temp.getNextNode());
temp.setNextNode(heroNode);
}else {
throw new RuntimeException("add node exist!");
}
}
修改节点
public void updateByNo(HeroNode heroNode){
if(head.getNextNode() == null){
System.out.println("linkedlist is empty !");
}
HeroNode temp = head;
boolean flag = false;
while (true){
if(temp.getNo() == heroNode.getNo()){
flag = true;
break;
}
temp = temp.getNextNode();
}
if(flag){
temp.setName(heroNode.getName());
temp.setNickName(heroNode.getNickName());
}
}
删除节点
- 找到要删除节点的前一个节点temp
- temp.next = temp.next.next;
- 被删除的节点,将不会有其他引用,会被GC回收
public void delete(HeroNode heroNode){
if (head.getNextNode() == null){
System.out.println("linkedlist is empty !");
return;
}
HeroNode temp = head;
boolean flag = false;
while (true){
if(temp.getNextNode().getNo() == heroNode.getNo()){
flag = true;
break;
}
temp = temp.getNextNode();
}
if(flag){
temp.setNextNode(temp.getNextNode().getNextNode());
}
}
练习
- 获取链表的节点个数
public static int getNum(SingleLinkedList singleLinkedList){
int sum = 0;
HeroNode temp = singleLinkedList.head;
while (true){
if(temp.getNextNode() == null){
break;
}
sum++;
temp = temp.getNextNode();
}
return sum;
}
- 查找链表中倒数第k个节点
思路:
- 将链表从头到尾遍历,得到链表的总长度length
- 得到length后,我们从链表的第一个开始遍历(length-k)个,得到节点
public HeroNode lastTop(SingleLinkedList singleLinkedList,int k){
int length = getNum(singleLinkedList);
HeroNode temp = singleLinkedList.head;
for (int i = 0; i < length-k+1; i++) {
temp = temp.getNextNode();
}
return temp;
}
- 将链表翻转
思路:
- 先定义一个节点reverseHead
- 从头到尾遍历链表,每遍历一个节点,就将其取出,并放在新的链表reverseHead的后端
- 原来的链表的head.next = reverseHead.next
public void reverse(){
if(head.getNextNode() == null || head.getNextNode().getNextNode() == null){
System.out.println("链表元素为0或只有一个元素");
return;
}
HeroNode reverseHead = new HeroNode(0,"","");
//定义一个辅助指针变量,帮助我们遍历原来的链表
HeroNode cur = head.getNextNode();
HeroNode next = null; //指向当前节点[cur]的下一个节点
while (cur != null){
next = cur.getNextNode(); //保存当前节点的下一个节点
cur.setNextNode(reverseHead.getNextNode());//将cur的下一个节点指向新的链表的最前端
reverseHead.setNextNode(cur);
cur = next;//让cur后移
}
//将head.next指向reverseHead.next实现单链表反转
head.setNextNode(reverseHead.getNextNode());
}
- 逆序打印单链表
思路:
- 先将链表反转,然后再遍历,会破坏原来的链表结构,不建议使用
- 利用栈,将各个节点压入到栈中,利用栈先进后出的特点实现逆序打印
public void reversePrint(){
if (head.getNextNode() == null){
System.out.println("链表元素为0");
return;
}
Stack<HeroNode> stack = new Stack<>();//利用栈实现
HeroNode temp = head.getNextNode();
while (true){
stack.add(temp);//入栈
if(temp.getNextNode()==null){
break;
}
temp = temp.getNextNode();
}
while (stack.size()>0){
System.out.println(stack.pop().toString());//弹出并打印
}
}
- 合并两个有序单链表,合并之后的链表依然有序