java实现单项链表(复制,自己总结的在下一篇)

  1. 一、单向链表的结构。
  2. (1)、首先节点的结构,其中包含本节点内容,以及需要指向下一个节点。
  3. Java代码
  4. private static class Entry<E>{
  5. E e;
  6. Entry<E> nextEntry;
  7. public Entry(E e,Entry<E> nextEntry){
  8. this.e=e;
  9. this.nextEntry=nextEntry;
  10. }
  11. }
  12. private static class Entry<E>{
  13. E e;
  14. Entry<E> nextEntry;
  15. public Entry(E e,Entry<E> nextEntry){
  16. this.e=e;
  17. this.nextEntry=nextEntry;
  18. }
  19. }Java代码
  20. Java代码
  21. 其中e则指向本节点的对象,而nextEntry则指向下一个节点。
  22. (2)、任何时候都需要知道表头在哪里。毕竟是单向链表嘛,因为只有一个方向,找到了表头就能找到全部。
  23. Java代码
  24. private  Entry<E> head;
  25. private  Entry<E> head;
  26. (3)、还可以记录链表中总共有多少个节点。它是在某些判断时为了提高效率而存在的。不是绝对需要的。毕竟知道表头后,一个一个按顺序去寻找就好了。
  27. Java代码
  28. private  int size;
  29. public int size(){
  30. return this.size;
  31. }
  32. private  int size;
  33. public int size(){
  34. return this.size;
  35. }
  36. Java代码
  37. 好了有这三样,就足够了。就看我们如何用他们了。
  38. 二、内部实现。
  39. (1)、第一次向链表中插入。此时链表中节点为null,第一次插入,无非就是把节点头插入而已。
  40. 可以看出就是把链表头初始化了,并且链表大小涨1。其中modCount记录整个链表修改的次数,链表的增加和删除它都会增加。毕竟第一次插入相对外调用是透明的,所以应该是私有的咯。(透明就是不可见,这里只得是外部没必要知道它的存在)
  41. Java代码
  42. private void addFirst(E e){
  43. head=new Entry<E>(e,null);
  44. size++;
  45. modCount++;
  46. }
  47. private void addFirst(E e){
  48. head=new Entry<E>(e,null);
  49. size++;
  50. modCount++;
  51. }
  52. (2)、表头插入。在链表的头前插入一个元素,新增的元素变成新的表头。这个插入是效率最高的,毕竟你时刻知道链表的头在哪里。
  53. Java代码
  54. public void addHead(E e){
  55. if(head==null){
  56. this.addFirst(e);
  57. }else{
  58. Entry<E> newEntry=new Entry<E>(e,head);
  59. head=newEntry;
  60. size++;
  61. modCount++;
  62. }
  63. }
  64. public void addHead(E e){
  65. if(head==null){
  66. this.addFirst(e);
  67. }else{
  68. Entry<E> newEntry=new Entry<E>(e,head);
  69. head=newEntry;
  70. size++;
  71. modCount++;
  72. }
  73. }可以看出头为null的时候,则表明链表中没值,只需调用第一次插入。否则对给定的元素创新增一个节点,新增节点的下一个指向头节点,当然此时自己已经变成头结点了,索引要更新头节点的引用。(可以看出想要清空链表,只需要将头置为null就好了)
  74. (3)、指定节点插入(插队)。在链表的指定节点插入一个元素,效率非常低。由于规则上你只能从队伍第一个开始往后找,找到你要插队位置的前一个,并将你插入其中,你先要告诉你身前人你在他身后,并且你自己要清楚你身后是谁。反正够麻烦的。
  75. Java代码
  76. public void addSpecifyIndex(E e,int index){
  77. if(index<0||index>size||size==0){
  78. throw new NoSuchElementException();
  79. }
  80. if(index==0){
  81. this.addHead(e);
  82. return;
  83. }
  84. int count=0;
  85. for (Entry<E> p=head; p!=null;p=p.nextEntry) {
  86. if(count+1==index){
  87. Entry<E> newEntry=new Entry<E>(e,p.nextEntry);
  88. p.nextEntry=newEntry;
  89. size++;
  90. modCount++;
  91. return;
  92. }
  93. count++;
  94. }
  95. }
  96. public void addSpecifyIndex(E e,int index){
  97. if(index<0||index>size||size==0){
  98. throw new NoSuchElementException();
  99. }
  100. if(index==0){
  101. this.addHead(e);
  102. return;
  103. }
  104. int count=0;
  105. for (Entry<E> p=head; p!=null;p=p.nextEntry) {
  106. if(count+1==index){
  107. Entry<E> newEntry=new Entry<E>(e,p.nextEntry);
  108. p.nextEntry=newEntry;
  109. size++;
  110. modCount++;
  111. return;
  112. }
  113. count++;
  114. }
  115. }
  116. Java代码
  117. 先进行判断index是否正确,规定不能插入null链表。而且不能跳着走,毕竟链表要连起来。由于要找到前一个,但是表头的前一个是没有的,所以index==0时要单独判断。后面则用count进行计数,找到其index-1节点,然后进行插队处理。
  118. (4)、尾插入。其实也是插队了,只是总是需要插到最后一个之后。
  119. Java代码
  120. public void add(E e){
  121. if(head==null){
  122. this.addFirst(e);
  123. }else{
  124. this.addSpecifyIndex(e, size);
  125. }
  126. }
  127. public void add(E e){
  128. if(head==null){
  129. this.addFirst(e);
  130. }else{
  131. this.addSpecifyIndex(e, size);
  132. }
  133. }
  134. (5)、指定节点获取元素。效率低,同样从头开始找到指定的节点把其中元素取出
  135. Java代码
  136. public E get(int index){
  137. if(index<0||index>=size){
  138. throw new NoSuchElementException();
  139. }
  140. E result=null;
  141. int count=0;
  142. for (Entry<E> p=head;p!=null;p=p.nextEntry) {
  143. if(count==index){
  144. result=p.e;
  145. }
  146. count++;
  147. }
  148. return result;
  149. }
  150. public E get(int index){
  151. if(index<0||index>=size){
  152. throw new NoSuchElementException();
  153. }
  154. E result=null;
  155. int count=0;
  156. for (Entry<E> p=head;p!=null;p=p.nextEntry) {
  157. if(count==index){
  158. result=p.e;
  159. }
  160. count++;
  161. }
  162. return result;
  163. }
  164. Java代码
  165. (6)、指定节点删除。效率低,同样需要找到指定节点前一节点,直接把指定节点跳过就好了。
  166. Java代码
  167. public void remove(int index){
  168. if(index<0||index>=size){
  169. throw new NoSuchElementException();
  170. }
  171. if(index==0){
  172. head=head.nextEntry;
  173. size--;
  174. modCount++;
  175. return;
  176. }
  177. int count=0;
  178. for (Entry<E> p=head;p.nextEntry!=null;p=p.nextEntry) {
  179. if(count+1==index){
  180. p.nextEntry=p.nextEntry.nextEntry;
  181. size--;
  182. modCount++;
  183. break;
  184. }
  185. count++;
  186. }
  187. }
  188. public void remove(int index){
  189. if(index<0||index>=size){
  190. throw new NoSuchElementException();
  191. }
  192. if(index==0){
  193. head=head.nextEntry;
  194. size--;
  195. modCount++;
  196. return;
  197. }
  198. int count=0;
  199. for (Entry<E> p=head;p.nextEntry!=null;p=p.nextEntry) {
  200. if(count+1==index){
  201. p.nextEntry=p.nextEntry.nextEntry;
  202. size--;
  203. modCount++;
  204. break;
  205. }
  206. count++;
  207. }
  208. }
  209. (7)、循环。为了好进行遍历演示,下面的就是循环遍历所用的了,大家随意看一下就好了。
  210. Java代码
  211. private transient Entry<E> current;
  212. public void setCursor(int index){
  213. if(index<0||index>=size){
  214. throw new NoSuchElementException();
  215. }
  216. int count=0;
  217. for (Entry<E> p=head;p!=null;p=p.nextEntry) {
  218. if(count==index){
  219. current=p;
  220. break;
  221. }
  222. count++;
  223. }
  224. }
  225. public boolean hasNext(){
  226. return current!=null;
  227. }
  228. public E next(){
  229. E result=current.e;
  230. current=current.nextEntry;
  231. return result;
  232. }
  233. private transient Entry<E> current;
  234. public void setCursor(int index){
  235. if(index<0||index>=size){
  236. throw new NoSuchElementException();
  237. }
  238. int count=0;
  239. for (Entry<E> p=head;p!=null;p=p.nextEntry) {
  240. if(count==index){
  241. current=p;
  242. break;
  243. }
  244. count++;
  245. }
  246. }
  247. public boolean hasNext(){
  248. return current!=null;
  249. }
  250. public E next(){
  251. E result=current.e;
  252. current=current.nextEntry;
  253. return result;
  254. }
  255. 三、测试。。一个main方法,测试一下。
  256. Java代码
  257. public static void main(String[] args) {
  258. SingleChain<String> singleChain=new SingleChain<String>();
  259. for (int i = 0; i < 4; i++) {
  260. singleChain.add(i+"");
  261. }
  262. //头插入
  263. //      singleChain.addHead("head");
  264. //尾插入
  265. //      singleChain.add("tail");
  266. //指定节点插入
  267. //      singleChain.addSpecifyIndex("Specify", 1);
  268. //指定节点删除
  269. //      singleChain.remove(3);
  270. //设置循环的初始节点
  271. singleChain.setCursor(0);
  272. int count=0;
  273. System.out.println("######SIZE"+singleChain.size()+"#######");
  274. while(singleChain.hasNext()){
  275. System.out.println("index:"+count+",entry:"+singleChain.next());
  276. count++;
  277. }
  278. System.out.println(singleChain.get(singleChain.size()-1));
  279. }
  280. public static void main(String[] args) {
  281. SingleChain<String> singleChain=new SingleChain<String>();
  282. for (int i = 0; i < 4; i++) {
  283. singleChain.add(i+"");
  284. }
  285. //头插入
  286. //      singleChain.addHead("head");
  287. //尾插入
  288. //      singleChain.add("tail");
  289. //指定节点插入
  290. //      singleChain.addSpecifyIndex("Specify", 1);
  291. //指定节点删除
  292. //      singleChain.remove(3);
  293. //设置循环的初始节点
  294. singleChain.setCursor(0);
  295. int count=0;
  296. System.out.println("######SIZE"+singleChain.size()+"#######");
  297. while(singleChain.hasNext()){
  298. System.out.println("index:"+count+",entry:"+singleChain.next());
  299. count++;
  300. }
  301. System.out.println(singleChain.get(singleChain.size()-1));
  302. }
  303. 四、全部代码
  304. Java代码
  305. package paladin.chain;
  306. import java.util.NoSuchElementException;
  307. public class SingleChain<E> implements Chain<E>{
  308. private  Entry<E> head;
  309. private transient Entry<E> current;
  310. private  int size;
  311. private  int modCount;
  312. private void addFirst(E e){
  313. head=new Entry<E>(e,null);
  314. size++;
  315. modCount++;
  316. }
  317. public void addHead(E e){
  318. if(head==null){
  319. this.addFirst(e);
  320. }else{
  321. Entry<E> newEntry=new Entry<E>(e,head);
  322. head=newEntry;
  323. size++;
  324. modCount++;
  325. }
  326. }
  327. public void addSpecifyIndex(E e,int index){
  328. if(index<0||index>size||size==0){
  329. throw new NoSuchElementException();
  330. }
  331. if(index==0){
  332. this.addHead(e);
  333. return;
  334. }
  335. int count=0;
  336. for (Entry<E> p=head; p!=null;p=p.nextEntry) {
  337. if(count+1==index){
  338. Entry<E> newEntry=new Entry<E>(e,p.nextEntry);
  339. p.nextEntry=newEntry;
  340. size++;
  341. modCount++;
  342. return;
  343. }
  344. count++;
  345. }
  346. }
  347. public void add(E e){
  348. if(head==null){
  349. this.addFirst(e);
  350. }else{
  351. this.addSpecifyIndex(e, size);
  352. }
  353. }
  354. public E get(int index){
  355. if(index<0||index>=size){
  356. throw new NoSuchElementException();
  357. }
  358. E result=null;
  359. int count=0;
  360. for (Entry<E> p=head;p!=null;p=p.nextEntry) {
  361. if(count==index){
  362. result=p.e;
  363. }
  364. count++;
  365. }
  366. return result;
  367. }
  368. public void remove(int index){
  369. if(index<0||index>=size){
  370. throw new NoSuchElementException();
  371. }
  372. if(index==0){
  373. head=head.nextEntry;
  374. size--;
  375. modCount++;
  376. return;
  377. }
  378. int count=0;
  379. for (Entry<E> p=head;p.nextEntry!=null;p=p.nextEntry) {
  380. if(count+1==index){
  381. p.nextEntry=p.nextEntry.nextEntry;
  382. size--;
  383. modCount++;
  384. break;
  385. }
  386. count++;
  387. }
  388. }
  389. public void setCursor(int index){
  390. if(index<0||index>=size){
  391. throw new NoSuchElementException();
  392. }
  393. int count=0;
  394. for (Entry<E> p=head;p!=null;p=p.nextEntry) {
  395. if(count==index){
  396. current=p;
  397. break;
  398. }
  399. count++;
  400. }
  401. }
  402. public boolean hasNext(){
  403. return current!=null;
  404. }
  405. public E next(){
  406. E result=current.e;
  407. current=current.nextEntry;
  408. return result;
  409. }
  410. public int size(){
  411. return this.size;
  412. }
  413. public static void main(String[] args) {
  414. SingleChain<String> singleChain=new SingleChain<String>();
  415. for (int i = 0; i < 4; i++) {
  416. singleChain.add(i+"");
  417. }
  418. //头插入
  419. //      singleChain.addHead("head");
  420. //尾插入
  421. //      singleChain.add("tail");
  422. //指定节点插入
  423. //      singleChain.addSpecifyIndex("Specify", 1);
  424. //指定节点删除
  425. //      singleChain.remove(3);
  426. //设置循环的初始节点
  427. singleChain.setCursor(0);
  428. int count=0;
  429. System.out.println("######SIZE"+singleChain.size()+"#######");
  430. while(singleChain.hasNext()){
  431. System.out.println("index:"+count+",entry:"+singleChain.next());
  432. count++;
  433. }
  434. System.out.println(singleChain.get(singleChain.size()-1));
  435. }
  436. private static class Entry<E>{
  437. E e;
  438. Entry<E> nextEntry;
  439. public Entry(E e,Entry<E> nextEntry){
  440. this.e=e;
  441. this.nextEntry=nextEntry;
  442. }
  443. }
  444. }
时间: 2024-08-10 23:26:10

java实现单项链表(复制,自己总结的在下一篇)的相关文章

[java]反转单项链表,用O(n)时间和O(1)空间

链表数据结构 public class ListNode { public int val; public ListNode next; public ListNode(int x) { val = x; } } 反转代码 public ListNode reverse(ListNode head) { ListNode p; ListNode tmp = head.next; head.next = null; while(tmp != null) { p = tmp; tmp = tmp.n

Java实现双链表

public class DoubleLink<T> { //存放第一个指针 private Node<T> firstNode; //存放最后一个指针 private Node<T> lastNode; //存放链大小 private int size; //构造函数 public DoubleLink() {} // --------------------------------add()系列---------------------------------- p

单项链表的建立

链表是最基本的数据结构之一,建立单项链表步骤如下 定义链表节点 定义三个指针——头指针,尾指针,当前结点指针.并分别申请内存,初始化 判断是不是头指针,如果是,则当前结点赋值给头指针,尾指针的后继为空;如果当前不是头指针,在尾指针后追加当前结点 完成插入操作后,更新尾指针和尾指针的后继 重新申请一块内存为新的扩展节点使用 定义简单的节点结构体 1 typedef struct Node 2 { 3 int data; 4 struct Node *next; 5 } Node; 最后返回链表的头

java实现单链表

前面已经介绍了java如何实现顺序链表:http://www.cnblogs.com/lixiaolun/p/4643664.html 接下来,我们开始学习java实现单链表. 单链表类 package linklist; public class LinkList { class Element { public Object value=null; private Element next=null; } private Element header = null;//头结点 /** * 初

采用头插插法和尾插法建立单项链表

PS: 来源2014年数据结构联考复习指导 Page27. #include <iostream> #include <stdio.h> #include <stdlib.h> using namespace std; const int END_INPUT = -1; typedef struct LNode { int data; struct LNode *next; }LNode, *LinkList; LinkList CreatList1(LinkList

Java对象的深复制----利用串行化进行深复制

把对象写到流里的过程是串行化(Serilization)过程,但是在Java程序圈里又非常形象地称为“冷冻”或者“腌咸菜”过程:而把对象从流中读出来的并行化(Deserialization)过程则叫做“解冻”或者“回鲜”过程.应当指出的是,写到流里的是对象的一个拷贝,而原来对象仍然存在于JVM里面,因此“腌成咸菜”的只是对象的一个拷贝. 在Java语言里深复制一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里(腌成咸菜),再从流里读回来

Linked List Cycle leetcode II java (寻找链表环的入口)

题目: Given a linked list, return the node where the cycle begins. If there is no cycle, return null. Follow up: Can you solve it without using extra space? 题解: 这个连同I都是很经典的题啦,刷CC150时候就折磨了半天. 其实就推几个递推公式就好..首先看图(图引用自CC150): 从链表起始处到环入口长度为:a,从环入口到Faster和Sl

(java描述)关于链表的代码-----单双、循环链表、约瑟夫环、多项式相加

将链表头尾倒置 将几个链表合并成一个新的链表,将链表中重复的节点去掉,并按大小排序 双向循环链表 单向循环链表(约瑟夫循环) 多项式相加 程序源代码 单链表.单向循环链表结点类 package javab; public class Node { int data; Node next; public Node(int data){ this.data=data; } } 第一题代码: package javab; import java.util.Scanner; public class I

3、蛤蟆的数据结构笔记之三线性表单项链表实现

今天励志短语:"人生的价值,即以其人对于当代所做的工作为尺度." 昨天我们看了线性表的一些定义概念,今天来看下其中的单项链表代码如何实现. 1.  声明结构 如下声明一个指向结构的指针.(存放整数的节点,我们也可以根据需要创建字符的链表) typedef struct list_node *list_pointer; typedef struct list_node{ intdata; list_pointerlink; }; list_pointerptr = NULL; 2.  定