<div class="it610-blog-content-contain" style="font-size: 14px"></div>
概念: 链表是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针。使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。链表通常由一连串节点组成,每个节点包含任意的实例数据和一或两个用来指向上一个/或下一个节点的位置的链接("links")。链表数据的存取往往要在不同的排列顺序中转换。而链表是一种自我指示数据类型,因为它包含指向另一个相同类型的数据的指针(链接)。链表允许插入和移除表上任意位置上的节点,但是不允许随机存取。链表有很多种不同的类型:单向链表,双向链表以及循环链表。
动手练习一下以增加对链表的理解:
练习:
1.定义一个链表类
2.链表中存储学生信息,根据学分从小到大的排序
代码如下:
package 链表; public class Node { public Object date;//数据域 public Node next;//引用域 public Node(Object date){ this.date=date; } }
package 链表; /* * 还应该再加一个方法:根据内容查找节点的位置,这样就可以通过修改指定位置的节点的方法达到修改指定内容的节点的目的 * 总结: * 删除和插入时一定要特别注意头节点和尾节点,很容易出错 * */ public class LinkNode { public Node root;//头节点 public Node rail;//尾节点 public int size=0; /* * 添加节点的方法*/ public void add(Node node){ if(size==0){ root=node; rail=node; size++; return; } rail.next=node; rail=node; size++; } /* * 找指定位置的节点*/ public Node get(int index){ if(index<0||index>=size){//index=0->size-1 return null; } Node node=root; for(int i=0;i<index;i++){ //node.next=node; node=node.next; } return node; } /* * 修改指定位置的节点*/ public Object revamp(int index,Object date){ Node node=get(index); get(index).date=date; return node.date; } /* * 在指定位置插入节点(插到指定位置的前面)*/ public void insert(int index,Node node){ size++; node.next=get(index);//这两行代码的顺序不能弄反了 if(index==0){//如果要插入到第一个节点的前面,则要特殊处理 root=node; }else { get(index-1).next=node; } } /* * 删除指定位置的节点 * 返回被删除节点的数据 * */ public Object deletNode(int index){ Node node=null; if(index<0||index>=size){ } if(index==0){//如果删除的是头节点,则要特殊处理 if(size==1){//如果只有一个节点则直接删除即可 node=get(index); root=null; rail=null; size--; } if(size>1){ node=get(index); root=get(index).next; size--; } } if(index>0&&index<size-1){ node=get(index);//把要被删除的节点赋给中间变量 get(index-1).next=get(index).next;//删除节点的下一个节点赋给删除节点的上一个节点 size--; } if(index==size-1){//如果删除的是尾节点也要做特殊处理 if(size==1){//如果只有一个节点则直接删除即可 node=get(index); root=null; rail=null; size--; } if(size>1){ node=get(index); rail=get(index-1); size--; } } return node.date; } /* * 删除节点(根据内容删除) * 返回删除的节点位置 * */ public int deletNode(Object date){ int index=0; for(int i=0;i<size;i++){ if(date.equals(get(i).date)){ index=i; Node node=get(i);//把要被删除的节点赋给中间变量 if(i==0){//如果是要删除第一个节点的内容,则要特殊处理 root=get(i).next; } if(i==size-1){//如果是要删除最后一个节点的内容,则要特殊处理 rail=get(i-1); } if(i>0&&i<size-1){ get(i-1).next=get(i+1);//删除节点的下一个节点赋给删除节点的上一个节点 } //node=null; size--; break; } } return index; } /* * 返回节点总数*/ public int size(){ return size; } }
package 链表; public class Students { private String name; private String id; private int score; public Students(String name, String id, int score) { this.name = name; this.id = id; this.score = score; } /* * 重写equals()方法 * */ public boolean equals(Object st){ Students stu=(Students)st; if(this.name.equals(stu.name)&&stu.score==this.score&&this.id.equals(stu.id)){ return true; } else return false; } public String toString() { return "姓名:" + name + "\t学号:" + id + "\t学分:" + score; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getId() { return id; } public void setId(String id) { this.id = id; } public int getScore() { return score; } public void setScore(int score) { this.score = score; } }
package 链表; public class Test { public static void main(String[] args) { Test test=new Test(); java.util.Random random=new java.util.Random(); //创建链表对象 LinkNode link=new LinkNode(); //创建七个学生对象 Students st1=new Students("李 文","20140801",random.nextInt(100)); Students st2=new Students("李小东","20140802",random.nextInt(100)); Students st3=new Students("张晓江","20140803",random.nextInt(100)); Students st4=new Students("朱 丽","20140804",random.nextInt(100)); Students st5=new Students("肖 笑","20140805",random.nextInt(100)); Students st6=new Students("王 琳","20140806",random.nextInt(100)); Students st7=new Students("沈 文","20140807",random.nextInt(100)); //创建七个节点对象 Node node1=new Node(st1); Node node2=new Node(st2); Node node3=new Node(st3); Node node4=new Node(st4); Node node5=new Node(st5); Node node6=new Node(st6); Node node7=new Node(st7); //把七个节点添加在链表里 link.add(node1); link.add(node2); link.add(node3); link.add(node4); link.add(node5); link.add(node6); link.add(node7); /* * 输出链表里的节点*/ System.out.println("排序前:"); test.output(link);//调用输出节点的方法 test.sort(link);//排序 System.out.println("按学分从低到高排序后:"); test.output(link);//调用输出节点的方法 System.out.println("------------------------------------------"); System.out.println(); /* * 添加一个学生的信息 * */ System.out.println("--------- * 添加一个学生的信息*---------------------------------"); Students st8=new Students("王小晓","20140808",random.nextInt(100)); System.out.println("添加一个学生信息: "+st8.toString()); Node node8=new Node(st8); link.add(node8); //输出节点 System.out.println("添加了一个学生后:"); test.output(link);//调用输出节点的方法 test.sort(link);//排序 System.out.println("添加了一个学生后按学分从低到高排序后:"); test.output(link);//调用输出节点的方法 System.out.println("-------------------------------------------"); System.out.println(); /* * 插入一个学生对象 * * */ System.out.println("----------* 插入一个学生对象* ---------------------------------"); Students st9=new Students("李重云","20140809",random.nextInt(100)); System.out.println("插入的学生信息: "+st9.toString()); Node node9=new Node(st9); link.insert(0, node9);//在第三个位置插入 //输出节点 System.out.println("插入后:"); test.output(link);//调用输出节点的方法 test.sort(link);//排序 System.out.println("插入后按学分从低到高排序后:"); test.output(link);//调用输出节点的方法 System.out.println("-----------------------------------------"); System.out.println(); /* * 删除指定位置的节点*/ System.out.println("------------* 删除指定位置的节点*-----------------------------"); Students st=(Students)link.deletNode(7); System.out.println("指定删除第八个节点"); System.out.println("被删除的学生信息是: "+st.toString()); System.out.println("删除一个节点后:"); test.output(link);//调用输出节点的方法 System.out.println("-----------------------------------------"); System.out.println(); /* * 根据内容删除指定位置的节点 * */ System.out.println("-----* 根据内容删除指定位置的节点 *--------------------------------------"); int index=link.deletNode(node9.date); //输出节点 System.out.println("删除的学生是第"+(index+1)+"个\n该学生的信息是\t"+node9.date.toString()); System.out.println("删除第"+(index+1)+"一个学生后:"); test.output(link);//调用输出节点的方法 System.out.println("-----------------------------------------"); System.out.println(); /* * 修改指定位置的节点 * */ System.out.println("------* 修改指定位置的节点*-----------------------------------"); Students stu=new Students("李文文","20140801",random.nextInt(100)); link.revamp(2, stu); System.out.println("修改了第一个同学的信息,为:"+stu.toString()); System.out.println("修改后:"); test.output(link);//调用输出节点的方法 test.sort(link);//排序 System.out.println("修改后按学分从低到高排序后:"); test.output(link);//调用输出节点的方法 System.out.println("-----------------------------------------"); System.out.println(); } /* * 输出链表里的节点方法*/ public void output(LinkNode link){ for(int i=0;i<link.size;i++){ System.out.println((i+1)+" "+link.get(i).date.toString()); } } //用冒泡排序法给学生的分数排序 public void sort(LinkNode link){ for(int j=0;j<link.size-1;j++){ for(int i=0;i<link.size-1;i++){ Students stu1 = (Students)link.get(i).date; Students stu2 = (Students)link.get(i+1).date; if(stu1.getScore() > stu2.getScore()){ Object temp=link.get(i).date; link.get(i).date=link.get(i+1).date; link.get(i+1).date=temp; } } } } }
排序前: 1 姓名:李 文 学号:20140801 学分:43 2 姓名:李小东 学号:20140802 学分:97 3 姓名:张晓江 学号:20140803 学分:40 4 姓名:朱 丽 学号:20140804 学分:41 5 姓名:肖 笑 学号:20140805 学分:6 6 姓名:王 琳 学号:20140806 学分:51 7 姓名:沈 文 学号:20140807 学分:55 按学分从低到高排序后: 1 姓名:肖 笑 学号:20140805 学分:6 2 姓名:张晓江 学号:20140803 学分:40 3 姓名:朱 丽 学号:20140804 学分:41 4 姓名:李 文 学号:20140801 学分:43 5 姓名:王 琳 学号:20140806 学分:51 6 姓名:沈 文 学号:20140807 学分:55 7 姓名:李小东 学号:20140802 学分:97 ------------------------------------------ --------- * 添加一个学生的信息*--------------------------------- 添加一个学生信息: 姓名:王小晓 学号:20140808 学分:25 添加了一个学生后: 1 姓名:肖 笑 学号:20140805 学分:6 2 姓名:张晓江 学号:20140803 学分:40 3 姓名:朱 丽 学号:20140804 学分:41 4 姓名:李 文 学号:20140801 学分:43 5 姓名:王 琳 学号:20140806 学分:51 6 姓名:沈 文 学号:20140807 学分:55 7 姓名:李小东 学号:20140802 学分:97 8 姓名:王小晓 学号:20140808 学分:25 添加了一个学生后按学分从低到高排序后: 1 姓名:肖 笑 学号:20140805 学分:6 2 姓名:王小晓 学号:20140808 学分:25 3 姓名:张晓江 学号:20140803 学分:40 4 姓名:朱 丽 学号:20140804 学分:41 5 姓名:李 文 学号:20140801 学分:43 6 姓名:王 琳 学号:20140806 学分:51 7 姓名:沈 文 学号:20140807 学分:55 8 姓名:李小东 学号:20140802 学分:97 ------------------------------------------- ----------* 插入一个学生对象* --------------------------------- 插入的学生信息: 姓名:李重云 学号:20140809 学分:10 插入后: 1 姓名:李重云 学号:20140809 学分:10 2 姓名:肖 笑 学号:20140805 学分:6 3 姓名:王小晓 学号:20140808 学分:25 4 姓名:张晓江 学号:20140803 学分:40 5 姓名:朱 丽 学号:20140804 学分:41 6 姓名:李 文 学号:20140801 学分:43 7 姓名:王 琳 学号:20140806 学分:51 8 姓名:沈 文 学号:20140807 学分:55 9 姓名:李小东 学号:20140802 学分:97 插入后按学分从低到高排序后: 1 姓名:肖 笑 学号:20140805 学分:6 2 姓名:李重云 学号:20140809 学分:10 3 姓名:王小晓 学号:20140808 学分:25 4 姓名:张晓江 学号:20140803 学分:40 5 姓名:朱 丽 学号:20140804 学分:41 6 姓名:李 文 学号:20140801 学分:43 7 姓名:王 琳 学号:20140806 学分:51 8 姓名:沈 文 学号:20140807 学分:55 9 姓名:李小东 学号:20140802 学分:97 ----------------------------------------- ------------* 删除指定位置的节点*----------------------------- 指定删除第八个节点 被删除的学生信息是: 姓名:李小东 学号:20140802 学分:97 删除一个节点后: 1 姓名:肖 笑 学号:20140805 学分:6 2 姓名:李重云 学号:20140809 学分:10 3 姓名:王小晓 学号:20140808 学分:25 4 姓名:张晓江 学号:20140803 学分:40 5 姓名:朱 丽 学号:20140804 学分:41 6 姓名:李 文 学号:20140801 学分:43 7 姓名:王 琳 学号:20140806 学分:51 ----------------------------------------- -----* 根据内容删除指定位置的节点 *-------------------------------------- 删除的学生是第1个 该学生的信息是 姓名:肖 笑 学号:20140805 学分:6 删除第1一个学生后: 1 姓名:李重云 学号:20140809 学分:10 2 姓名:王小晓 学号:20140808 学分:25 3 姓名:张晓江 学号:20140803 学分:40 4 姓名:朱 丽 学号:20140804 学分:41 5 姓名:李 文 学号:20140801 学分:43 6 姓名:王 琳 学号:20140806 学分:51 ----------------------------------------- ------* 修改指定位置的节点*----------------------------------- 修改了第一个同学的信息,为:姓名:李文文 学号:20140801 学分:66 修改后: 1 姓名:李重云 学号:20140809 学分:10 2 姓名:王小晓 学号:20140808 学分:25 3 姓名:李文文 学号:20140801 学分:66 4 姓名:朱 丽 学号:20140804 学分:41 5 姓名:李 文 学号:20140801 学分:43 6 姓名:王 琳 学号:20140806 学分:51 修改后按学分从低到高排序后: 1 姓名:李重云 学号:20140809 学分:10 2 姓名:王小晓 学号:20140808 学分:25 3 姓名:朱 丽 学号:20140804 学分:41 4 姓名:李 文 学号:20140801 学分:43 5 姓名:王 琳 学号:20140806 学分:51 6 姓名:李文文 学号:20140801 学分:66 -----------------------------------------
总结:写插入方法、删除方法、添加方法时一定要对链表的头节点和尾节点进行特殊的处理,不然在用链表的头尾部分对节点进行处理时很容易报空指针异常的错误。