基本介绍
链表是有序的列表,它在内存中的存储如下图:
- 链表是以节点的方式来存储,是链式存储
- 每个节点包含data 域,next域:指向下一个节点
- 如图:链表的各个节点不一定是连续存储
- 链表分带头节点的链表和没有头节点的链表,根据实际的需求来确定
单向链表的应用实例
使用带head头的单向链表实现:水浒英雄排行榜管理完成对英雄人物的增删改查操作
- 在添加英雄时,直接添加到链表的尾部
添加(创建)
a. 先创建一个head头节点,作用就是表示单链表的头
b. 每添加一个节点,就直接加入到链表的最后
遍历
:通过一个辅助变量遍历,帮助遍历整个链表
- 在添加英雄时,根据排名将英雄插入到指定位置(如果有这个排名,则添加失败,并给出提示)
需要按照编号的顺序添加
- 首先找到新添加的节点的位置,是通过辅助变量({指针),通过遍历来搞定
- 新的节点.next =temp.next
- 将temp.next=新的节点
修改节点功能
思路:(1)先找到该节点,通过遍历 (2) temp.name = newHeroNode .name ; temp. nickname= newHeroNode .nickname
删除节点
从单链表中删除一个节点的思路
- 先找到需要删除的这个节点的前一个节点temp
- termn.next = temp.next.next
- 被删除的节点,将不会有其它引用指向,会被垃圾回收机制回收
- 代码实现
1 | package com.ysy.linkedlist; |
单向链表面试题
求单链表中节点的个数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20//方法:获取单链表的节点的个数(如果是带头结点的链表,需求不统计头节点)
/**
*
* @param head 链表的头节点
* @return 有效节点个数
*/
public static int getLength(HeroNode head){
if(head.next == null){
//空链表
return 0;
}
int length = 0;
//定义一个辅助的变量
HeroNode cur = head.next;
while(cur != null){
length++;
cur = cur.next;//遍历
}
return length;
}查找单链表中的倒数第k个结点[新浪面试题]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26//查找单链表中的倒数第k个结点
//思路:
//1.编写一个方法,接收head节点,同时接受一个index
//2.index 表示是倒数第index个节点
//3.先把链表从头到尾遍历,得到链表的总的长度 getLength
//4.得到size后,从链表的第一个开始遍历(size - index)个,就可以得到
//5.如果找到了,则返回该节点,否则返回null
public static HeroNode findLastIndexNode(HeroNode head, int index){
//判断链表是否为空
if(head.next == null){
return null;//没有找到
}
//第一次遍历得到链表的长度(节点个数)
int size = getLength(head);
//第二次遍历 size-index 位置,就是倒数第K个点
//先做一个index的校验
if(index <= 0 || index > size){
return null;
}
//定义辅助变量,for 循环定位到倒数的index
HeroNode cur = head.next;
for(int i =0; i < size-index; i++){
cur = cur.next;
}
return cur;
}单链表的反转[腾讯面试题]
思路
- 先定义一个节点reverseHead=new HeroNode();
- 从头到尾遍历原来的链表,每遍历一个节点,就将其取出,并放在新的链表reverseHead的最前端.
- 原来的链表的head.next =reverseHead.next
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22//将单链表反转
public static 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.next = reverseHead.next;//将cur的下一个节点指向新的链表的最前端
reverseHead.next = cur;//将cur连接到新的链表上
cur = next;//让cur指向后一个节点
}
//将head.next指向reverseHead.next,实现反转
head.next = reverseHead.next;
}从尾到头打印单链表[百度,要求方式1:反向遍历。方式2: Stack栈]
思路
- 方式1:先将单链表进行反转操作,然后再遍历即可,这样的做的问题是会破坏原来的单链表的结构,不建议
- 方式2:可以利用栈这个数据结构,将各个节点压入到栈中,然后利用栈的先进后出的特点,就实现了逆序打印的效果.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19//从尾到头打印单链表(栈)
public static void reversePrint(HeroNode head) {
//如果当前链表为空,不能打印
if(head.next == null || head.next.next == null){
return;
}
//创建栈,将节点压入栈
Stack<HeroNode> stack = new Stack<>();
HeroNode cur = head.next;
//将链表的所有节点压入栈
while (cur != null){
stack.push(cur);
cur = cur.next;//cur后移,这样就可以压入下一个节点
}
//将栈中的节点进行打印,pop出栈
while (stack.size() > 0){
System.out.println(stack.pop());
}
}