文章最后更新于 1414 天前,其中的信息可能已经过时。
本篇文章将详细讲述数据结构 线性表 章节的内容,没想到距离上次更新已经快两个礼拜了。
本教程编程语言采用 JAVA ,文章框架参考自 HUST数据结构PPT ,源码内容参考自 尚硅谷 JAVA 数据结构教程 。
线性表章节部分将简单讲述概念方面的问题,重点将放在具体的代码实现过程中。
线性表的定义
线性表的逻辑结构
- 线性表:由n(n≥0)个数据元素(a1,a2,...,an)构成的有限序列,记作: L=(a1,a2,...,an),a1称为首元素,an称为尾元素。
- 表长:线性表中数据元素的数目。
- 空表:不含数据元素的线性表。
在线性表L=(a1,a2,...,an)中:
- ai−1是ai的直接前驱(1<i<=n)
- ai+1是ai的直接后继(1<=i<n)
- a1没有前驱,an没有后继,ai有且仅有一个前驱和后继(1<i<n)
抽象数据类型线性表的定义
抽象类型的线性表主要定义几个属性和方法
InitList(&L)//构造空表 L。LengthList(L)//求表 L 的长度GetElem(L,i,&e)//取元素 ai,由 e 返回 aiPriorElem(L,ce,&pre_e)//求 ce 的前驱,由 pre_e 返回InsertElem(&L,i,e)//在元素 ai 之前插入新元素 eDeleteElem(&L,i)//删除第 i 个元素EmptyList(L)//判断 L 是否为空表
线性表的顺序表示(顺序存储结构)
顺序分配
- 定义:将线性表中的数据元素依次存放到计算机存储器中一组地址连续的存储单元中, 这种分配方式称为顺序分配或顺序映像。由此得到的存储结构称为顺序存储结构或向量(一维数组)。
- 线性表的几个参数
a:首元素的地址。sizeof(a[0]):线性表元素所占的储存空间的大小。sizeof(a[n]):线性表的长度。
寻址公式
顺序储存方式的地址查询与数组类似,故不再赘述,感兴趣的读者可以自己查询相关资料。
顺序储存结构的评价
- 是一种随机存取结构,存取任何元素的时间是一个常数,速度快。
- 结构简单,逻辑上相邻的元素在物理上也是相邻的。
- 不使用指针,节省存储空间。
- 插入和删除元素要移动大量元素,消耗大量时间。
- 需要一个连续的存储空间。
- 插入元素可能发生“溢出”。
- 自由区中的存储空间不能被其它数据占用(共享)。
稀疏数组的实现
- 书写思路:
二维数组转稀疏数组:
- 遍历原始二维数组得到,有效数字的个数
sum。 - 创建稀疏数组
int[sum+1][3]。 - 记录
chessRow和chessCol以及有效数字count。 - 遍历数组,为稀疏数组
sparseArr赋值。 - 返回稀疏数组。
- 遍历原始二维数组得到,有效数字的个数
稀疏数组转二维数组: 1. 创建原有大小的二维数组。 2. 将稀疏数组中的有效数字返回到原来的二维数组中。 3. 返回原来的二维矩阵。
-
代码实现:
查看代码实现
- 编写函数
JAVA 1package DataStructure;23public class SparseArray {4// 主函数:负责打印原始数组,转换后的稀疏数组,以及在转换回来的二维数组5public static void main(String[] args) {6int[][] chessArr = new int[11][11];7chessArr[1][2] = 1;8chessArr[2][3] = 2;9chessArr[5][5] = 5;10System.out.println("Raw array preview:");11printChessArray(chessArr);1213int[][] sparseArr = chessToSparse(chessArr);14System.out.println("chessArray to sparseArray:");15printChessArray(sparseArr);1617int[][] chessArr2 = sparseToChess(sparseArr);18System.out.println("sparseArray to chessArray:");19printChessArray(chessArr2);20}2122// 二维数组转稀疏数组:23// 1. 记录有效数字的个数sum24// 2. 创建稀疏数组int[sum+1][3]25// 3. 记录chessRow和chessCol以及有效数字count26// 4. 遍历数组,为稀疏数组sparseArr赋值27// 5. 返回稀疏数组28private static int[][] chessToSparse(int[][] chessArr) {29int sum = 0;30for (int[] row : chessArr) {31for (int chess : row) {32if (chess != 0) {33sum++;34}35}36}37int[][] sparseArr = new int[sum + 1][3];38int chessRow = chessArr.length;39int chessCol = 0;40int count = 0;41for (int i = 0; i < chessArr.length; i++) {42int[] rows = chessArr[i];43if (chessCol == 0) {44chessCol = rows.length;45}46for (int j = 0; j < rows.length; j++) {47int chess = rows[j];48if (chess == 0) {49continue;50}51count++;52sparseArr[count][0] = i;53sparseArr[count][1] = j;54sparseArr[count][2] = chess;55}56}57sparseArr[0][0] = chessRow;58sparseArr[0][1] = chessCol;59sparseArr[0][2] = sum;60return sparseArr;61}6263/*64* 1. 创建原有大小的二维数组65* 2. 将稀疏数组中的有效数字返回到原来的二维数组中66* 3. 返回原来的二维矩阵67*/68private static int[][] sparseToChess(int[][] sparseArr) {69int[][] chessArr = new int[sparseArr[0][0]][sparseArr[0][1]];70for (int i = 1; i < sparseArr.length; i++) {71int[] rows = sparseArr[i];72chessArr[rows[0]][rows[1]] = rows[2];73}74return chessArr;75}7677/*78* 通过两个for循环每行循环打印输出79*/80public static void printChessArray(int[][] chessArr) {81for (int[] row : chessArr) {82for (int data : row) {83System.out.printf("%-2d\t", data);84}85System.out.println("");86}87}88}- 输出结果
Terminal window 1Raw array preview:20 0 0 0 0 0 0 0 0 0 030 0 1 0 0 0 0 0 0 0 040 0 0 2 0 0 0 0 0 0 050 0 0 0 0 0 0 0 0 0 060 0 0 0 0 0 0 0 0 0 070 0 0 0 0 5 0 0 0 0 080 0 0 0 0 0 0 0 0 0 090 0 0 0 0 0 0 0 0 0 0100 0 0 0 0 0 0 0 0 0 0110 0 0 0 0 0 0 0 0 0 0120 0 0 0 0 0 0 0 0 0 013chessArray to sparseArray:1411 11 3151 2 1162 3 2175 5 518sparseArray to chessArray:190 0 0 0 0 0 0 0 0 0 0200 0 1 0 0 0 0 0 0 0 0210 0 0 2 0 0 0 0 0 0 0220 0 0 0 0 0 0 0 0 0 0230 0 0 0 0 0 0 0 0 0 0240 0 0 0 0 5 0 0 0 0 0250 0 0 0 0 0 0 0 0 0 0260 0 0 0 0 0 0 0 0 0 0270 0 0 0 0 0 0 0 0 0 0280 0 0 0 0 0 0 0 0 0 0290 0 0 0 0 0 0 0 0 0 0
线性表的链式存储结构
基本概念
- 链表是以 节点 的方式来存储,是 链式存储。
- 每个节点包含 data 域、next 域,next 域指向下一个节点。
- 链表还分:带头节点、不带头节点,根据实际需求来确定。
- 链表的各个节点 不一定是连续存储。
单链表
-
单链表的一般形式
-
单链表的代码实现(考虑一个这样的场景使用带头单链表实现P5R Phantom Thieves原教程是用的水浒传英雄的管理为啥我换成P5R呢?这是因为vscode Junit单元测试的时候输出中文乱码,我上网搜索了一下也没什么好的解决办法,索性全部用英文算了,正好最近我在打P5R就干脆拿来用了。的成员管理)
查看代码实现
- 完成对怪盗团成员的增删查改操作。
- 第一种方法:在添加成员时,直接添加到链表的尾部。
- 第二种方法:在添加成员时,根据序号将成员添加到指定的位置,如果有这个序号,则添加失败并给出提示。
- 构造链表节点的类
JAVA 1// 构造链表中的一个节点2class HeroNode {3// 定义4个基本属性4public int no; // 序号5public String name; // 名字6public String nickName; // 代号7public HeroNode next; // 指针域89// 书写构造函数10public HeroNode(int no, String name, String nickName) {11this.no = no;12this.name = name;13this.nickName = nickName;14}1516// 为方便重新打印重写toString函数17@Override18public String toString() {19return "HeroNode{" +20"no=" + no +21", name='" + name + '\'' +22", nickName='" + nickName + '\'' +23'}';24}25}- 单链表反转思路
- 定义一个新的
reverseHead节点。 - 从原链表中依次取出节点,并始终添加到
reverseHead的第一个节点。next = cur.next;cur.next = reverseHead.next;reverseHead.next = cur;cur = next; - 将
head节点的next指向reverseHead节点的next。
- 定义一个新的
- 构造链表类
JAVA 1// 单向链表节点的书写2class SingleLinkedList {3// 创建一个头节点4private HeroNode head = new HeroNode(0, "", "");56// 添加节点,将新加入的元素添加至链表的最后78public void add(HeroNode node) {9HeroNode temp = head;10while (true) {11if (temp.next == null) {12break;13}14temp = temp.next;15}16temp.next = node;17}1819// 打印链表中的数据20public void list() {21if (head.next == null) {22System.out.println("The linked list is empty!");23return;24}25HeroNode temp = head.next;26while (true) {27if (temp == null) {28break;29}30System.out.println(temp);31temp = temp.next;32}33}3435// 有序插入元素36public void addByOrder(HeroNode node) {37// 分为节点为空 大于 相等三种情况来书写函数38HeroNode temp = head; // 此处temp为辅助变量存放在栈中,指向堆空间的head39boolean exist = false;40while (true) {41if (temp.next == null) {42break;43}44if (temp.next.no > node.no) {45break;46}47if (temp.next.no == node.no) {48exist = true;49break;50}51temp = temp.next;52}53if (exist) {54System.out.printf("The phantom thief number %d to be inserted already exists and can't be added! \n",55node.no);56return;57}58node.next = temp.next;59temp.next = node;60}6162// 书写更新链表数据函数63public void update(HeroNode newNode) {64// 分为空和相等来区分计算65if (head.next == null) {66System.out.println("The linked list is empty!");67return;68}69HeroNode temp = head.next;70boolean exist = false;71while (true) {72if (temp == null) {73System.out.println("The linked list is empty!");74return;75}76if (temp.no == newNode.no) {77exist = true;78break;79}80temp = temp.next;81}82if (exist) {83temp.name = newNode.name;84temp.nickName = newNode.nickName;85} else {86System.out.printf("Phantom thief with number %d not found", newNode.no);87}88}8990// 删除节点操作91public void delete(int no) {92if (head.next == null) {93System.out.println("The linked list is empty!");94return;95}96HeroNode temp = head;97boolean exist = false; // 是否找到要删除的节点98while (true) {99if (temp.next == null) {100break;101}102if (temp.next.no == no) {103exist = true;104break;105}106temp = temp.next;107}108if (!exist) {109System.out.printf("Phantom thief with number %d not found! \n", no);110return;111}112// 删除操作113temp.next = temp.next.next;114}115116// 统计有效节点的个数,即遍历链表117public int length() {118HeroNode temp = head.next;119int num = 0;120if (head.next == null) {121return 0;122}123while (temp != null) {124num++;125temp = temp.next;126}127return num;128}129130// 查找单链表中的倒数第k个节点131public HeroNode findLastIndexNode(int index) {132// 通过size与index的大小来判断133int size = length();134if (size == 0) {135return null;136}137if (index <= 0 || index > size) {138return null;139}140HeroNode cur = head.next;141for (int i = 0; i < size - index; i++) {142cur = cur.next;143}144return cur;145}146147// 单链表的反转148public void reverse() {149// 始终添加到第一个节点150if (head.next == null) {151return;152}153HeroNode cur = head.next;154HeroNode next = null;155HeroNode reverseHead = new HeroNode(0, "", "");156157while (cur != null) {158next = cur.next; // 储存下一个元素的指针159cur.next = reverseHead.next;160reverseHead.next = cur;161cur = next;162}163head.next = reverseHead.next;164}165166public void reversePrint() {167if (head.next == null) {168System.out.println("The Linked List is Empty!");169return;170}171172Stack<HeroNode> stack = new Stack<>();173HeroNode cur = head.next;174// 遍历原链表,入栈175while (cur != null) {176stack.push(cur);177cur = cur.next;178}179// 打印栈180while (!stack.empty()) {181System.out.println(stack.pop());182}183}184}- 测试函数
JAVA 1public static void main(String[] args) {2SingleLinkedListDemo singleLinkedListDemo = new SingleLinkedListDemo();3singleLinkedListDemo.test1();4singleLinkedListDemo.test2();5}67public void test1() {8HeroNode hero1 = new HeroNode(1, "Amamiya Ren", "Joker");9HeroNode hero2 = new HeroNode(2, "Ryuji Sakamoto", "Skull");10HeroNode hero3 = new HeroNode(3, "Anne Takamaki", "Panther");11HeroNode hero4 = new HeroNode(4, "Yusuke Kitagawa", "Fox");12SingleLinkedList singleLinkedList = new SingleLinkedList();13singleLinkedList.add(hero1);14singleLinkedList.add(hero2);15singleLinkedList.add(hero3);16singleLinkedList.add(hero4);17singleLinkedList.list();18}1920public void test2() {21HeroNode hero1 = new HeroNode(1, "Amamiya Ren", "Joker");22HeroNode hero2 = new HeroNode(2, "Ryuji Sakamoto", "Skull");23HeroNode hero3 = new HeroNode(3, "Anne Takamaki", "Panther");24HeroNode hero4 = new HeroNode(4, "Yusuke Kitagawa", "Fox");2526SingleLinkedList singleLinkedList = new SingleLinkedList();2728singleLinkedList.addByOrder(hero4); // 添加顺序提前29singleLinkedList.addByOrder(hero2);30singleLinkedList.addByOrder(hero1);31singleLinkedList.addByOrder(hero3);32singleLinkedList.addByOrder(hero3);33singleLinkedList.list();34}3536private SingleLinkedList singleLinkedList;3738@Before39public void before() {40HeroNode hero1 = new HeroNode(1, "Amamiya Ren", "Joker");41HeroNode hero2 = new HeroNode(2, "Ryuji Sakamoto", "Skull");42HeroNode hero3 = new HeroNode(3, "Anne Takamaki", "Panther");43HeroNode hero4 = new HeroNode(4, "Yusuke Kitagawa", "Fox");4445singleLinkedList = new SingleLinkedList();4647singleLinkedList.addByOrder(hero4); // 添加顺序提前48singleLinkedList.addByOrder(hero2);49singleLinkedList.addByOrder(hero1);50singleLinkedList.addByOrder(hero3);51}5253@Test54public void updateTest() {55// 测试修改56System.out.println("Before update:");57singleLinkedList.list();58HeroNode hero4New = new HeroNode(4, "Yusuke Kitagawa-Test", "Fox-Test");59singleLinkedList.update(hero4New);6061System.out.println("After update:");62singleLinkedList.list();63}6465@Test66public void deleteTest() {67System.out.println("Before deletion:");68singleLinkedList.list();69singleLinkedList.delete(1);70singleLinkedList.delete(4);71System.out.println("After deletion:");72singleLinkedList.list();73}7475@Test76public void lengthTest() {77System.out.println(singleLinkedList.length());78singleLinkedList.delete(1);79System.out.println(singleLinkedList.length());80}8182@Test83public void findLastIndexNodeTest() {84singleLinkedList.list();85System.out.println("Search Test");86HeroNode lastIndexNode = singleLinkedList.findLastIndexNode(1);87System.out.println("Find the 1st last " + lastIndexNode);88lastIndexNode = singleLinkedList.findLastIndexNode(4);89System.out.println("Find the 4th last " + lastIndexNode);90lastIndexNode = singleLinkedList.findLastIndexNode(2);91System.out.println("Find the 2nd last " + lastIndexNode);92lastIndexNode = singleLinkedList.findLastIndexNode(5);93System.out.println("Find the 5th last " + lastIndexNode);94}9596@Test97public void reverseTest() {98System.out.println("Before reversal:");99singleLinkedList.list();100101singleLinkedList.reverse();102103System.out.println("After reversal:");104singleLinkedList.list();105}106107@Test108public void reversePrintTest() {109System.out.println("The data of the linked list:");110singleLinkedList.list();111System.out.println("Print in reverse order:");112singleLinkedList.reversePrint();113}- 输出结果
Terminal window 1Test1:2HeroNode{no=1, name='Amamiya Ren', nickName='Joker'}3HeroNode{no=2, name='Ryuji Sakamoto', nickName='Skull'}4HeroNode{no=3, name='Anne Takamaki', nickName='Panther'}5HeroNode{no=4, name='Yusuke Kitagawa', nickName='Fox'}67Test2:8The phantom thief number 3 to be inserted already exists and can't be added!9HeroNode{no=1, name='Amamiya Ren', nickName='Joker'}10HeroNode{no=2, name='Ryuji Sakamoto', nickName='Skull'}11HeroNode{no=3, name='Anne Takamaki', nickName='Panther'}12HeroNode{no=4, name='Yusuke Kitagawa', nickName='Fox'}1314updateTest:15Before update:16HeroNode{no=1, name='Amamiya Ren', nickName='Joker'}17HeroNode{no=2, name='Ryuji Sakamoto', nickName='Skull'}18HeroNode{no=3, name='Anne Takamaki', nickName='Panther'}19HeroNode{no=4, name='Yusuke Kitagawa', nickName='Fox'}20After update:21HeroNode{no=1, name='Amamiya Ren', nickName='Joker'}22HeroNode{no=2, name='Ryuji Sakamoto', nickName='Skull'}23HeroNode{no=3, name='Anne Takamaki', nickName='Panther'}24HeroNode{no=4, name='Yusuke Kitagawa-Test', nickName='Fox-Test'}2526deleteTest:27Before deletion:28HeroNode{no=1, name='Amamiya Ren', nickName='Joker'}29HeroNode{no=2, name='Ryuji Sakamoto', nickName='Skull'}30HeroNode{no=3, name='Anne Takamaki', nickName='Panther'}31HeroNode{no=4, name='Yusuke Kitagawa', nickName='Fox'}32After deletion:33HeroNode{no=2, name='Ryuji Sakamoto', nickName='Skull'}34HeroNode{no=3, name='Anne Takamaki', nickName='Panther'}3536lengthTest:3743833940findLastIndexNodeTest:41HeroNode{no=1, name='Amamiya Ren', nickName='Joker'}42HeroNode{no=2, name='Ryuji Sakamoto', nickName='Skull'}43HeroNode{no=3, name='Anne Takamaki', nickName='Panther'}44HeroNode{no=4, name='Yusuke Kitagawa', nickName='Fox'}45Search Test46Find the 1st last HeroNode{no=4, name='Yusuke Kitagawa', nickName='Fox'}47Find the 4th last HeroNode{no=1, name='Amamiya Ren', nickName='Joker'}48Find the 2nd last HeroNode{no=3, name='Anne Takamaki', nickName='Panther'}49Find the 5th last null5051reverseTest:52Before reversal:53HeroNode{no=1, name='Amamiya Ren', nickName='Joker'}54HeroNode{no=2, name='Ryuji Sakamoto', nickName='Skull'}55HeroNode{no=3, name='Anne Takamaki', nickName='Panther'}56HeroNode{no=4, name='Yusuke Kitagawa', nickName='Fox'}57After reversal:58HeroNode{no=4, name='Yusuke Kitagawa', nickName='Fox'}59HeroNode{no=3, name='Anne Takamaki', nickName='Panther'}60HeroNode{no=2, name='Ryuji Sakamoto', nickName='Skull'}61HeroNode{no=1, name='Amamiya Ren', nickName='Joker'}6263reversePrintTest:64The data of the linked list:65HeroNode{no=1, name='Amamiya Ren', nickName='Joker'}66HeroNode{no=2, name='Ryuji Sakamoto', nickName='Skull'}67HeroNode{no=3, name='Anne Takamaki', nickName='Panther'}68HeroNode{no=4, name='Yusuke Kitagawa', nickName='Fox'}69Print in reverse order:70HeroNode{no=4, name='Yusuke Kitagawa', nickName='Fox'}71HeroNode{no=3, name='Anne Takamaki', nickName='Panther'}72HeroNode{no=2, name='Ryuji Sakamoto', nickName='Skull'}73HeroNode{no=1, name='Amamiya Ren', nickName='Joker'}
双向链表
双向链表节点定义与单向链表大致相同,只不过多了一个指向前一个节点的指针域。
-
双向链表相关函数的实现思路 基本实现思路与单向链表相同,可在前者的基础上作出修改
-
双向链表的代码实现
查看代码实现
- 函数编写
JAVA 1package DataStructure.DoubleLinkedListPackage;23class HeroNode {4// 基本的元素与构造元素与单链表基本相同,主要多了一个pre域5public int no;6public String name;7public String nickName;8public HeroNode next;9public HeroNode pre;1011public HeroNode(int no, String name, String nickName) {12this.no = no;13this.name = name;14this.nickName = nickName;15}1617// 重写函数也基本一致18@Override19public String toString() {20return "HeroNode{" +21"no=" + no +22", name='" + name + '\'' +23", nickName='" + nickName + '\'' +24'}';25}26}2728// 对双向链表类进行编写29public class DoubleLinkedList {30// 同样的,初始化一个最初的节点31private HeroNode head = new HeroNode(0, "", "");3233// 将节点添加到链表的尾部34public void add(HeroNode node) {35HeroNode temp = head;36while (temp.next != null) {37temp = temp.next;38}39temp.next = node;40node.pre = temp;41}4243// 修改值的函数,与单向链表基本相同44public void update(HeroNode newNode) {45if (head.next == null) {46System.out.println("The linked list is empty!");47return;48}4950HeroNode temp = head;51boolean exist = false;52while (true) {53if (temp.next == null) {54break;55}56if (temp.no == newNode.no) {57exist = true;58break;59}60temp = temp.next;61}62if (exist) {63temp.name = newNode.name;64temp.nickName = newNode.nickName;65} else {66System.out.printf("no element found with number: %d !", newNode.no);67}68}6970// 删除函数与单向链表的思路基本相同,需要注意删除的操作以及最后一位元素的删除处理71public void delete(int no) {72if (head.next == null) {73System.out.println("The linked list is empty!");74return;75}7677HeroNode temp = head.next;78boolean exist = false;79while (true) {80if (temp.next == null) {81break;82}83if (temp.no == no) {84exist = true;85break;86}87temp = temp.next;88}89if (!exist) {90System.out.printf("no element found with number: %d !", no);91return;92}93if (temp.next != null) {94temp.next.pre = temp.pre;95}96temp.pre.next = temp.next;97}9899// 打印链表100public void print() {101if (head.next == null) {102System.out.println("The linked list is empty!");103return;104}105HeroNode cur = head.next;106while (cur != null) {107System.out.println(cur);108cur = cur.next;109}110}111112// 按序添加113public void addByOrder(HeroNode node) {114HeroNode temp = head;115boolean exist = false; // 添加的节点是否已经在链表中存在116117while (true) {118// 已到列表尾部119if (temp.next == null) {120break;121}122// 已找到123if (temp.next.no > node.no) {124break;125}126127// 已存在该编号128if (temp.next.no == node.no) {129exist = true;130break;131}132temp = temp.next;133}134if (exist) {135System.out.printf("The phantom thief number %d to be inserted already exists and can't be added! \n", node.no);136return;137}138139// 把节点插入到 temp 和 temp.next 之间140// temp -> node -> temp.next141node.next = temp.next;142temp.next = node;143node.pre = temp.next.pre;144temp.next.pre = node;145}146}- 测试用例
JAVA 1package DataStructure.DoubleLinkedListPackage;23import org.junit.Before;4import org.junit.Test;56/**7* 双向链表测试8*/9public class DoubleLinkedListTest {10DoubleLinkedList doubleLinkedList;1112@Before13public void before() {14HeroNode hero1 = new HeroNode(1, "Amamiya Ren", "Joker");15HeroNode hero2 = new HeroNode(2, "Ryuji Sakamoto", "Skull");16HeroNode hero3 = new HeroNode(3, "Anne Takamaki", "Panther");17HeroNode hero4 = new HeroNode(4, "Yusuke Kitagawa", "Fox");1819// 测试新增20doubleLinkedList = new DoubleLinkedList();21doubleLinkedList.add(hero1);22doubleLinkedList.add(hero4);23doubleLinkedList.add(hero2);24doubleLinkedList.add(hero3);25}2627@Test28public void addTest() {29// before 中已测试30}3132/**33* 更新测试34*/35@Test36public void updateTest() {37System.out.println("Before update:");38doubleLinkedList.print();39HeroNode hero4New = new HeroNode(4, "Yusuke Kitagawa-Test", "Fox-Test");40doubleLinkedList.update(hero4New);41System.out.println("After update:");42doubleLinkedList.print();43}4445/**46* 删除测试47*/48@Test49public void deleteTest() {50System.out.println("Before deletion:");51doubleLinkedList.print();52doubleLinkedList.delete(1);53doubleLinkedList.delete(4);54doubleLinkedList.delete(3);55System.out.println("After deletion:");56doubleLinkedList.print();57}58@Test59public void addByOrderTest() {60HeroNode hero1 = new HeroNode(1, "Amamiya Ren", "Joker");61HeroNode hero2 = new HeroNode(2, "Ryuji Sakamoto", "Skull");62HeroNode hero3 = new HeroNode(3, "Anne Takamaki", "Panther");63HeroNode hero4 = new HeroNode(4, "Yusuke Kitagawa", "Fox");6465// 测试新增66doubleLinkedList = new DoubleLinkedList();67doubleLinkedList.addByOrder(hero1);68doubleLinkedList.addByOrder(hero4);69doubleLinkedList.addByOrder(hero2);70doubleLinkedList.addByOrder(hero3);71doubleLinkedList.addByOrder(hero3);72doubleLinkedList.print();7374}75}- 输出结果
Terminal window 1Before update:2HeroNode{no=1, name='Amamiya Ren', nickName='Joker'}3HeroNode{no=4, name='Yusuke Kitagawa', nickName='Fox'}4HeroNode{no=2, name='Ryuji Sakamoto', nickName='Skull'}5HeroNode{no=3, name='Anne Takamaki', nickName='Panther'}6After update:7HeroNode{no=1, name='Amamiya Ren', nickName='Joker'}8HeroNode{no=4, name='Yusuke Kitagawa-Test', nickName='Fox-Test'}9HeroNode{no=2, name='Ryuji Sakamoto', nickName='Skull'}10HeroNode{no=3, name='Anne Takamaki', nickName='Panther'}111213Before deletion:14HeroNode{no=1, name='Amamiya Ren', nickName='Joker'}15HeroNode{no=4, name='Yusuke Kitagawa', nickName='Fox'}16HeroNode{no=2, name='Ryuji Sakamoto', nickName='Skull'}17HeroNode{no=3, name='Anne Takamaki', nickName='Panther'}18no element found with number: 3 !After deletion:19HeroNode{no=2, name='Ryuji Sakamoto', nickName='Skull'}20HeroNode{no=3, name='Anne Takamaki', nickName='Panther'}212223The phantom thief number 3 to be inserted already exists and can't be added!24HeroNode{no=1, name='Amamiya Ren', nickName='Joker'}25HeroNode{no=2, name='Ryuji Sakamoto', nickName='Skull'}26HeroNode{no=3, name='Anne Takamaki', nickName='Panther'}27HeroNode{no=4, name='Yusuke Kitagawa', nickName='Fox'}
循环链表
循环链表的讲解将与约瑟夫问题结合实现
-
实现基本思路
- 先构成一个有
n个节点的单循环链表。 - 然后由
k节点起从1开始计数。 - 计数到
m时,对应节点从链表中删除,然后从下一个节点又从1开始计数
- 先构成一个有
-
代码实现
查看代码实现
- 函数编写
JAVA 1package DataStructure;23// 构造孩子节点4class Boy {5int no;6Boy next;78public Boy(int no) {9this.no = no;10}11}1213public class CircleSingleLinkedList {14Boy first = null;1516/*17* 添加节点18* 1. 检查num的输入是否在1及以上19* 2. 通过cur指针循环前移,创建环形单链表20* 3. 第一个节点为空的时候需要特殊考虑21* 4. 添加节点的顺序为:cur指向boy,boy指向first,cur指针指向boy22*/23public void add(int num) {24if (num < 1) {25System.out.println("Please input a number greater than 1! ");26return;27}28Boy cur = null;29for (int i = 1; i <= num; i++) {30Boy boy = new Boy(i);31if (first == null) {32first = boy;33boy.next = first;34cur = first;35continue;36}37cur.next = boy;38boy.next = first;39cur = boy;40}41}4243/**44* 打印队列45*/46public void print() {47if (first == null) {48System.out.println("Queue empty!");49return;50}51Boy cur = first;52while (true) {53System.out.printf("Child number %d \n", cur.no);54cur = cur.next;55// 如果和 first 一致,则标识已经走了一圈了56if (cur == first) {57return;58}59}60}6162public void countBoy(int startNo, int countNum, int nums) {63// 进行一个数据校验64if (first == null || // 环形队列没有构建65countNum < 1 || // 每次至少数 1 下66startNo > nums // 开始小孩不能大于参与游戏的人数67) {68System.out.println("The parameter is incorrect.Please re-enter it!");69}70// 1. 初始化辅助变量到 first 的后面71Boy helper = first;72// 当 helper.next = first 时,就说明已经定位了73while (helper.next != first) {74helper = helper.next;75}7677// 2. 定位 first 和 helper 在 startNo 位置78// first 初始在最开始,移动到 startNo 位置79for (int i = 0; i < startNo - 1; i++) {80helper = first;81first = first.next;82}8384// 为了测试方便,这里添加一个日志输出85System.out.printf("Localize: %d \n", startNo);86print();8788// 3. 开始报数 和 出圈89while (true) {90// 当队列中只剩下一个人的时候,跳出循环,因为最后一个必然是他自己出队列91if (helper == first) {92break;93}94// 报数:每次报数 m-195for (int i = 0; i < countNum - 1; i++) {96// 因为 helper 永远在 first 后面,只要在 first 移动时,指向 first 原来所在的位置即可97helper = first;98first = first.next;99}100// 出圈101System.out.printf("The number of the child out of the circle %d \n", first.no);102first = first.next; // first 重置为下一次报数的小孩节点上103helper.next = first; // helper 重置为下一次报数的小孩节点上104}105System.out.printf("The number of the last child left %d \n", first.no);106}107}- 测试用例
JAVA 1package DataStructure;23import org.junit.Test;45public class JosepfuTest {6@Test7public void addTest() {8CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();9circleSingleLinkedList.add(5);10circleSingleLinkedList.print();11}1213@Test14public void countBoy() {15CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();16circleSingleLinkedList.add(5);17System.out.println("Build Circle Queue:");18circleSingleLinkedList.print();1920// 开始玩游戏21// 正确的输出顺序为:2、4、1、5、322circleSingleLinkedList.countBoy(1, 2, 5);23}24}- 输出结果
Terminal window 1Child number 12Child number 23Child number 34Child number 45Child number 567Build Circle Queue:8Child number 19Child number 210Child number 311Child number 412Child number 513Localize: 114Child number 115Child number 216Child number 317Child number 418Child number 5
- 文章作者:
- 希亚的西红柿
- 版权声明:
- 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自希亚的西红柿のBlog!
相关推荐
评论
评论加载中…





