java链表

一、链表介绍

  链表是一种根据元素节点逻辑关系排列起来的一种数据结构。利用链表可以保存多个数据。这里有类似数组的概念,但是数组因为本身的限制有一个很大的缺点——数组的长度固定,不可改变。在长度固定的情况下首选的肯定是数组,但是在实际开发中往往要保存的内容长度是不固定的,此时可以用链表结构来代替数组的使用。

 

二、链表的基本形式

  所有要保存的数据都会被包装到一个节点对象中,之所以会引用一个节点类,是因为只依靠保存的数据无法区分出先后顺序,而引入了Node类可以包装数据并指向下一个节点。所以在Node类的设计中主要保存两个属性:

  • 数据(data)
  • 下一个节点的引用(next)

  Node节点类本身不属于一个简单Java类,而是一个功能性的表示类,在这个类中,主要保存了两种数据:一种是储存的对象,另一种是当前节点的下一个节点

  在链表操作的时候,首先需要一个根节点即第一个节点,然后每一个及诶单的引用都保存在上一个节点的next属性中。在进行输出操作的时候也应该按照节点的先后顺序一个一个取得每一个节点所包装的数据。

三、节点类的基本操作

  • 新增节点(addNode)
  • 打印节点(printNode)
  • 构造方法(Node)

  1.新增节点:

  可以用递归的方法遍历所有节点,直到遍历到最后一个节点,把新的节点放到最后一个节点后面。

1         public void addNode(Node newNode) {
2             if(this.next == null) {
3                 this.next = newNode;
4             }
5             else {
6                 this.next.addNode(newNode); //递归调用addNode方法
7             }
8         }

  在这个方法中,当递归遍历到最后一个节点时,如果他对的next为空则把新节点插入到该位置。

  2.打印节点:

  可以用递归调用的方法遍历所有节点,没遍历一个节点就输出这个节点的值,直到最后一个节点的next指正为空

 1         public void printNode() {
 2             System.out.println(this.data);
 3             if(this.data != null) {
 4                 if(this.next == null) {
 5                     return;
 6                 }
 7                 else {
 8                     this.next.printNode();
 9                 }
10             }
11         }

  在这个方法中,每次递归到一个节点,输出这个节点的值后,判断这个节点的next值是否为空,如果为空则返回,否则才继续递归。

  3.构造方法

  Node类中还有一个构造方法,在Node节点创建的时候,这个节点的data会通过构造方法的参数赋值给这个新创建的节点。

 

1     //构造方法,每一个Node类对象都必须保存有相应的数据    
2     public Node(String data) {
3         this.data = data;
4     }

 

四、链表的基本雏形

  链表中最重要的类就是Node,而如果用户直接操作Node类来封装数据,匹配节点关系,会给用户操作带来很大的复杂性,而用户实际上只关心链表中保存的数据有哪些,至于说数据是如何保存的,节点间的的关系是如何分配的,用户完全不需要知道。所以此时应该定义一个专门负责这个节点操作的类。

  这个类便是称为链表操作类的Link类

 

 

做了一个没有完成的Demo,暂时学到这里吧,心累。。。

  1 package question6;
  2 import java.io.BufferedReader;
  3 import java.io.File;
  4 import java.io.FileNotFoundException;
  5 import java.io.FileReader;
  6 import java.io.FileWriter;
  7 import java.io.IOException;
  8 import java.io.Reader;
  9 import java.io.Writer;
 10 import java.util.Scanner;
 11 /*
 12  * 程序说明:
 13  * Book类:
 14  *     构造方法(book对象包含title和price属性)
 15  *     compare(比较title是否相同)
 16  *     getInfo
 17  *     Info
 18  * Link类(外部能看见的类):
 19  *     内部的Node类(用于对节点进行操作)
 20  *         构造方法(通过book类对象构造Node)
 21  *         addNode方法
 22  *         containsNode方法
 23  *         getNode方法
 24  *         setNode方法
 25  *         removeNode方法
 26  *         toArrayNode方法
 27  *     root根节点(Node类对象)
 28  *     count保存元素的个数(int型)
 29  *     foot节点索引(int型)
 30  *     flag
 31  *     retArray数组(book类型)
 32  *     add方法
 33  *     size方法
 34  *     contains方法
 35  *     get方法
 36  *     set方法
 37  *     remove方法
 38  *     toArray方法
 39  *     clear方法
 40  * LinkListDemo类
 41  * 
 42  */
 43 
 44 //定义一个保存图书信息的类
 45 class Book{
 46     private String title;
 47     private double price;
 48     
 49     /*
 50      * 构造函数
 51      * 书名和价格
 52      */
 53     public Book(String title,double price) {
 54         this.title = title;
 55         this.price = price;
 56     }
 57     
 58     /*
 59      * compare函数
 60      * 对本类的对象进行比较操作
 61      * 1.判断传入的对象是否为null
 62      * 2.判断对象的地址是否相同
 63      * 3.对对象的内容进行比较
 64      */
 65     public boolean compare(Book book) {
 66         if(book == null) {
 67             return false;
 68         }
 69         if(this == book) {    //如果内存地址相同,则不需要进行细节比较,节约时间
 70             return true;
 71         }
 72         if(this.title.equals(book.title)&&this.price == book.price) {
 73             return true;
 74         }
 75         else {
 76             return false;
 77         }
 78     }
 79     
 80     /*
 81      * getInfo函数
 82      * 返回当前book对象的名称和价格
 83      */
 84     public String getInfo() {
 85         return "图书名称:"+ this.title + ",图书价格" + this.price;
 86     }
 87     
 88     public String info() {
 89         return  this.title + "\t" + this.price + "\r\n";
 90     }
 91 }
 92 //---------------------------Book类结束-----------------------------------------
 93 
 94 //链表的实现类,外部能看见的只有这个类
 95 class Link{
 96     //内部节点类
 97     private class Node{
 98         private Book data;
 99         private Node next;
100         public Node(Book data) {
101             this.data = data;
102         }
103         
104         /*
105          * 节点类的addNode函数
106          * 所有节点的新建保存在最后一个节点的尾部
107          */
108         public void addNode(Node newNode) {
109             //如果当前节点的下一个节点是null,则把新建的节点插入到这个节点之后
110             if(this.next == null) {
111                 this.next = newNode;
112             }
113             else {//否则,递归调用这个函数继续向后保存
114                 this.next.addNode(newNode);
115             }
116         }
117         /*
118          * 判断某本书籍是否存在函数containsNode
119          * 递归调用自身来遍历链表的每一个节点直到找到该节点,返回true
120          * 1.如果当前节点找到,返回true
121          * 2.如果当前节点未找到,判断下一个节点
122          * 3.如果下一个节点为空则返回true
123          */
124         public boolean containsNode(Book data) {
125             
126             if(data.compare(this.data)) {
127                 flag = 1;
128                 return true;
129             }
130             else {
131                 if(this.next!=null) {
132                     return this.next.containsNode(data);
133                 }
134                 else {
135                     flag = 0;
136                     return false;
137                 }
138             }
139         }
140         
141         /*
142          * 根据索引取数据函数getNode
143          * 参数是某个节点的索引值
144          * 返回值是指定索引包含的书籍名称
145          */
146         public Book getNode(int index) {
147             if(Link.this.foot++ == index) {
148                 return this.data;
149             }
150             else {
151                 return this.next.getNode(index);
152             }
153         }
154         
155         /*
156          * 根据索引修改数据函数setNode
157          * 参数是某个节点的索引和和书籍名
158          * 返回值是新的数据
159          */
160         public void setNode(int index,Book data) {
161             if(Link.this.foot++ == index) {
162                 this.data = data;
163             }
164             else {
165                 this.next.setNode(index, data);
166             }
167         }
168         
169         /*
170          * 节点的删除操作,removeNode
171          * 遍历每一个节点的数据,如果当前节点符合则删除
172          * 原理:当前节点的上一个节点.next = 当前节点.next
173          * 参数:当前节点的上一个节点和要删除的书籍
174          */
175         public void removeNode(Node previous,Book data) {
176             if(data.compare(this.data)) {
177                 previous.next = this.next;
178             }
179             else {
180                 this.next.removeNode(this, data);
181             }
182         }
183         
184         /*
185          * 将节点中保存的内容转化为数组函数toArrayNode
186          * 作用是将当前节点中保存的内容转化为对象数组
187          * 1.把当前对象存入retArray数组
188          * 2.递归调用自己,把下一个对象存入retArray
189          * 3.直到链表最后一节点
190          */
191         public void toArrayNode() {
192             Link.this.retArray[Link.this.foot++] = this.data;
193             if(this.next != null) {
194                 this.next.toArrayNode();
195             }
196         }
197     }
198 //----------------------------------以上为内部类Node--------------------------------------
199     
200     private Node root;        //定义根节点
201     private int count = 0;    //定义保存元素的个数
202     private int foot = 0;    //定义节点索引
203     public int flag = 0;
204     private Book[] retArray;    //返回的数组
205     
206     /*
207      * 用户向链表增加新的数据
208      * 参数是Node类对象
209      * 1.错误判断,如果传入数据为空则返回
210      * 2.定义一个newNode节点对象保存传入的对象
211      * 3.判断当前链表的根节点是否为空
212      * 4.如果为空则把新节点当做根节点
213      * 5.如果不为空,则用根节点对象调用节点类内部函数addNode
214      * 6.将newNode对象传入内部类函数创建新节点
215      */
216     public void add(Book data) {
217         if(data == null) {
218             return;
219         }
220         Node newNode = new Node(data);
221         if(this.root == null) {
222             this.root = newNode;
223         }
224         else
225         {
226             this.root.addNode(newNode);
227         }
228         this.count++;
229     }
230     
231     /*
232      * 获取当前链表数据个数函数
233      * 返回值是当前链表的数据个数
234      */
235     public int size() {
236         return this.count;
237     }
238     
239     /*
240      * 判断当前链表是否存在某个节点函数contains
241      * 1.判断传入的数据是否为空或当前链表是否为空,只要有一个节点为空,则返回false
242      * 2.否则,则用根节点调用内部类函数containsNode函数遍历节点列表判断是否存在该节点
243      */
244     public boolean contains(Book data) {
245         flag = 0;
246         if(data == null || this.root == null) {
247             return false;
248         }
249         return this.root.containsNode(data);
250     }
251     
252     /*
253      * 根据索引取数据函数get
254      * 1.判断传入的索引是否大于当前链表长度
255      * 2.大于则返回空
256      * 3.否则,设置foot值为0,调用内部类函数getNode遍历节点列表
257      */
258     public Book get(int index) {
259         if(index > this.count) {
260             return null;
261         }
262         this.foot = 0;
263         return this.root.getNode(index);
264     }
265     
266     public int getCount() {
267         return this.count;
268     }
269     /*
270      * 根据节点索引修改节点的数据
271      * 如果索引值大于当前节点的长度直接返回
272      * 否则调用内部类函数setNode遍历查找需要修改的数据
273      */
274     public void set(int index,Book data) {
275         if(index > this.count) {
276             return;
277         }
278         this.foot = 0;
279         this.root.setNode(index, data);
280     }
281     
282     /*
283      * 链表数据的删除函数remove
284      * 1.删除之前使用contains函数判断当前数据是否存在
285      * 2.如果存在则判断根节点的数据与当前数据是否相等,如果相等直接删除
286      * 3.如果不相等,则递归调用内部类函数removeNode查找并删除需要删除的节点
287      */
288     public void remove(Book data) {
289         if(this.contains(data)) {
290             if(data.equals(this.root.data)) {
291                 this.root = this.root.next;
292             }
293             else {
294                 this.root.next.removeNode(this.root, data);
295             }
296             this.count--;
297         }
298     }
299     
300     /*
301      * 将链表中的数据转换为对象数组输出
302      * 
303      */
304     public Book[] toArray() {
305         if(this.root == null) {
306             return null;
307         }
308         this.foot = 0;
309         this.retArray = new Book[this.count];
310         this.root.toArrayNode();
311         return this.retArray;
312     }
313     
314     /*
315      * 清空链表
316      * 把根节点设置成空
317      * 把count设置为0
318      */
319     public void clear() {
320         this.root = null;
321         this.count = 0;
322     }    
323     
324 }
325 //-------------------------节点类结束--------------------------------------
326 
327 public class LinkListDemo{
328     private static String tushupath = "bookmanage.txt";
329     
330     public void menu() {
331         System.out.println("\t----------------");
332         System.out.println("\t---1.图书添加----");
333         System.out.println("\t---2.图书删除----");
334         System.out.println("\t---3.图书修改----");
335         System.out.println("\t---4.图书列表----");
336         System.out.println("\t----------------");
337         System.out.println("请输入你要选择的功能");
338         
339     }
340     
341     
342     public static void show() throws IOException {
343         File file = new File(tushupath);
344         Reader in = new FileReader(file);
345         BufferedReader read = new BufferedReader(in);
346         int serial = 1;
347         String str;
348         String headline = "书籍名    价格";
349         while((str = read.readLine()) != null) {
350             if(str.equals(headline)) {
351                 System.out.println("序号" + "\t" + str);
352             }
353             else {
354                 System.out.println(serial + "\t" + str);
355                 serial++;
356             }
357             
358         }
359     }
360     
361     public static void bookadd(String bookname,double price) throws IOException{
362         Link add = new Link();
363         add.add(new Book(bookname,price));
364         File file = new File(tushupath);
365         Writer out = new FileWriter(file,true);
366         Book[] books = add.toArray();
367         for(int x = 0; x < books.length; x++) {
368             out.append(books[x].info());
369             System.out.println("booktest" + x);
370         }
371         out.close();
372     }
373     public static void bookremove(String bookname,double price) throws IOException {
374         Link remove = new Link();
375         remove.remove(new Book(bookname,price));
376         File file = new File(tushupath);
377         Writer out = new FileWriter(file,true);
378         
379         /*Book[] books = remove.toArray();
380         for(int x = 0; x < books.length; x++) {
381             out.append(books[x].info());
382         }*/
383         out.close();
384     }
385     
386     
387     
388     public static void main(String[] args) throws IOException {
389         String bookname = "";
390         double price = 0.00;
391         int serial = 0;
392         Scanner scan = new Scanner(System.in);
393         File file = new File(tushupath);
394         Writer out = new FileWriter(file,true);
395         Reader in = new FileReader(file);
396         BufferedReader read = new BufferedReader(in);
397         System.out.println(read.readLine());
398         String headline = "书籍名\t价格\r\n";
399         String headline_read = read.readLine();
400         if(headline.equals(headline_read) ) {
401             out.write(headline);
402         }
403         in.close();
404         out.close();
405         
406         LinkListDemo list = new LinkListDemo();
407         int choose = 0;
408         while(true) {
409             list.menu();
410             choose = scan.nextInt();
411             if(choose == 1) {
412                 System.out.println("你选择了图书添加功能");
413                 System.out.print("请输入你要添加的图书名:");
414                 bookname = scan.next();
415                 System.out.print("请输入你要添加图书的价格:");
416                 price = scan.nextDouble();
417                 LinkListDemo.bookadd(bookname, price);
418                 System.out.println("添加成功");
419                 System.out.println("当前图书列表:");
420                 LinkListDemo.show();
421             }
422             if(choose == 2) {
423                 System.out.println("你选择了图书删除功能");
424                 System.out.print("请输入你要删除的图书名:");
425                 bookname = scan.next();
426                 System.out.print("请输入你要删除图书的价格:");
427                 price = scan.nextDouble();
428                 LinkListDemo.bookremove(bookname, price);
429                 System.out.println("删除成功");
430                 System.out.println("当前图书列表:");
431                 LinkListDemo.show();
432             }
433             if(choose == 0) {
434                 out.close();
435                 System.exit(0);;
436             }
437         }
438     }
439 }
View Code

 

posted @ 2019-05-30 14:48  DIAO葫芦娃  阅读(327)  评论(0编辑  收藏  举报