据书上说,链表是一种物理存储单元上非连续、非顺序的存储结构,而它的数据元素的逻辑顺序是通过链表的指针连接次序实现的。听着好深奥,其实和C语言的链表基本相同(可惜木有好好学C),它是由一系列的节点组成,而每个节点包括两个部分:数据域(存储数据),指针域(存储下一个节点的地址)。链表又有单向链表、双向链表和循环链表之分,其实也就是一个指针的指向问题:
1.单向链表:前面一个节点指向后面一个节点。
2.双向链表:前一个节点指向后一个节点,后一个节点也指向前一个节点;根节点向前指向null,向后指向下一个节点;尾节点向前指向上一个节点,向后指向null。
3.循环链表:前一个节点指向后一个节点,后一个节点也指向前一个节点;根节点向前指向尾节点,向后指向下一个节点;尾节点向前指向上一个节点,向后指向根节点。
好吧,废话不多说,直接上代码,代码才是王道:
首先是链表节点类:
/** * 双向链表节点类 * @author ZhuMei */ public class doublyLinkedListNode { private Object obj;//节点内的数据对象 private doublyLinkedListNode next;//对下一个节点的引用 private doublyLinkedListNode previous;//对上一个节点的引用 private int score; /** * 构造方法1 */ public doublyLinkedListNode(){ } /** * 构造方法2 */ public doublyLinkedListNode(Object obj){ this.obj = obj ; } /** * 构造方法3 */ public doublyLinkedListNode(Object obj, int score) { super(); this.obj = obj; this.score = score; } /** * 构造方法4 */ public doublyLinkedListNode(Object obj, doublyLinkedListNode next, doublyLinkedListNode previous) { this.obj = obj; this.next = next; this.previous = previous; } public Object getObj() { return obj; } public void setObj(Object obj) { this.obj = obj; } public doublyLinkedListNode getNext() { return next; } public void setNext(doublyLinkedListNode next) { this.next = next; } public doublyLinkedListNode getPrevious() { return previous; } public void setPrevious(doublyLinkedListNode previous) { this.previous = previous; } public int getScore() { return score; } public void setScore(int score) { this.score = score; } }
然后是链表的实现类(重点):
/** * 双向链表实现类 * @author ZhuMei * */ public class doublyLinkedList implements NodeLinkedListInterface{ private int size = 0;// 节点总数 private doublyLinkedListNode root = null;// 根节点,附初值null private doublyLinkedListNode last = null;// 尾节点,附初值null /** * 添加节点的方法 * @param node新添加的节点对象 */ public void add(doublyLinkedListNode node) { //判断root是否null if(null == root ){ //让根节点和尾节点都指向新添加的节点 root = node; last =node; }else{ //向末尾添加节点 last.setNext(node); //将last设为node的上一个节点 node.setPrevious(last); //将新的节点作为尾节点 last = node; } size++; } /** * 在指定索引位置添加新节点 * @param node要添加的新节点 * @param index指定的索引位置 */ public void add(doublyLinkedListNode node, int index) { if(index >= size || index<0){ return; } //创建一个新节点 doublyLinkedListNode oldNode = new doublyLinkedListNode(); //获取指定索引位置的节点,将其赋给node oldNode = this.get(index); //如果将node设为根节点,即index==0 if(index == 0){ doublyLinkedListNode nextNode = root; root = node; root.setNext(nextNode); nextNode.setPrevious(root); }else{ //得到上一个节点 doublyLinkedListNode preNode = oldNode.getPrevious(); //设置新的节点关系 preNode.setNext(node); node.setPrevious(preNode); node.setNext(oldNode); oldNode.setPrevious(node); } size++; } /** * 获取指定索引位置的节点对象 * * @param index指定的索引位置 * @return 返回节点对象,如果index的范围超出size,则返回null. */ public doublyLinkedListNode get(int index) { //如果超出索引,返回null if(index >= size || index<0){ return null; } //让node为根节点 doublyLinkedListNode node = root; //遍历至索引位置 for(int i = 0; i<index;i++){ //获取node节点的下一个节点 node = node.getNext(); } return node; } /** * 移除指定的节点 * @param node要被移除的节点对象 */ public boolean remove(doublyLinkedListNode node) { //用state标记,当state = true时,表示移除成功,返回true,当state = false 时,表示移除失败,返回false boolean state = false; int x = size; //遍历数组,找出node for(int i = 0; i<size;i++){ //取出索引为i的节点数据,赋给node1 doublyLinkedListNode node1 = this.get(i); //当node = node1 时,执行移除 if(node == node1){ //当node1的下一个节点不为null时 if(node1.getNext()!=null && node1.getPrevious()!=null){ //得到节点node1的下一个节点,赋给nextNode doublyLinkedListNode nextNode = node1.getNext(); System.out.println(nextNode); //得到节点node1的上一个节点,赋给preNode doublyLinkedListNode preNode = node1.getPrevious(); //将nextNode设置为preNode的下一个节点 preNode.setNext(nextNode); //将preNode设置为nextNode的上一个节点 nextNode.setPrevious(preNode); } else if(node1.getNext()==null && node1.getPrevious()!=null){//当node1的下一个节点为null时 //获得node1的上一个节点preNode doublyLinkedListNode preNode = node1.getPrevious(); //让preNode的下一个节点指向null //preNode.setNext(null); last = preNode; } else if(node1.getNext()!=null && node1.getPrevious()==null){ //获得node1的下一个节点nextNode doublyLinkedListNode nextNode = node1.getNext(); //让nextNode的上一个节点指向null //nextNode.setPrevious(null); root = nextNode; } else{ root = null; } size--; state = true; } } return state; } /** * 移除指定所以位置的节点 * @param index指定要移除的节点索引 * @return 返回true和false,true表示移除成功,false表示移除失败 */ public boolean remove(int index) { //若超出索引,返回false,表示移除失败 if(index >=size && index <0){ return false; } //让node为根节点 doublyLinkedListNode node = root; //遍历至索引位置 for(int i = 0; i < index-1; i++){ //获取node的下一个节点 node = node.getNext(); } //next为index处的节点 doublyLinkedListNode next = node.getNext(); //将next指向index+1处的节点 next =next.getNext(); //设置node(index-1)的下一个节点是index+1 node.setNext(next); size--; return true; } /** * 获取双链表中存储的元素总数 * @return 返回size的值,如果为0则表示链表中没有节点 */ public int getSize() { return size; } }
最后是主函数(应用实现类里面的方法):
public class doublyManager { /** * @param ZhuMei */ public static void main(String[] args) { //实例化一个doublyLinkedList对象 NodeLinkedListInterface nll = new doublyLinkedList(); //实例化对象,再添加 doublyLinkedListNode node1 = new doublyLinkedListNode("海绵宝宝",97); doublyLinkedListNode node2 = new doublyLinkedListNode("派大星",95); doublyLinkedListNode node3 = new doublyLinkedListNode("蟹老板",68); doublyLinkedListNode node4 = new doublyLinkedListNode("章鱼哥",61); doublyLinkedListNode node5 = new doublyLinkedListNode("珊迪",90); doublyLinkedListNode node6 = new doublyLinkedListNode("痞老板",59); doublyLinkedListNode node7 = new doublyLinkedListNode("小蜗",92); nll.add(node1); nll.add(node2); nll.add(node3); nll.add(node4); nll.add(node5); nll.add(node6); nll.add(node7); //初始化节点n doublyLinkedListNode n = new doublyLinkedListNode("泡芙老师",91); //将n添加到索引为6的位置 nll.add(n, 0); //输出 System.out.print("********移除之前的人物排列为:\n"); for(int i=0;i<nll.getSize();i++){ doublyLinkedListNode node = nll.get(i); System.out.println(node.getObj()+" "+node.getScore()); } //移除索引为7的节点 nll.remove(7); //移除节点n nll.remove(n); //输出 System.out.print("\n********移除之后的人物排列为:\n"); for(int i=0;i<nll.getSize();i++){ doublyLinkedListNode node = nll.get(i); System.out.println(node.getObj()+" "+node.getScore()); } } }
至于链表实现类的接口的代码就不用贴了,然后说一句:《海绵宝宝》真的好看呢,尽管好久都没看了,不过真的很怀念。
练习中遇到的困难和解决:
做链表练习的时候老是遇到空指针异常,这让我很是忧桑啊,不过这些异常都是有原因的,总体来说,就是考虑不周,比如在“移除指定的节点”的方法中,开始的时候就没有考虑到如果移除的节点是根节点或尾节点的情况,导致空指针异常。当然,还有很多犯了同样的错误,不过我倒是觉得犯错并没有什么,它甚至还会是你进步的关键,在编程中,调试改错也是一种能力,而且可以大大地提高对编程的认识和编程能力。
练习的不足:到现在还没有将链表排序实现(捣鼓了好久,没有效果,得去问大神啊)。
还想说说做完练习的感想:嗯~这篇总结和练习是拖了好久的了,练习之前实现了部分,后来由于种种原因停了,现在把搞定之后有一种如释重负的感觉,虽然今天花了不少时间,但我自己感觉我在自己琢磨的过程中有收获,这就够了,我没有一些人的聪明,编个程序要花我很多时间,但是我既然选择了,就会认真地做,虽然有时会晚一点。
OK!又搞定了一篇总结,先睡觉咯,明天继续奋斗…………
相关推荐
虽然开发者在大一时完成这个项目,有些设计可能显得较为初级,但它包含了C语言基础到进阶的许多关键知识点,对于学习C语言的同学来说,是一个很好的参考和实践案例。 首先,C语言是一种底层编程语言,它的特点是...
比第一版内容更为详细、更为丰富全面,有兴趣的、初学者,可以一看。
7. **买东西.cpp**: 这个程序可能模拟了一个购物过程,涵盖了变量、条件语句、循环和数组,可能还涉及到基本的财务计算,如计算总价、找零等。 8. **14.【日期】根据日期求星期.cpp**: 这个程序可能使用了日期计算...
每个单元都用一个领域名加一个数字后缀表示,比如OS3是关于并发的单元。各个单元由被细分成主题(topics),这是CS知识体层次结构的最底层。 离散结构(DS) DS1. 函数,关系,集合[核心] DS2. 基本逻辑[核心] DS3. ...
线性链表是最基本的链表类型,它的每个节点包含数据和一个或多个指向其他节点的指针。除了线性链表,还有双向链表、循环链表等更加复杂的数据结构。 树结构是非线性数据结构的一种,它的每个节点可以有零个或多个子...
1. **钩子链表**:对于每种类型的钩子,系统都会维护一个钩子链表,其中包含了指向用户定义的回调函数(即钩子子程)的指针列表。每当与特定钩子类型相关的消息发生时,系统会将这些消息传递给相应的钩子子程进行...
【压缩包子文件的文件名称列表】:只有一个文件——[大家网]软件设计师考试试题分类精解.pdf,这表明压缩包内是一个PDF格式的文档,通常PDF文档结构严谨,易于阅读和打印,适合包含大量文字和图像信息,如题目、答案...
这样一来原因就很明显了,当我们输入数字后,是不是按下了回车键,这个时候,nextInt()从缓冲区把我们输入的数字读走了,但留下了最后的换行符,等运行到nextLine()的时候,它开始读缓冲区里的内容,然而好巧不巧的...
"数据结构算法集绝对可靠"这个标题暗示我们拥有的是一份全面且可靠的资源,它可能包含了数据结构领域内的各种经典算法及其详细解析。 描述中的“不错的东西”表达了对资源质量的认可,指出这份资料集合了数据结构的...
本教程将专注于使用Java实现一个经典游戏——贪吃蛇。贪吃蛇游戏程序是学习面向对象编程、事件处理以及游戏逻辑控制的绝佳案例。下面,我们将详细探讨其中涉及的关键知识点。 1. **Java基础语法**:在编写贪吃蛇...
可我找不到任何方法来声明这样的函数——感觉我需要一个返回指针的函数,返回的指针指向的又是返回指针的函数……,如此往复,以至无穷。 数组大小 1.23 能否声明和传入数组大小一致的局部数组,或者由其他参数...
可我找不到任何方法来声明这样的函数——感觉我需要一个返回指针的函数,返回的指针指向的又是返回指针的函数……,如此往复,以至无穷。 12 数组大小 13 1.23 能否声明和传入数组大小一致的局部数组,或者由...
17. 局域网(Local Area Network,LAN):在一个有限地理范围内连接多台设备的网络。 18. 界面(Interface):用户与软件或硬件交互的图形或文本环境。 19. 路由器(Router):网络设备,负责数据包在不同网络间转发...
这个问题的解决方案实际上就是一个算法,它涉及到一系列决策和步骤,如先带哪一样东西过河、何时返回等。这种问题可以通过流程图来清晰地展示其解决过程。 流程图,是算法的一种图形化表示,它使用各种图形符号(如...
一个简单的蛇游戏,主要由第一学期计算机科学的简单结构组成。 它由两个类组成,可执行文件 Snake.java 和 SnakePart.java 代表蛇身体的一部分。 前景是对作为游戏场的 2D 数组的操作、简单的查询构造(我右边的框...
- **示例1:吃东西**:通过一个简单的递归函数模拟吃东西的过程。 - **示例2:后代关系**:使用递归来定义一个人的后代关系。 - **示例3:后继关系**:介绍如何使用递归来定义数字的后继关系。 - **示例4:加法...
紧接着就会有一个判断,用来确定该链表中是否只有一项,如果链表中保存了多个文档模版,则会弹出一个对话框,来让我们选择到底是使用哪一套文档模版来构建应用程序,相信大家也都见到过这种情况吧。对了,还有一点要...
- GCC(GNU Compiler Collection)是GNU项目的一部分,是一个强大的跨平台编译器集合。它支持多种编程语言,包括C语言。 - 使用GCC编译C程序的基本命令格式为 `gcc [选项] 文件名.c -o 输出文件名`。 #### 三、使用...
它汇集了几所知名大学的ACM题库和详尽的解答,为学习者提供了一个深入理解算法、提升编程技巧的广阔天地。 一、ACM竞赛概述 ACM国际大学生程序设计竞赛,由国际计算机学会(ACM)主办,是一项全球性的编程竞赛,...