第4章:链表
单向链表
节点类
public class HeroNode {
public int no;
public String name;
public String nickname; //别名
public HeroNode next;
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 SingleLinkedList {
private HeroNode head = new HeroNode(0, "", ""); //头节点,不存放数据
//在尾部添加节点
public void add(HeroNode heroNode) {
HeroNode temp = head;
while (true) {
if (temp.next == null) {
break;
}
temp = temp.next;
}
temp.next = heroNode;
}
//按顺序添加节点
public void addByOrder(HeroNode heroNode) {
HeroNode temp = head;
boolean flag = false;
while (true) {
if (temp.next == null) {
break;
}
if (temp.next.no > heroNode.no) {
break;
} else if (temp.next.no == heroNode.no) {
flag = true;
break;
}
temp = temp.next;
}
if (flag) {
System.out.println("编号" + heroNode.no + "已存在");
} else {
heroNode.next = temp.next;
temp.next = heroNode;
}
}
//修改节点信息
public void update(HeroNode heroNode) {
if (head.next == null) {
System.out.println("链表为空");
return;
}
HeroNode temp = head;
boolean flag = false;
while (true) {
if (temp.next == null) {
break;
}
if (temp.next.no == heroNode.no) {
flag = true;
break;
}
temp = temp.next;
}
if (flag) {
temp.next.name = heroNode.name;
temp.next.nickname = heroNode.nickname;
} else {
System.out.println("没有找到呢");
}
}
//删除节点
public void del(int no) {
HeroNode temp = head;
boolean flag = false;
while (true) {
if (temp.next == null) {
break;
}
if (temp.next.no == no) {
flag = true;
break;
}
temp = temp.next;
}
if (flag) {
temp.next = temp.next.next;
} else {
System.out.println("不存在");
}
}
//遍历
public void list() {
if (head.next == null) {
System.out.println("链表为空");
return;
}
HeroNode temp=head;
while (true){
if (temp.next==null){
break;
}
System.out.println(temp.next);
temp=temp.next;
}
}
}
单链表面试题
1. 求单链表中有效节点的个数
public int getLength(HeroNode heroNode){
if (head.next==null){
return 0;
}
int length=0;
HeroNode temp=head;
while (temp.next!=null){
length++;
temp=temp.next;
}
return length;
}
2. 查找单链表中的倒数第k个结点【新浪面试题】
public HeroNode findLastIndexNode(HeroNode head,int index){
if (head.next==null){
return null;
}
int size=getLength(head);
if (index<=0||index>size){
System.out.println("输入错误");
}
HeroNode temp=head.next;
for (int i = 0; i < size-index; i++) {
temp=temp.next;
}
return temp;
}
当size=5,index=2(倒数第二个)时,size-index=3
3. 单链表的反转【腾讯面试题】
新建一个头节点,即新链表
遍历旧链表,每遍历到一个就放在新链表的最前面,紧跟新链表头节点后面
最后旧链表头节点指向新链表头节点.next
public void reverseList(HeroNode head){
if (head.next==null||head.next.next==null){
return;
}
HeroNode temp=head.next;
HeroNode tempNext=null;
HeroNode reverseHead=new HeroNode(0,"","");
while (temp!=null){
tempNext=temp.next; //保存temp的下一个节点
temp.next=reverseHead.next; //放到最前边
reverseHead.next=temp;
temp=tempNext; //后移
}
head.next= reverseHead.next;
}
4. 从尾到头打印单链表 【百度,要求方式1:反向遍历 。 方式2:Stack栈】
使用栈
public void reversePrint(HeroNode head){
if (head.next==null){
return;
}
Stack<HeroNode> stack = new Stack<>();
HeroNode temp=head.next;
while (temp!=null){
stack.push(temp);
temp=temp.next;
}
while (stack.size()>0){
System.out.println(stack.pop());
}
}
5. 合并两个有序的单链表,合并之后的链表依然有序
public HeroNode merge(HeroNode head1,HeroNode head2){
HeroNode heroNode=new HeroNode(0,"","");
HeroNode temp=heroNode;
while (head1!=null&&head2!=null) {
if (head1.no > head2.no) {
heroNode.next = head2; //添加小的
heroNode = head2; //后移
head2 = head2.next; //head2也后移
} else {
heroNode.next = head1;
heroNode = head1;
head1 = head1.next;
}
}
if (head1!=null){
heroNode.next=head1;
}
if (head2!=null){
heroNode.next=head2;
}
return temp.next;
}
双向链表
- 可以双向查找
- 可以自主删除节点
双向链表
-
遍历:和单链表一样,可以向前,也可以向后
-
添加:默认添加到最后
-
1 找到最后的节点temp
-
2 temp.next=newHeroNode
-
3 newHeroNode.pre=temp
-
-
修改:和单链表一样
-
删除:找到要删除节点temp
-
1 temp.pre.next=temp.next
-
2 temp.next.pre=temp.pre
-
删除
public class HeroNode2 {
public int no;
public String name;
public String nickname;
public HeroNode2 next;
public HeroNode2 pre;
public HeroNode2(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 DoubleLinkedList {
private HeroNode2 head = new HeroNode2(0, "", "");
public HeroNode2 getHead() {
return head;
}
//添加
public void add(HeroNode2 heroNode) {
HeroNode2 temp = head;
while (true) {
if (temp.next == null) {
break;
}
temp = temp.next;
}
temp.next = heroNode;
heroNode.pre=temp;
}
//按顺序添加
public void addByOrder(HeroNode2 heroNode) {
HeroNode2 temp = head;
boolean flag = false;
while (true) {
if (temp.next == null) {
break;
}
if (temp.next.no > heroNode.no) {
break;
} else if (temp.next.no == heroNode.no) {
flag = true;
break;
}
temp = temp.next;
}
if (flag) {
System.out.println("编号" + heroNode.no + "已存在");
} else {
heroNode.next = temp.next;
temp.next = heroNode;
}
}
//修改
public void update(HeroNode2 heroNode) {
if (head.next == null) {
System.out.println("链表为空");
return;
}
HeroNode2 temp = head.next;
boolean flag = false;
while (true) {
if (temp == null) {
break;
}
if (temp.no == heroNode.no) {
flag = true;
break;
}
temp = temp.next;
}
if (flag) { //找到了
temp.name = heroNode.name;
temp.nickname = heroNode.nickname;
} else {
System.out.println("没找到呢");
}
}
//删除
public void del(int no) {
if (head.next==null){
System.out.println("空");
return;
}
HeroNode2 temp = head.next;
boolean flag = false;
while (true) {
if (temp.next == null) {
break;
}
if (temp.no == no) {
flag = true;
break;
}
temp = temp.next;
}
if (flag) {
temp.next = temp.next.next;
if (temp.next!=null){ //不是最后一个节点时执行
temp.next.pre=temp.pre;
}
} else {
System.out.println(no+"不存在");
}
}
//遍历
public void list() {
if (head.next == null) {
System.out.println("链表为空");
return;
}
HeroNode2 temp = head;
while (true) {
if (temp.next == null) {
break;
}
System.out.println(temp.next);
temp = temp.next;
}
}
}
单向环形链表
约瑟夫问题:数到的那个人出队列
创建环形链表思路
添加小孩
出队列思路
出队列
节点类
public class Boy {
private int no;
private Boy next;
public Boy(int no){
this.no=no;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public Boy getNext() {
return next;
}
public void setNext(Boy next) {
this.next = next;
}
}
public class CircleSingleLinkedList {
private Boy first=null;
//添加nums:一共多少个boy
public void addBoy(int nums){
if (nums<1){
System.out.println("小孩个数不能小于1");
return;
}
Boy temp=null;
for (int i = 1; i <= nums; i++) {
Boy boy=new Boy(i);
if (i==1){
first=boy;
first.setNext(first); //形成环
temp=first;
}else {
temp.setNext(boy);
boy.setNext(first);
temp=boy;
}
}
}
//遍历
public void showBoy(){
if (first==null){
System.out.println("空");
return;
}
Boy temp=first;
while (true){
System.out.println("小孩:"+temp.getNo());
if (temp.getNext()==first){
break;
}
temp=temp.getNext();
}
}
//出圈(开始位置,数几下,多少个小孩)
public void countBoy(int startNo,int countNum,int nums){
if (first==null||startNo<1||startNo>nums){
System.out.println("参数错误");
return;
}
Boy temp=first;
while (true){ //让temp指向最后一个节点,即first的后面
if (temp.getNext()==first){
break;
}
temp=temp.getNext();
}
for (int i = 0; i < startNo-1; i++) { //定位到开始计数的位置
first=first.getNext();
temp=temp.getNext();
}
while (true){
if (temp==first){ //只一个
break;
}
for (int i = 0; i < countNum-1; i++) {
first=first.getNext();
temp=temp.getNext();
}
System.out.println("出圈小孩:"+first.getNo());
first=first.getNext(); //当前first为要出圈的孩子,移动后直接让temp的next指向它
temp.setNext(first);
}
System.out.println(first.getNo()+"为最后一个");
}
}