链表
链表介绍以及基本增删改查
- 链表是有序的列表,但是它再内存中是存储如下
- 初始化,和添加 基础操作
package com.data;
public class SingleLinkListDemo {
public static void main(String[] args) {
SingleLinkList singleLinkList=new SingleLinkList();
singleLinkList.addNode(new Hero(1,"宋江","及时雨"));
singleLinkList.addNode(new Hero(2,"卢俊义","玉麒麟"));
singleLinkList.addNode(new Hero(3,"吴用","智多星"));
singleLinkList.addNode(new Hero(4,"林冲","豹子头"));
singleLinkList.list();
}
}
class SingleLinkList{
//初始化
Hero head=new Hero(0,"","");
//往尾部添加节点
public void addNode(Hero hero){
Hero temp=head;
while (true){
if(temp.next==null)break;
temp=temp.next;
}
temp.next=hero;
}
//遍历节点
public void list(){
Hero temp=head.next;
if(temp==null){
System.out.println("该链表为空");
return;
}
while (true){
if(temp==null)break;
System.out.println(temp);
temp=temp.next;
}
}
}
class Hero{
public int no;
public String name;
public String nickName;
public Hero next;
public Hero(int no,String name,String nickName){
this.no=no;
this.name=name;
this.nickName=nickName;
}
@Override
public String toString() {
return "Hero{" +
"no=" + no +
", name='" + name + '\'' +
", nickName='" + nickName + '\'' +
'}';
}
}
单链表小结
- 链表是以节点的方式来存储,是链式存储
- 每个节点包含data域,next域:指向下一个节点
- 链表的各节点不一定是连续存储
- 链表分带头节点的链表和没有头节点的链表,根据实际的需求来确定
单链表面试题
1, 求单链表中有效节点个数
2, 查找单链表中的倒数第k个节点【新浪面试题】
3,单链表的反转【腾讯面试题】
4, 从尾到头打印单链表【百度,要求方式一:反向遍历。方式二:Stack栈】
5, 合并两个有序的单链表,合并之后的链表仍然有序
题解
- 求单链表中有效节点个数
public int getLength(){
int length=0;
Hero temp=head;
while (true){
if(temp.next==null)break;
length++;
temp=temp.next;
}
return length;
}
-
查找单链表中的倒数第k个节点【新浪面试题】
-
思路:先获取长度得到size-k;
//查找单链表中的倒数第k个节点
public Hero getIndexNode(int index){
Hero temp=head.next;
int length=this.getLength();
boolean flag=false;
int count=0;
while(true){
if(temp==null)break;
if(count==length-index){
flag=true;
break;
}
count++;
temp=temp.next;
}
if(flag)return temp;
else System.out.println("没有找到");
return null;
}
- 单链表的反转【腾讯面试题】
public void reverseList(){
Hero newListHead=new Hero(0,"","");
Hero temp=head.next;
Hero next;
while (temp!=null){
next=temp.next;
temp.next=newListHead.next;
newListHead.next=temp;
temp=next;
}
head.next=newListHead.next;
}
-
从尾到头打印单链表【百度,要求方式一:反向遍历。方式二:Stack栈】
-
思路:方式1:先反转后打印,但是会破坏原来的单链表的结构,不建议。
-
方式2:将各个节点压入到栈中,然后利用栈的先进后出的特点,就实现了逆序打印的效果。
//采取方式2
//从尾到头打印单链表
public void reversePrint(){
Hero temp=head.next;
Stack<Hero> stack=new Stack<>();
while (temp!=null){
stack.push(temp);
temp=temp.next;
}
while (!stack.empty()){
System.out.println(stack.pop());
}
}
-
练习
-
合并两个有序的单链表,合并之后的链表仍然有序
static private SingleLinkList merge(SingleLinkList list1,SingleLinkList list2){
Hero temp1=list1.head.next;
Hero temp2=list2.head;
boolean flage=true;
while (temp1!=null) {
while (temp1.no >= temp2.next.no) {
temp2 = temp2.next;
if (temp2.next == null) {
// System.out.println("没有找到");
flage = false;
break;
}
}
Hero next = temp1.next;
if (flage) {
temp1.next = temp2.next;
temp2.next = temp1;
temp1 = next;
continue;
} else {
temp2.next = temp1;
break;
}
}
return list2;
}
双链表
管理单链表的确定分析
- 管理单链表的确定分析:
- 单向链表查找的方向只能是一个方向,而双链表可以向前或者向后查找。
- 单链表不能自我删除,需要辅助节点,而双链表相反,所以我们单链表删除节点总是找到temp,temp是待删除节点的前一个节点。
-
遍历 方式和单链表一样,只是可以向前,也可以向后查找
-
添加 (默认添加到双向链表的最后)
-
先找到双向链表的最后这个节点
temp.next=newNode
newNode.pre=temp
单向环形链表应用场景
Josephu(约瑟夫,约瑟夫环)问题
- 设编号为1,2…n的n个人围坐在一起,约定编号为k(1<=k<=n)的人从1开始报数,数到m的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,此此类推,直到所有人出列为止,由此产生一个出队编号的序列。
-
构建一个单项的环形链表思路
- 先创建第一个节点,让first指向该节点,并形成环形
- 后面当我们每创建一个新的节点,就把该节点,加入到已有的环形链表中即可
-
遍历环形链表
- 先让一个辅助指针变量curBoy,指向first节点
- 然后通过一个while循环遍历该环形链表即可curBoy.next==fisrt结束。
-
package com.data;
public class CircleLinkList {
public static void main(String[] args) {
CircleList circleList=new CircleList();
circleList.addNode(5);
circleList.show();
}
}
class CircleList{
Boy first=new Boy(0);
Boy cur=new Boy(0);
//增加节点
public void addNode(int n){
if(n<1){
System.out.println("创建循环链表数据有误");
}
for(int i=1;i<n+1;i++){
if(i==1){
first.no=i;
first.next=first;
cur=first;
}else {
Boy newNode=new Boy(i);
cur.next=newNode;
newNode.next=first;
cur=cur.next;
}
}
}
//打印链表
public void show(){
cur=first;
while (true){
if(cur.next==first){
System.out.println(cur.no);
break;
}
System.out.print(cur.no+"->");
cur=cur.next;
}
}
}
class Boy{
public int no;
public Boy next;
public Boy(int no){
this.no=no;
}
}
解决约瑟夫环的问题
- 设编号为1,2…n的n个人围坐在一起,约定编号为k(1<=k<=n)的人从1开始报数,数到m的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,此此类推,直到所有人出列为止,由此产生一个出队编号的序列。
-
图解
-
代码
-
public void yuesefu(int start,int num,int sum){
if(start>sum||num>sum||sum<1) {
System.out.println("参数不合法");
return;
}
//开始添加节点
addNode(sum);
Boy helper=new Boy(0);
helper=cur;
//找到开始的节点
while (true){
if(first.no==start)break;
helper=helper.next;
first=cur.next;
}
while (true){
if(first.next==first){
System.out.println("最后留下来的是"+helper.no);
break;
}
//循环到规定之后的节点
for(int i=0;i<num-1;i++){
helper=helper.next;
first=first.next;
}
//取出节点
System.out.println(first.no+"->");
first=first.next;
helper.next=first;
}
}