数据结构 -线性结构 ->单向链表
定义:链表就是由包含值域和next域的多个节点组成,其中由头节点出发连接下一个节点直到最后,
链表的逻辑储存结构和实际储存结构是不一样的,逻辑结构中每个节点都是按顺序连接,实际则不是,主要根据节点的next域来实现连接。
单链表:节点只有值域和next域,结构中的数据查询也只能按一个方向来实现
单链表实现增删改查功能:
1 /** 2 * 定义一个SingleListed 3 */ 4 class SingleListed{ 5 //初始化头节点,头节点不能储存数据 6 StartNode head = new StartNode( 0, "",""); 7 8 public StartNode getHead() { 9 return head; 10 } 11 12 /** 13 *删除节点,通过将要删除的节点的引用转到下一个即可,没有了引用,jvm的垃圾回收机制会自动回收 14 */ 15 public void delete(int num){ 16 //头节点不能动 17 StartNode temp = head; 18 boolean flag = false; 19 while(true){ 20 if(temp.next == null){ 21 break;//已到链表最后 22 } 23 if(temp.next.no == num){ 24 flag = true;//找到 25 break; 26 } 27 temp = temp.next; 28 } 29 if(flag){ 30 temp.next = temp.next.next; 31 } 32 else{ 33 System.out.printf("没有找到该%d的数据,无删除\n",num); 34 } 35 } 36 37 /** 38 * 链表添加数据 39 */ 40 public void add(StartNode startNode){ 41 //定义一个临时变量代替节点 42 StartNode temp = head; 43 while(true){ 44 //找到链表的最后 45 if( temp.next == null){ 46 break; 47 } 48 //如果没有找到最后,temp向后移 49 temp = temp.next; 50 } 51 temp.next = startNode; 52 } 53 54 /** 55 * 按照顺序添加数据 56 */ 57 public void addByOder(StartNode startNode){ 58 //头节点不能动,利用temp来处理数据 59 StartNode temp = head; 60 boolean flag = false;//标记数据编号是否重复 61 //遍历链表添加数据 62 while(true){ 63 //判断是否到链表的最后 64 if(temp.next == null){ 65 break; 66 } 67 else if(temp.next.no > startNode.no){ 68 break; 69 } 70 else if( temp.next.no == startNode.no) { 71 flag = true; 72 break; 73 } 74 temp = temp.next;//往后移动 75 } 76 if(flag){ 77 System.out.printf("该球星的排名%d已经有了,不能这么排了\n",temp.next.no); 78 } 79 else{ 80 startNode.next = temp.next; 81 temp.next = startNode; 82 } 83 84 } 85 86 /** 87 * 修改已有编号的name和nickname 88 * @param startNode 89 */ 90 public void update(StartNode startNode){ 91 //判断链表是否为空 92 if(head.next == null){ 93 System.out.println("链表为空!"); 94 return; 95 } 96 //当no重复时进行更换 97 StartNode temp = head.next; 98 boolean flag = false;//判断是否找到目标 99 while(true){ 100 if(temp == null){ 101 break;//链表已经遍历结束 102 } 103 if(temp.no == startNode.no){ 104 //找到 105 flag = true; 106 break; 107 } 108 temp = temp.next; 109 } 110 if(flag){ 111 temp.nickName = startNode.nickName; 112 temp.name = startNode.name; 113 } 114 else{ 115 System.out.println("无修改"); 116 } 117 118 } 119 120 /** 121 * 显示链表中储存的数据 122 */ 123 public void showList(){ 124 //判断链表是否为空 125 if(head.next == null){ 126 System.out.println("链表为空!"); 127 return; 128 } 129 //头节点不能动,需要一个辅助变量来遍历 130 StartNode temp = head.next; 131 while(true){ 132 //判断是否到最后 133 if(temp == null){ 134 break; 135 } 136 //输出节点数据 137 System.out.println(temp); 138 temp = temp.next; 139 } 140 141 } 142 } 143 144 //定义StartNode,每个StartNode都是一个节点 145 class StartNode{ 146 int no; 147 String name; 148 String nickName; 149 StartNode next; 150 public StartNode(int no,String name,String nickName){ 151 this.no = no; 152 this.name = name; 153 this.nickName = nickName; 154 } 155 156 @Override 157 public String toString() { 158 return "StartNode{" + 159 "no=" + no + 160 ", name='" + name + '\'' + 161 ", nickName='" + nickName + '\'' + 162 '}'; 163 } 164 }
单链表的一些应用:
(1)求单链表的倒数第k个数:
思路:先取得链表中的有效数据个数,再找到有效数据个数-k即可得到链表中的倒数第k个数。
1 /** 2 *求链表倒数第K个节点 3 * getLength - K = 倒数的第K的节点位置 4 */ 5 public static StartNode findLastIndexNode(StartNode head,int k){ 6 if(head.next == null){ 7 return null; 8 } 9 int listedLength = getLength(head); 10 //判断k值是否合理 11 if(k <= 0 || k > listedLength){ 12 return null; 13 } 14 //遍历取得倒数第K个数 15 StartNode temp = head.next; 16 for(int x = 0;x < listedLength-k;x++){ 17 temp = temp.next; 18 } 19 return temp; 20 } 21 /** 22 * 取得链表的有效数据个数 23 */ 24 public static int getLength(StartNode head){ 25 if(head.next == null){ 26 return 0; 27 } 28 StartNode temp = head.next; 29 int length = 0; 30 while(true){ 31 if(temp == null){ 32 break; 33 } 34 length++; 35 temp = temp.next; 36 } 37 return length; 38 }
(2)反转链表
思路:新建一个带头节点的空的单链表,遍历原链表将头节点下的第一个数链接到新链表的头节点后,然后依次取原链表后面的数据,每取一个将取得的该数据插入到新链表的头节点之后,新链表中已有的数据依次往后移动,遍历完原链表后再将新链表的头节点后第一个节点链接回原链表的头节点后,即实现链表的反转,
需要两个辅助变量,一个为原链表的头节点的后一个,一个为当前节点的后一个,保证原链表不断。
1 /** 2 * 反转单链表 3 */ 4 public static void inverseLinked(StartNode head){ 5 if(head.next == null || head.next.next == null){ 6 return;//链表中无数据或者只有一个数据就不用反转了 7 } 8 StartNode newHead = new StartNode(0,"",""); 9 StartNode temp = head.next; 10 StartNode next = null;//指向当前节点的下一个节点 11 while(temp != null){ 12 next = temp.next;//临时节点指向当前节点的下一个节点 13 temp.next = newHead.next;//将temp的下一个节点指向新链表的最前 14 newHead.next = temp;//将temp连接到新链表 15 temp = next;//temp后移 16 } 17 head.next = newHead.next; 18 }
(3)反向打印单链表
思路:反向打印不代表反转链表后打印,是在不改变链表的结构顺序下将链表中的数据从后往前依次打印,可以使用到栈先进后出的储存顺序完成,将链表中的数据依次压入栈中,然后打印栈中的弹出的数据即可。
1 /** 2 *反向打印链表:使用Stack栈(先进后出)的思路 3 * 不应该使用反转,因为会破坏链表的的数据结构 4 */ 5 public static void reversePrint(StartNode head){ 6 if(head.next == null){ 7 return ; 8 } 9 //使用jdk中stack 10 Stack<StartNode> s = new Stack<StartNode>(); 11 //循环将链表中的节点压入栈中 12 StartNode temp = head.next; 13 while(temp != null){ 14 s.push(temp); 15 temp = temp.next; 16 } 17 while(s.size()>0){ 18 System.out.println(s.pop()); 19 } 20 }
(4)合并两有序单链表,并且合并后的链表也是有序的
思路:需要新建一个空链表,循环比较两个有序链表的第一个数,将满足比较条件的数存到新链表中即可
1 /** 2 * 合并两个有序列表,合并后任然有序 3 */ 4 public static SingleListed mergeLinked(SingleListed s1,SingleListed s2){ 5 SingleListed s = new SingleListed(); 6 StartNode head = s.head;//新链表的头节点 7 StartNode head1 = s1.getHead(); 8 StartNode head2 = s2.getHead(); 9 StartNode temp1 = head1.next; 10 StartNode temp2 = head2.next; 11 //当两个表中任意一个表是空的时候,就不用比较大小,不为空的链表直接存入新链表 12 if(temp1 == null) head.next = head2.next; 13 if(temp2 == null) head.next = head1.next; 14 //循环比较两个链表头节点之后的数据,满足比较条件的数据存入新链表,且存入的数据不参与下次比较 15 while(temp1 != null && temp2 != null){ 16 if(temp1.no < temp2.no){ 17 head.next = temp1; 18 temp1 = temp1.next; 19 } 20 else if(temp1.no > temp2.no){ 21 head.next = temp2; 22 temp2 = temp2.next; 23 } 24 head = head.next; 25 } 26 return s; 27 }

浙公网安备 33010602011771号