Chapter 3 链表

文章目录

  • Chapter 3 链表
    • 3.1 链表
      • 3.1.1 链表介绍
      • 3.1.2 链表CRUD
      • 3.1.3 单链表题目
    • 3.2 双向链表
      • 3.2.1 双向链表介绍
      • 3.2.2 双向链表CRUD
    • 3.3 循环链表和约瑟夫问题
      • 3.3.1 单向环形链表的应用场景
      • 3.3.2 单向环形链表的构建与遍历
      • 3.3.3 约瑟夫问题实现

3.1 链表

3.1.1 链表介绍

  • 链表以结点方式存储,存储空间不一定连续
  • 每个结点包含数据域和指针域
  • 每个结点不一定是连续存储
  • 链表有带头结点和不带头结点的,根据需求确定使用哪一种

3.1.2 链表CRUD

1、按输入顺序建立一个学生链表

/*** The type Single linked list.* @author ybs*/
public class SingleLinkedListTest {public static void main(String[] args) {StudentNode s1 = new StudentNode(1, "jack", "c1");StudentNode s2 = new StudentNode(2, "york", "c1");StudentNode s3 = new StudentNode(3, "peter", "c1");StudentNode s4 = new StudentNode(4, "marry", "c1");SingleLinkedList singleLinkedList = new SingleLinkedList();singleLinkedList.addNode(s1);singleLinkedList.addNode(s2);singleLinkedList.addNode(s3);singleLinkedList.addNode(s4);singleLinkedList.listLinkedList();}
}class SingleLinkedList{/*** head 头结点*/public StudentNode head = new StudentNode(0, "", "");public void addNode(StudentNode student){StudentNode temp = head;//找到最后一个结点while(true){if(temp.next==null) {break;}temp = temp.next;}temp.next=student;}public void listLinkedList(){if(head.next==null){System.out.println("空链表");return;}StudentNode temp = head.next;while(true){if(temp==null){break;}System.out.println(temp);temp = temp.next;}}}class StudentNode{public int stuNo;public String stuName;public String stuClass;public StudentNode next;public StudentNode(int stuNo, String stuName, String stuClass) {this.stuNo = stuNo;this.stuName = stuName;this.stuClass = stuClass;}@Overridepublic String toString() {return "Student{" +"stuNo=" + stuNo +", stuName='" + stuName + '\'' +", stuClass='" + stuClass + '\'' +'}';}
}

2、按照编号顺序建立一个学生表

/*** The type Single linked list.* @author ybs*/
public class SingleLinkedListTest {public static void main(String[] args) {StudentNode s1 = new StudentNode(1, "jack", "c1");StudentNode s2 = new StudentNode(2, "york", "c1");StudentNode s3 = new StudentNode(3, "peter", "c1");StudentNode s4 = new StudentNode(4, "marry", "c1");SingleLinkedList singleLinkedList = new SingleLinkedList();
/*        singleLinkedList.addNode(s1);singleLinkedList.addNode(s2);singleLinkedList.addNode(s3);singleLinkedList.addNode(s4);*/singleLinkedList.addNodeByOrder(s3);singleLinkedList.addNodeByOrder(s1);singleLinkedList.addNodeByOrder(s2);singleLinkedList.addNodeByOrder(s4);singleLinkedList.addNodeByOrder(s4);singleLinkedList.listLinkedList();}
}class SingleLinkedList{/*其他同1*///按照序号加入链表public void addNodeByOrder(StudentNode student){StudentNode temp = head;boolean flag = false;//判断是否有重复的序号//找到插入位置while(true){if(temp.next==null){break;}if(temp.next.stuNo > student.stuNo){break;}else if(temp.next.stuNo == student.stuNo){flag=true;break;}temp = temp.next;}if(flag){System.out.printf("重复序号%d,无法加入\n",student.stuNo);}else{student.next = temp.next;temp.next = student;}}}class StudentNode{/*同1*/
}

3、修改链表

/*** The type Single linked list.* @author ybs*/
public class SingleLinkedListTest {public static void main(String[] args) {StudentNode s1 = new StudentNode(1, "jack", "c1");StudentNode s2 = new StudentNode(2, "york", "c1");StudentNode s3 = new StudentNode(3, "peter", "c1");StudentNode s4 = new StudentNode(4, "marry", "c1");SingleLinkedList singleLinkedList = new SingleLinkedList();
/*        singleLinkedList.addNode(s1);singleLinkedList.addNode(s2);singleLinkedList.addNode(s3);singleLinkedList.addNode(s4);*/singleLinkedList.addNodeByOrder(s3);singleLinkedList.addNodeByOrder(s1);singleLinkedList.addNodeByOrder(s2);singleLinkedList.addNodeByOrder(s4);singleLinkedList.addNodeByOrder(s4);singleLinkedList.listLinkedList();singleLinkedList.updateNode(new StudentNode(3, "sam", "c2"));singleLinkedList.listLinkedList();}
}class SingleLinkedList{/*其他同1*///修改结点//根据要修改的结点newStudent的stuNo编号查找修改public void updateNode(StudentNode newStudent){if(head.next==null){System.out.println("空链表");return;}StudentNode temp = head.next;boolean flag = false;//判断是否找到序号while(true){if(temp==null){break;}if(temp.stuNo== newStudent.stuNo){flag=true;break;}temp = temp.next;}if(flag){temp.stuName = newStudent.stuName;temp.stuClass = newStudent.stuClass;}else{System.out.printf("未找到序号%d的学生",newStudent.stuNo);}}}class StudentNode{/*同1*/
}

3.1.3 单链表题目

1、求单链表的有效结点个数

//获取单链表的长度
public static int getLength(StudentNode head){if(head.next == null){return 0;}int length = 0;StudentNode temp = head.next;while(temp!=null){length++;temp=temp.next;}return length;
}

2、查找单链表倒数第k个结点

//获取单链表倒数第index个元素
//1.先得到单链表目前的长度size  2.从头遍历(size-index)个
public static StudentNode getLastIndexNode(StudentNode head, int index){if(head.next==null || index <= 0 || index > getLength(head)){return null;}int size = getLength(head);StudentNode temp = head.next;for(int i=0;i<(size-index);++i){temp = temp.next;}return temp;
}

3、单链表反转

//反转单链表
//1.设置一个新的头结点reverseHead    2.遍历链表,每次将结点放到reverseHead的最前端  3.将原来的头结点指向新的头结点的下一个结点
public static void reverseLinkedList(StudentNode head){//如果为空或者只有一个结点就直接返回if(head.next==null||head.next.next==null){return;}StudentNode temp = head.next;//循环指针StudentNode next = null;//指向当前循环下一个的指针StudentNode reverseHead = new StudentNode(0, "", "");//新的头结点while(temp!=null){next = temp.next;temp.next = reverseHead.next;reverseHead.next = temp;temp = next;}head.next = reverseHead.next;
}

4、从尾到头打印单链表

//从尾到头打印单链表
public void reverseListLinkedList(){if(head.next==null){return;}Stack<StudentNode> stack = new Stack<>();StudentNode temp = head.next;while(temp!=null){stack.push(temp);temp = temp.next;}while(stack.size()>0){System.out.println(stack.pop());}
}

5、合并两个有序单链表,合并之后依然有序

//合并两个有序单链表,合并依然有序
public static SingleLinkedList mergeLinkedList(SingleLinkedList sglList1, SingleLinkedList sglList2){SingleLinkedList singleLinkedList = new SingleLinkedList();StudentNode list1 = sglList1.head;StudentNode list2 = sglList2.head;StudentNode newList = new StudentNode(0, "", "");if(list1.next==null){newList.next = list2.next;singleLinkedList.head = newList;return singleLinkedList;}else if(list2.next==null){newList.next  = list1.next;singleLinkedList.head = newList;return singleLinkedList;}StudentNode temp1 = list1.next;StudentNode temp2 = list2.next;StudentNode tempNewList = newList;while (temp1!=null && temp2!=null){if(temp1.stuNo< temp2.stuNo){tempNewList.next=temp1;tempNewList = tempNewList.next;temp1 = temp1.next;}else{tempNewList.next=temp2;tempNewList = tempNewList.next;temp2 = temp2.next;}}if (temp1==null){tempNewList.next = temp2;}else{tempNewList.next = temp1;}singleLinkedList.head = newList;return singleLinkedList;
}

3.2 双向链表

3.2.1 双向链表介绍

  • 单链表只能往一个方向查找,双向链表可以向前向后查找
  • 单链表的结点不能自我删除,双链表的结点可以

3.2.2 双向链表CRUD

public class DoubleLinkedListTest {public static void main(String[] args) {StudentNode2 s1 = new StudentNode2(1, "jack", "c1");StudentNode2 s2 = new StudentNode2(2, "york", "c1");StudentNode2 s3 = new StudentNode2(3, "peter", "c1");StudentNode2 s4 = new StudentNode2(4, "marry", "c1");StudentNode2 s5 = new StudentNode2(5, "sam", "c2");DoubleLinkedList doubleLinkedList = new DoubleLinkedList();doubleLinkedList.addNode(s1);doubleLinkedList.addNode(s2);doubleLinkedList.addNode(s3);doubleLinkedList.addNode(s4);doubleLinkedList.addNode(s5);//doubleLinkedList.updateNode(new StudentNode2(3, "peter", "c2"));//doubleLinkedList.deleteNode(3);doubleLinkedList.listLinkedList();}
}class DoubleLinkedList{/*** head 头结点*/public StudentNode2 head = new StudentNode2(0, "", "");public void addNode(StudentNode2 student){StudentNode2 temp = head;//找到最后一个结点while(true){if(temp.next==null) {break;}temp = temp.next;}temp.next=student;student.previou = temp;}public void listLinkedList(){if(head.next==null){System.out.println("空链表\n");return;}StudentNode2 temp = head.next;while(true){if(temp==null){break;}System.out.println(temp);temp = temp.next;}}//删除结点//根据编号删除结点public void deleteNode(int stuNo){StudentNode2 temp = head.next;boolean flag = false;//判断是否找到该结点while(true){if(temp==null){break;}if(temp.stuNo==stuNo){flag=true;break;}temp = temp.next;}if(flag){temp.next.previou = temp.previou;temp.previou.next = temp.next;}else{System.out.printf("未找到编号为%d的结点",stuNo);}}//修改结点//根据要修改的结点newStudent的stuNo编号查找修改public void updateNode(StudentNode2 newStudent){if(head.next==null){System.out.println("空链表");return;}StudentNode2 temp = head.next;boolean flag = false;//判断是否找到序号while(true){if(temp==null){break;}if(temp.stuNo== newStudent.stuNo){flag=true;break;}temp = temp.next;}if(flag){temp.stuName = newStudent.stuName;temp.stuClass = newStudent.stuClass;}else{System.out.printf("未找到序号%d的学生",newStudent.stuNo);}}
}class StudentNode2 {public int stuNo;public String stuName;public String stuClass;public StudentNode2 next;public StudentNode2 previou;public StudentNode2(int stuNo, String stuName, String stuClass) {this.stuNo = stuNo;this.stuName = stuName;this.stuClass = stuClass;}@Overridepublic String toString() {return "Student{" +"stuNo=" + stuNo +", stuName='" + stuName + '\'' +", stuClass='" + stuClass + '\'' +'}';}
}

3.3 循环链表和约瑟夫问题

3.3.1 单向环形链表的应用场景

Josephu(约瑟夫、约瑟夫环)问题

3.3.2 单向环形链表的构建与遍历

1、构建思路

先创建一个first结点,并形成环形,每增加一个新的结点,就把该结点加入已有的环形链表中

2、遍历思路

先让一个辅助指针cur指向first,然后通过while遍历环形链表,当cur.next=first时结束

3、实现

public class JosephuProblemTest {public static void main(String[] args) {CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();circleSingleLinkedList.addGirl(5);circleSingleLinkedList.listGirls();}
}class CircleSingleLinkedList{public Girl first = null;public CircleSingleLinkedList(){}public void addGirl(int num){if (num<1){System.out.println("num不符合");return;}Girl curGirl = null;for(int i=1;i<=num;++i){Girl girl = new Girl(i);if (i==1){first = girl;curGirl = first;girl.setNext(first);}else{curGirl.setNext(girl);girl.setNext(first);curGirl = girl;}}}public void listGirls(){if (first==null){System.out.println("空表");return;}Girl curGirl = first;while(true){System.out.println("Girl "+curGirl.getId());if(curGirl.getNext()==first){break;}curGirl = curGirl.getNext();}}
}class Girl{private int id;private Girl next;public Girl(int id) {this.id = id;}public int getId() {return id;}public void setId(int id) {this.id = id;}public Girl getNext() {return next;}public void setNext(Girl next) {this.next = next;}
}

3.3.3 约瑟夫问题实现

思路:n 一共有几个人; k 表示从第k个人开始报数; m 表示每次数几个数

  1. 需要创建一个辅助指针helper,事先应该指向环形链表的最后一个结点
  2. 报数前,让 first 和 helper 同时移动 k-1 次
  3. 报数时,让 first 和 helper 同时移动 m-1 次
  4. 此时 first 指向的结点出圈
/*** 约瑟夫问题实现** @param startId  表示从第几个开始数数* @param countNum 表示每次数到几出圈* @param sumNum   表示最初有多少小孩*/
public void josephuCountGirl(int startId,int countNum,int sumNum){if (first==null || startId < 1 || startId > sumNum){System.out.println("链表或输入异常");return;}Girl helper = first;//将helper移动到最后一个结点while(true){if(helper.getNext()==first){break;}helper = helper.getNext();}//将first移动到起始结点,helper移动到first的前一个结点for(int i=0;i<startId-1;++i){first = first.getNext();helper = helper.getNext();}//数数,出圈while(true){//first==helper时,说明圈内只剩下一个结点,跳出if (first==helper){break;}//数数for (int i=0;i<countNum-1;++i){first = first.getNext();helper = helper.getNext();}System.out.printf("%d出圈\n",first.getId());first = first.getNext();//first移动到出圈结点的下一个结点helper.setNext(first);//helper.next指向first,出圈结点被移出链表}System.out.printf("最后剩下%d\n",first.getId());
}

【自学笔记】尚硅谷数据结构与算法Chapter 3 链表相关推荐

  1. 【自学笔记】尚硅谷数据结构与算法Chapter 1 数据结构与算法概述

    Chapter 1 数据结构与算法概述 文章目录 Chapter 1 数据结构与算法概述 1.1.1 数据结构和算法的关系 1.2.1 线性结构 1.2.2 非线性结构 尚硅谷数据结构B站学习视频地址 ...

  2. 【自学笔记】尚硅谷数据结构与算法Chapter 5 递归

    Chapter 5 递归 文章目录 Chapter 5 递归 5.1 递归概念 5.2 递归的调用机制 5.3 迷宫问题(回溯) 5.4 八皇后问题(回溯) 5.1 递归概念 递归好就是方法自己调用自 ...

  3. 【自学笔记】尚硅谷数据结构与算法Chapter 4 栈

    Chapter 4 栈 文章目录 Chapter 4 栈 4.1 栈 4.1.1 栈的介绍 4.1.2 数组模拟栈 4.1.3 练习:用链表模拟栈 4.1.4 例题:用栈完成表达式计算(中缀表达式) ...

  4. 【自学笔记】尚硅谷数据结构与算法Chapter 2 稀疏数组和队列

    Chapter 2 稀疏数组和队列 文章目录 Chapter 2 稀疏数组和队列 2.1 稀疏数组 2.1.1 基本介绍 2.1.2 应用案例 2.2 队列 2.2.1 队列介绍 2.2.2 用数组模 ...

  5. 尚硅谷数据结构与算法(Java)--17--归并排序

    :归并排序 归并排序是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用. 将已有序的子序列合并,得到完全有序的序列:即先使每个 ...

  6. 尚硅谷数据结构和算法01-数据结构介绍和稀疏数组

    文章目录 一.数据结构组成 1.线性结构 2.非线性结构 二.稀疏数组 1.应用场景: 2.稀疏数组转换的思路分析 3.代码实现 补充: %d\t 一.数据结构组成 包括:线性结构和非线性结构 1.线 ...

  7. 电商数仓描述_笔记-尚硅谷大数据项目数据仓库-电商数仓V1.2新版

    架构 项目框架 数仓架构 存储压缩 Snappy与LZO LZO安装: 读取LZO文件时,需要先创建索引,才可以进行切片. 框架版本选型Apache:运维麻烦,需要自己调研兼容性. CDH:国内使用最 ...

  8. 【笔记】Java数据结构与算法

    [笔记]Java数据结构与算法 文章目录 [笔记]Java数据结构与算法 1.八大排序应用场景 2.未完待续-- 1.八大排序应用场景 冒泡排序:优化后的冒泡排序可用于当数据已经基本有序,且数据量较小 ...

  9. MySQL学习笔记——尚硅谷李玉婷经典版MySQL基础笔记(一)

    MySQL学习笔记--尚硅谷李玉婷经典版MySQL基础笔记(一) MySQL学习笔记目录 MySQL学习笔记--尚硅谷李玉婷经典版MySQL基础笔记(一) 一.基础知识 1.MySQL的语法规范 2. ...

最新文章

  1. Docker compose多容器管理
  2. db2 日期英式写法_《学霸英语》16:美国人和英国人“表达日期”,差距竟然这么大!...
  3. 如果在安装32位oracle 客户端组件时的情况下以64位模式运行,将出现问题
  4. 两个排序数组中求第k大的sum(a+b)
  5. mysqldump主要参数探究
  6. react中使用构建缓存_完整的React课程:如何使用React构建聊天室应用
  7. wamp替换mysql_将wamp集成的mysql替换成安装版的
  8. js如何监听元素事件是否被移除_JS移除事件监听的方法 .removeEventListener( )
  9. python 发红包import random用redenv_python 常用模块之random,os,sys 模块
  10. 经典案例之MouseJack
  11. c语言贪吃蛇毕业论文,毕业论文c语言贪吃蛇
  12. 100个优秀安全测试工具
  13. 什么是线程安全性,如何保证线程安全*
  14. 电脑计算机网络都打不开怎么办,电脑网页打不开怎么回事的常规处理方法
  15. Qt for Mac苹果开发中,使用Apple Developer文档
  16. 科技巨头们在SaaS市场“雷声大雨点小”背后的症结
  17. 浅识Flutter 基本组件之showDatePicker方法
  18. Pr 入门教程之如何创建新序列?
  19. 全国职业院校技能大赛网络搭建与应用赛项——云平台底层的一些命令
  20. 美国买车维权,是怎样告别“按‘闹’分配”的?

热门文章

  1. Python实现节假日及按规定的加班日期
  2. 床长人工智能教程 - 神经网络是如何进行预测的?
  3. 分析图第二讲导出图片和后期PS5.12
  4. MATLAB:图片缩放
  5. 外汇救市无异加印人民币
  6. WordPress底部添加备案信息小技巧
  7. 如何成为虾皮的优选卖家-扬帆际海
  8. 有关lpk.dll病毒的清除方法
  9. FB、WhatsApp群发消息在2022年到底有多热门?
  10. 上传pdf文件转图片翻页小工具,遇到JSP form中type=file的文件上传及后台Part处理问题(后台取值为null)