[Java算法分析与设计]--单向链表(List)的实现和应用
单向链表与顺序表的区别在于单向链表的底层数据结构是节点块,而顺序表的底层数据结构是数组。节点块中除了保存该节点对应的数据之外,还保存这下一个节点的对象地址。这样整个结构就像一条链子,称之为“链表”
我们可以推理出单向链表和顺序表这两种数据结构特性对其本身操作的影响:
1、对读和改的影响:对于底层为数组的顺序表来说,读取(改写)数据是通过arr[n]的方式。而对于链表来说,操作第n个节点的数据必须要从第0个节点开始获取下一个节点的对象地址,直到第n个,如果运气不好要获取最后一个节点的数据,甚至要遍历整个链表所有的数据,其效率可想而知。
2、对插入的影响:对于底层为数组的顺序表来说,如果从首部或者中间位置插入一个数据,则其后的数据的物理内存地址全部都要往后移动一个单位,因为数组本身便是一连串的数据集合。而对于链表来说,如果要插入数据只需要对应位置前一位的对象地址以及在插入节点中加上后一位节点的对象地址即可。
下面我们通过代码的方式来实现我们自己的单向链表,我们首先先定义List接口:
- package com.chen.arithmetic_test.list_test;
- /**
- * Created by ChenMP on 2017/7/3.
- */
- public interface List {
- //获得长度
- public int size();
- //插入元素
- public boolean insert(int index, Object o) throws Exception;
- //新增元素
- public boolean add(Object o) throws Exception;
- //删除元素
- public boolean remove(int index) throws Exception;
- //获取元素
- public Object get(int index) throws Exception;
- //判断线性表是否为空
- public boolean isEmpty();
- }
编写节点类Node:
- package com.chen.arithmetic_test.list_test;
- /**
- * Created by ChenMP on 2017/7/4.
- */
- public class Node {
- private Object nodeData; //当前节点数据
- private Node nextNode; //保存下一个节点
- public Node() {
- super();
- }
- public Node(Object nodeData) {
- this.nodeData = nodeData;
- }
- public Object getNodeData() {
- return nodeData;
- }
- public void setNodeData(Object nodeData) {
- this.nodeData = nodeData;
- }
- public Node getNextNode() {
- return nextNode;
- }
- public void setNextNode(Node nextNode) {
- this.nextNode = nextNode;
- }
- }
编写LinkList的实现类:
- package com.chen.arithmetic_test.list_test;
- /**
- * Created by ChenMP on 2017/7/4.
- */
- public class LinkList implements List {
- private Node fristNode;//开始节点
- private Node lastNode;//结束节点
- private int size;//List长度
- private boolean isFixed;//是否限定List长度
- private int fixedLength;//List定长
- public LinkList() {
- this.size = 0;
- this.fristNode = null;//第一次成功插入时定义
- this.lastNode = null;
- this.isFixed = false;//不限定List长度
- this.fixedLength = -1;//不限定长度
- }
- public LinkList(int length) {
- this.fristNode = null;//第一次成功插入时定义
- this.lastNode = null;
- this.size = 0;
- this.isFixed = true;//限定List长度
- this.fixedLength = length;//设置限定长度
- }
- @Override
- public int size() {
- return this.size;
- }
- @Override
- public boolean insert(int index, Object o) throws Exception {
- if(index > size)
- throw new Exception("IndexOutOfBoundsException");
- if (index == size && this.isFixed && size>=this.fixedLength)
- throw new Exception("IndexOutOfBoundsException");
- Node previousNode = null; //遍历节点,用于存放更新节点的前一个节点
- Node currentNode = this.fristNode; //遍历节点,用于存放当前节点
- for (int i=1; i<=index; i++) {
- if (null == currentNode) //插入节点前有空节点
- throw new Exception("IndexOutOfBoundsException");
- previousNode = currentNode;
- currentNode = previousNode.getNextNode();
- }
- if (null == currentNode) { //把节点插入到最后
- currentNode = new Node(o);
- if (null != previousNode) { //fristNode不为空
- previousNode.setNextNode(currentNode);
- } else { //fristNode不为空,更新fristNode
- this.fristNode = currentNode;
- }
- this.lastNode = currentNode;
- size++;
- } else { //节点不为空,取代原节点数据
- currentNode.setNodeData(o);
- }
- return true;
- }
- @Override
- public boolean add(Object o) throws Exception {
- if (this.isFixed && size == fixedLength)
- throw new Exception("IndexOutOfBoundsException");
- Node currentNode = new Node(o);
- if (0 == size) {//List中插入第一个元素
- this.fristNode = currentNode;
- this.lastNode = currentNode;
- size++;
- } else {
- this.lastNode.setNextNode(currentNode);
- this.lastNode = currentNode;
- size++;
- }
- return true;
- }
- @Override
- public boolean remove(int index) throws Exception {
- if(index < 0 || index >= size)
- throw new Exception("IndexOutOfBoundsException");
- Node previousNode = null; //遍历节点,用于存放删除节点的前一个节点
- Node currentNode = this.fristNode; //遍历节点,用于存放删除节点
- for (int i=1; i<=index; i++) {
- if (null == currentNode) //删除节点前有空节点
- throw new Exception("IndexOutOfBoundsException");
- previousNode = currentNode;
- currentNode = previousNode.getNextNode();
- }
- previousNode.setNextNode(currentNode.getNextNode());
- currentNode = null;
- size--;
- return true;
- }
- @Override
- public Object get(int index) throws Exception {
- if(index < 0 || index >= size)
- throw new Exception("IndexOutOfBoundsException");
- Node currentNode = this.fristNode; //遍历节点,用于存放查询节点
- for (int i=1; i<=index; i++) {
- if (null == currentNode) //删除节点前有空节点
- throw new Exception("IndexOutOfBoundsException");
- currentNode = currentNode.getNextNode();
- }
- return currentNode.getNodeData();
- }
- @Override
- public boolean isEmpty() {
- return this.size>0?false:true;
- }
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- Node currentNode = this.fristNode; //遍历节点,用于存放查询节点
- while (null != currentNode) {
- sb.append(currentNode.getNodeData()).append(",");
- currentNode = currentNode.getNextNode();
- }
- return sb.toString();
- }
- }
编写测试代码:
- package com.chen.arithmetic_test.list_test;
- import java.util.LinkedList;
- /**
- * Created by ChenMP on 2017/7/3.
- */
- public class TestList {
- public static void main(String[] args) throws Exception {
- List list = new LinkList(3);
- list.insert(0,0);
- // list.add(0);
- list.add(1);
- list.add(2);
- // list.add(3);
- System.out.print("测试定长list: " + list.toString() + "|| list长度为: " + list.size());
- System.out.println();
- List list2 = new SequenceList();
- list2.add(0);
- list2.add(1);
- list2.add(2);
- list2.add(3);
- System.out.print("测试不定长list: " + list2.toString() + "|| list长度为: " + list2.size());
- }
- }
通过我们自己实现的代码,相信我们再去看JDK中LinkList源码的时候一定能够很轻松的理解其原理实现。怀挺!!
[Java算法分析与设计]--单向链表(List)的实现和应用的更多相关文章
- java笔试之从单向链表中删除指定值的节点
输入一个单向链表和一个节点的值,从单向链表中删除等于该值的节点,删除后如果链表中无节点则返回空指针. 链表的值不能重复 构造过程,例如 1 -> 2 3 -> 2 5 -> 1 4 ...
- java创建节点和单向链表
package datastructure; public class Node { private Object data; private Node next; public Node() { t ...
- [Java算法分析与设计]--顺序栈的实现
在程序的世界,栈的应用是相当广泛的.其后进先出的特性,我们可以应用到诸如计算.遍历.代码格式校对等各个方面.但是你知道栈的底层是怎么实现的吗?现在跟随本篇文章我们来一睹它的庐山真面目吧. 首先我们先定 ...
- [Java算法分析与设计]--线性结构与顺序表(List)的实现应用
说到线性结构,我们应该立马能够在脑子里蹦出"Array数组"这个词.在Java当中,数组和对象区别基本数据类型存放在堆当中.它是一连串同类型数据存放的一个整体.通常我们定义的方式为 ...
- [Java算法分析与设计]--链式堆栈的设计
在上篇文章当中,我们实现了底层为数组的顺序栈.在我之前的文章中也提到过:以数组为数据结构基础在存储数据方面需要一整块连续的内存来存放数据,一旦遇到需要可以动态扩展的功能需求时如果数据量大可能会给虚拟机 ...
- 单向链表的归并排序——java实现
在做Coursera上的Algorithms第三周测验练习的时候有一道链表随机排序问题,刚开始没有什么思路,就想着先把单向链表归并排序实现了,再此基础上进行随机排序的改造.于是就结合归并排序算法,实现 ...
- 笔试题&面试题:设计一个复杂度为n的算法找到单向链表倒数第m个元素
设计一个复杂度为n的算法找到单向链表倒数第m个元素.最后一个元素假定是倒数第0个. 提示:双指针查找 相对于双向链表来说,单向链表仅仅能从头到尾依次訪问链表的各个节点,所以假设要找链表的倒数第m个元素 ...
- Java实现单向链表基本功能
一.前言 最近在回顾数据结构与算法,有部分的算法题用到了栈的思想,说起栈又不得不说链表了.数组和链表都是线性存储结构的基础,栈和队列都是线性存储结构的应用- 本文主要讲解单链表的基础知识点,做一个简单 ...
- JAVA单向链表实现
JAVA单向链表实现 单向链表 链表和数组一样是一种最常用的线性数据结构,两者各有优缺点.数组我们知道是在内存上的一块连续的空间构成,所以其元素访问可以通过下标进行,随机访问速度很快,但数组也有其缺点 ...
随机推荐
- Android学习笔记:对Android应用进行单元测试
第一步:在AndroidManifest.xml中加入如下两段代码: <manifest xmlns:android="http://schemas.android.com/ap ...
- MySQL学习笔记_7_MySQL常用内置函数
MySQL常用内置函数 说明: 1)可以用在SELECT/UPDATE/DELETE中,及where,orderby,having中 2)在函数里将字段名作为参数,变量的值就是字段所对应的每一行的值. ...
- 使用MD5加密的登陆demo
最近接手了之前的一个项目,在看里面登陆模块的时候,遇到了一堆问题.现在记录下来. 这个登陆模块的逻辑是这样的 1 首先在登陆之前,调用后台的UserLoginAction类的getRandomKey方 ...
- 一个App与另一个App之间的交互,添加了自己的一些理解
URL Scheme 是什么? iOS有个特性就是应用将其自身"绑定"到一个自定义 URL scheme 上,该 scheme用于从浏览器或其他应用中启动本应用.常见的分享到第三方 ...
- ViewPager适配器学习记录( pageAdapter和FragmentPagerAdapter/FragmentStatePagerAdapter))
1.概述 ViewPager,顾名思义实现控件的滚动功能,是Support-v4的包中类,使用前要先导包.使用的时候跟listView有点相似,需要设置对应的适配器,通常有俩大类 [pageAdapt ...
- Java-Enumeration总结
纸上得来终觉浅,绝知此事要躬行 --陆游 问渠那得清如许,为有源头活水来 --朱熹 Enumeration(枚举)接口的作用和Iterator类似,只提供了遍历Vector和HashTabl ...
- 高通android开发摘要
一部分是开源的,可以从codeaurora.org上下载,还有一部分是高通产权的,需要从高通的网站上下载. 将高通产权的代码放到:vendor/qcom/proprietary 1. 设置bms一些参 ...
- 新书《Ext JS 4.2实战》即将出版
目录: 第1章 Ext JS 4概述1.1 从Ext JS 4.0到4.071.2 从4.1到4.1.1a1.3 从4.2到4.2.11.4 如何选择版本1.5 基 ...
- iOS监听模式系列之NSNotificationCenter的简单使用
NSNotificationCenter 对于这个没必要多说,就是一个消息通知机制,类似广播.观察者只需要向消息中心注册感兴趣的东西,当有地方发出这个消息的时候,通知中心会发送给注册这个消息的对象.这 ...
- 分布式版本库——Windows下Git的环境部署以及在GitHub上开源自己的项目
分布式版本库--Windows下Git的环境部署以及在GitHub上开源自己的项目 这几天着实忙的焦头烂额,可惜不是搞技术,今天周日,难得闲下来,写篇大家都想学习的Git教程,其实廖雪峰老师的网站已经 ...