线性表(List)是一种线性结构。其特点是数据元素直线的线性关系。

1.线性表抽象类定义

public abstract class AbsList implements Iterable,List{

protected int length;

abstract public T get(int i); //返回第i(i≥0)个元素

abstract public boolean set(int i, T x); //设置第i个元素值为x

//查找,返回首次出现的关键字为key元素

abstract public int indexOf(int begin,int end,T o);

abstract public void add(int i, T x); //插入x作为第i个元素

abstract public void clear();

abstract public T remove(int i); //删除第i个元素并返回被删除对象

abstract public Iterator iterator();//返回一个迭代器

public boolean isEmpty(){ return length==0;} //判断线性表是否空

public int length(){ return length;} //返回线性表长度

public void add(T x){ add(length,x); } //在线性表最后插入x元素

public void append(T x){ add(length,x); }

public int indexOf(T o){

return indexOf(0,length,o);

}

public int indexOf(int begin,T o){

return indexOf(begin,length,o);

}

public T remove(T o){ //删除第i个元素并返回被删除对象

return remove(indexOf(o));

}

}

1.1初始化:

public Seqlist(int initlen){//initlen初始化容量

if(initlen<0) initlen = 16;

length = 0;

incrementSize = 0;

data = new Object[initlen];

}

//默认构造函数

public Seqlist(){

this(16);

}

//用数组elem初始化顺序表

public Seqlist(T[] elem){

length = elem.length;

incrementSize = 0;

data=Arrays.copyOf(elem,length);//将elem全部存入data

}

1.2容量管理

public void setCapacity(int newsize){

data=Arrays.copyOf(data,newsize);

}

//获取顺序表的最大容量

public int getCapacity(){

return data.length;

}

public void setIncr(inc){

incrementSize=inc;

}

//内部使用,顺序表自动扩容

private void grow(){

int newsize=data.length+incrementSize;

data=Arrays.copyOf(data.newsize);

}

1.3数据存取

public T get(int i)

{

if(i<0 || i>length - 1)

return null;

return (T)data[i];

}

public boolean set(int i,T x)

{

if(i<0 || i>length - 1)

return false;

else

{

data[i] = x;

return true;

}

}

1.4指定位置插入元素

public void add(int i,T x)

{

if(length == data.length)

grow();

if(i<0)

i = 0;

if(i>length)

i = length;

for(int j=length-1;j>=i;j--)

data[j+1] = data[j];

data[i] = x;

length++;

}

public void add(T x)

{

if(length == data.length)

grow();

data[length] = x;

length++;

}

1.5删除顺序表元素

//删除下标为i的元素

public T remove(int i)

{

if(i<0 || i>length -1)

throw new IndexOutOfBoundsException("下标越界 i="+i);

T olddata = (T)data[i];

for(int j=i;j

data[j] = data[j+1];

data[--length] = null;

return olddata;

}

//删除值为o的元素

public T remove(T o)

{

int i =indexOf(o);

return remove(i);

}

//清空顺序表

public void clear()

{

for(int i=0;i

remove(i);

}

1.6查找值为o的数据元素的下标,使用顺序查找算法

//注意:我们许可查到的是null

public int indexOf(T o)

{

if(o == null)

{

for(int i=0;i

if(data[i] == null)

return i;

}

else

{

for(int i=0;i

if(compare(o,(T)data[i]) == 0)

return i;

}

return -1;

}

1.7顺序表中元素有序插入与插入排序

//T数据元素比较方法

protected int compare(T a,T b)

{

if(a instanceof Comparable && b instanceof Comparable)

return ((Comparable) a).compareTo((Comparable)b);

else

return ((String)a).compareTo((String)b);

}

instanceof运算符的前一个操作数是一个引用类型变量,后一个操作数是一个类(接口),用于判断前面的对象是否是后面的类,或子类、实现类的实例。若是,返回true;反之,返回false。

如果a,b均是comparable容器已实现的类型,则用comparable直接比较。

否则,转换为string类比较

//内部使用,有序地插入x

privated void insertOrder(int end,T x)

{

if(length == data.length)

grow();

int k;

for(k=end-1;k>=0;k--)

{

if(compare(x,(T)data[k])<0)

data[k+1] = data[k];

else

break;

}

data[k+1]=x;

}

public void addSort(T x)

{

insertOrder(length,x);

length++;

}

//顺序表排序算法

public void sort()

{

for(int i=0;i

insertOrder(i,(T)data[i]);

}

addSort时间复杂度为O(n) sort为

1.8顺序表转换为数组

public Object[] toArray()

{

return Arrays.copyOf(this.data, this.length);

}

public T[] toArray (T[] a)

{

if(a.length

//创建一个与数组a运行类型相同的新数组,长度可以是0

return (T[])Arrays.copyOf(this.data, this.length,a.getClass());

System.arraycopy(this.data, 0, a, 0, this.length);

if(a.length > this.length)

a[length] = null;

return a;

}

1.9顺序表转换为字符串

public String toString()

{

StringBuilder strb = new StringBuilder();

strb = strb.append("(");

for(int i=0;i

{

strb = strb.append(data[i].toString()+",");

}

strb=strb.append(data[length-1]+")");

String s = new String(strb);

strb=null;

return s;

}

2单链表的定义及其应用

2.1单链表的概念

单链表是一个用指向后继元素的指针将具有线性关系的节点链接起来,最后一个节点的后继指针为空指针。

节点:

class Lnode{

public T data;

public Lnode next;

}

由于节点类由data、next两部分组成,没有Comparable中数据类型的实现。故需改写Comparable中的方法。

节点类新增、改写几个方法:equals,comparaTo,toString

public class Lnode implements Comparable> {

public T data;

public Lnode next;

public Lnode(T key){

data = key;

next = null;

}

public Lnode(T key,Lnode next){

data = key;

this.next = next;

}

//重写的三个方法

public boolean equals (Object e){

@SuppressWarnings("unchecked")

Lnode node =(Lnode)e;

return data.equals(node.data);

}

@SuppressWarnings("unchecked")

public int compareTo(Lnode e) {

Comparable x;

if(data instanceof Comparable){

x = (Comparable)data;

return (int)x.compareTo(e.data);

}

else throw new ClassCastException("类型无法比较");

}

public String toString(){

return data.toString();

}

单链表的定义(部分):

public class LinkList extends AbsList implements Iterable {

Lnode first,last;//头指针与尾指针

Iterator itr = null;//指向当前节点迭代器的指针

public LinkList(){

first = last = null; length = 0;

this.itr = new LinkIterator();

}

public LinkList(int i){

first = last = null; length = 0;

if(i!=-1)

this.itr = new LinkIterator();

}

private int compare(Lnode a,Lnode b)

{

return a.compareTo(b);

}

public void clear()

{

first=last=null;

length=0;

}

public void removeAll()

{

clear();

}

//...

2.2单链表如何存取数据

首先用getNode(i)获取编号为i节点的引用。

链表getNode(i)时间复杂度为O(n)。注意,在顺序表中,复杂度为O(1)

获得引用后,用get(i)取得data值,set(i,x)修改i号节点的值。

protected Lnode getNode(int i)//getNode(i)获取编号为i节点的引用

{

if(i<0 || i>length-1)

return null;

if(i==0)

return first;

Lnode p= first;

int j=0;

while(p!=null&&j

{

p=p.next;

j++;

}

return p;

}

public T get(int i)//从引用中获取值

{

Lnode p=getNode(i);

if(p==null)

return null;

else

return p.data;

}

public boolean set(int i,T x)//在引用中修改值

{

Lnode p=getNode(i);

if(p==null)

return false;

else

{

p.data = x;

return true;

}

}

2.3向链表中插入元素

s=new Lnode(x)

s是指向新结点的引用变量,x是被插入的值。

分四种情况讨论:

1.向空链表插入一个新节点

if(first==null){

first = s;//直接将first指向s即可

last = s;

}

2.在链表头结点之前插入新节点

s.next = first; first=s;

3.在链表中间插入新节

s.next = p.next; p.next=s;

思考,两条语句能否调换位置? 答:不能,p.next=s,此时s未确定,p指向未知位置。

4.在链表尾部插入新节点

last.next=s; last=s;

完整的链表插入算法:

//注意:i是逻辑位置

public void add(int i,T x)

{

Lnodep,s;

int j = i-1;

s=new Lnode(x,null);

if(first==null||length==0)//1.向空链表插入一个新节点

{

first = s; last = s;

}

else if(j<0)//2.在链表头结点之前插入新节点

{

s.next = first; first = s;

}

else if(j>length-1)//4.在链表尾部插入新节点

{

last.next =s; last = s;

}

else //3.在链表中间插入新节

{

p=getNode(j);

s.next=p.next;

p.next=s;

}

length++;

}

//实际开发中,为方便使用,增加的函数

//重载add

public void add(T key){

add(length,key);

}

public void addBack(T key)

{

add(length,key);

}

public void addFront(T key)

{

add(0,key);

}

2.4删除链表节点

分三种情况处理:

1.删除的是空链表(first==null)

链表为空,此时删除非法。

2.被删除的是头结点(i=0)

first = first.next;//即可实现

实际开发中,可能需要被删除的值,故:

p=first;

first = first.next;

return p.data;

3.被删除的节点在中间

q.next = p

return p.data

得知要删除的节点p后,如何准确找到指针q的位置呢

q=getNode(i-1);

完整的删除算法如下:

public T remove(int i)

{

Lnode p=removeNode(i);

if(p!=null)

return p.data;

else

return null;

}

//删除逻辑第i节点,返回节点类型

protected Lnode removeNode(int i)

{

Lnode p,q;

if(first == null) return null;//1.删除的是空链表(first==null)

if(i==0)//2.被删除的是头结点(i=0)

{

p = first; first = first.next; length--;

return p;

}

if(i>=1&&i<=length-1)//3.被删除的节点在中间

{

q=getNode(i-1);

p = q.next;

q.next = p.next;

if(p==last)last = q;

length--;

return p;

}

return null;

}

2.5查找节点

//在begin-end中查找节点

public int indexOf(int begin,int end,T key)

{

Lnodep = getNode(begin);

int i = begin;

while(p!=null&i

{

if(p.data.equals(key)) return i;

p = p.next;

i++;

}

return i;

}

//在全链表中查找节点

public T search(T key)

{

Lnode p = getNode(0);

while(p!=null)

{

if(p.data.equals(key)) return p.data;

p = p.next;

}

return null;

}

//是否存在值为key的节点

public boolean contains(T key)

{

if(indexOf(key)==-1)

return false;

else

return true;

}

2.5向链表中插入有序节点

分四种情况讨论

1.链表为空

first = s;first.next = null;

2.插入节点s的值小于头结点

s.next=first;

first=s;//first 指向新节点

3.插入节点s值大于尾节点

last.next=s;

last=s;

4.插入节点处于中间位置

p1=p2=first;

while(p2.next!=null){

if(p1.datas.data){

将节点插入到p1之后;

break;

}else{

p1=p2;p2=p2.next;

}

}

单链表有序插入算法:

public void addSort(T x)

{

Lnode s=new Lnode(x,null);

insertOrder(s);

}

//核心算法

public void insertOrder(Lnode s)

{

Lnode p1,p2;

length++;

if(first==null)//链表为空

{

first=s;

last=first;

return;

}

if(compare(s,first)<0)//插入到头结点以前

{

s.next=first;

first=s;

return;

}

if(compare(s,last)>=0)//插入到尾节点

{

last.next=first;

last=s;

return;

}

//插入到中央

p2=first;

p1=p2;

while(p2!=null)

{

if(compare(s,p2)>0)//第一次执行必然s>p2

{

p1=p2;

p2=p2.next;

}

else break;

}

s.next=p2;

p1.next=s;

return;

}

2.6链表排序

单链表的插入排序示例:

public void sort()

{

LinkList s1=new LinkList();//有序链表

Lnode p;

p=this.getNode(0);//取出无序链表的头结点,this是调用这个方法的链表

while(p!=null)

{

s1.insertOrder(p);

p=this.getNode(0);

}

this.first=s1.first;

this.last=s1.last;

this.length=s1.length;

}

总结:1.若是要在单链表中插入、删除一个节点,必须知道其前驱结点。

2.单链表不具有按序号随机处理的特点,只能从头指针一个一个顺序进行。

2.7链表转换为字符组/数组

public String toString(Lnode first)

{

String s;

Lnode p;

p =first; s="(";

while(p!=null)

{

s=s+p.data.toString();

p = p.next;

}

return s= s+")\n";

}

public Object[] toArrays()

{

Object[] a=new Object[length];

Lnode p=first;

for(int i=0;i

{

a[i] = p.data;

p=p.next;

}

return a;

}

3.循环链表与双向链表

3.1单循环链表

具有单链表的特征,无需增加额外存储空间,对链表的处理更加灵活,整个链表构成一个环, 可以遍历已经访问过的元素。

在建立循环链表时,必须使最后一个节点的指针指向表头节点,而不是null。

在判断是否到表尾是.first==rear,而不是后继结点为null。

3.2双向链表

class DoubleNode(){

public int data;

public DoubleNode prior;

public DoubleNode next;

}

1.双链表的插入运算

s= new DoubleNode;

s.data=e;

s.next=p.next;

p.next.prior=s;

p.next=s;

s.prior=p;//一定要注意顺序

2.双链表的删除运算

直接断开节点间链接关系

删除s:

s.prior.next = s.next;

s.next.prior = s.prior;

4.额外补充:顺序表与链表的比较

一、顺序表的特点是逻辑上相邻的数据元素,物理位置相邻,

并且,顺序表的存储空间需要预先分配。

它的优点是:

(1)方法简单,各种高级语言中都有数组,易实现。

(2)不用为表示节点间的逻辑关系而增加额外的存储开销。

(3)顺序表具有按元素序号随机访问的特点。

缺点:

(1)在顺序表中做插入、删除操作时,平均移动表中的一半元素,因此对n较大的顺序表效率低。

(2)需要预先分配足够大的存储空间(难以估计),估计过大,可能会导致顺序表后部大量闲置;

预先分配过小,又会造成溢出。

二、在链表中逻辑上相邻的数据元素,物理存储位置不一定相邻,它使用**指针实现元素之间的

逻辑关系。并且,链表的存储空间是动态分配**的。

链表的最大特点是:

插入、删除运算方便。

缺点:

(1)要占用额外的存储空间存储元素之间的关系,存储密度降低。

存储密度是指一个节点中数据元素所占的存储单元和整个节点所占的存储单元之比。

(2)链表不是一种随机存储结构,不能随机存取元素。

三、顺序表与链表的优缺点切好相反,那么在实践应用中怎样选取存储结构呢?

通常有以下几点考虑:

(1)“MaxSize”分配,动态?静态?

当对线性表的长度或存储规模难以估计时,不宜采用顺序表。

当线性表的长度变化不大而且事先容易确定其大小时,为节省存储空间,

则采用顺序表作为存储结构比较适宜。

(2)基于运算的考虑(时间)

顺序存储是一种随机存取的结构,而链表则是一种顺序存取结构,

如果频繁按序号访问数据元素,显然顺表优于链表。

如果频繁增删,显然链表优于顺表。

(3)基于环境的考虑(语言)

顺序表容易实现,任何高级语言中都有数组类型;

链表的操作是基于指针的。相对来讲前者简单些,也用户考虑的一个因素。

总结: 通常“较稳定”的线性表,即主要操作是查找操作的线性表,适于选择顺序存储;

而频繁做插入删除运算的(即动态性比较强)的线性表适宜选择链式存储。

不得转载。

java拆装_JAVA线性表拆解相关推荐

  1. java 线性表排序_Java线性表的排序

    Java线性表的排序 前言:刚才在弄JDBC的时候,忽然觉得order-by用太多了没新鲜感,我的第六感告诉我java有对线性表排序的封装,然后在eclipse里随便按了一下"." ...

  2. Java数据结构之线性表(2)

    从这里开始将要进行Java数据结构的相关讲解,Are you ready?Let's go~~ java中的数据结构模型可以分为一下几部分: 1.线性结构 2.树形结构 3.图形或者网状结构 接下来的 ...

  3. 线性链表java实现_线性表的Java实现--链式存储(双向链表)

    线性表的Java实现--链式存储(双向链表) 有了单向链表的基础,双向链表的实现就容易多了. ? 双向链表的一般情况: ? ? class="decoded" alt=" ...

  4. 【Java数据结构】线性表

    线性表 线性表是最基本.最简单.也是最常用的一种数据结构. 线性表中数据元素之间的关系是一对一的关系,即除了第一个和最后一个数据元素之外,其它数据元素都是首尾相接的(注意,这句话只适用大部分线性表,而 ...

  5. 线性查找法java代码_Java线性查找和二分查找

    Java线性查找和二分查找. 一 线性查找 定义:在一列给定的值中进行搜索,从一端开始逐一检查每个元素,直到找到所需元素的过程. 线性查找又称为顺序查找.如果查找池是某种类型的一个表,比如一个数组,简 ...

  6. java拆装_Java自动拆装包

    Java自动拆装包的例子 这段代码在Java 1.5以前是不合法的 Long v = 0: v += 1: 需要写成这样: Long v = 0: v += new Long(1); 在Java 1. ...

  7. 数据结构:线性表(java实现)

    点个赞,看一看,好习惯!本文 GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了 3 个月总结的一线大厂 Java 面试总结,本 ...

  8. 使用Java模拟线性表顺序存储结构

    在数据结构中,线性表分两种结构 顺序结构和链表结构 下面使用Java模拟一下顺序结构 主要难点在顺序结构的插入和删除 import java.util.ArrayList;//线性表顺序存储结构 pu ...

  9. 【数据结构基础】线性数据结构——线性表概念 及 数组的封装(C和Java)

    前言 数据结构,一门数据处理的艺术,精巧的结构在一个又一个算法下发挥着他们无与伦比的高效和精密之美,在为信息技术打下坚实地基的同时,也令无数开发者和探索者为之着迷. 也因如此,它作为博主大二上学期最重 ...

最新文章

  1. 队列优化dijsktra(SPFA)的玄学优化
  2. 计算机网络第五章:运输层
  3. echarts 堆叠树状图排序
  4. linux环境中,top命令中,对command的命令进行扩展查看详情?
  5. axure如何实现跳转_Axure教程:网易云音乐首页原型设计
  6. 将Windows MyEclipse的web项目移植到Debian下
  7. 程序员出差是去干什么_让我来告诉你,35岁以上的人都在干什么!
  8. 安装python37路径报错_解决pycharm安装python库报错问题
  9. opencv中的图像拼接
  10. laravel上传文件到s3,打开链接无法下载而是直接在浏览器中显示内容
  11. HealthKit 的新增功能
  12. vue-awesome-swiper的点击事件
  13. 关于扫码签到统计信息,一键导出excel表
  14. android手机电池寿命,安卓手机如何查电池使用寿命
  15. 基于51单片机的万年历(带温湿度)带闹钟功能proteus仿真原理图PCB
  16. 真正解决Word中表格首行字母或首列字母(首字母)大写的问题
  17. 大作业系列之体育课 | 从NBA中看篮球精神
  18. Dual Regression Networks for SISR 环境搭建 | 2020Paper | 【❤️Pytorch 实现❤️】
  19. 满屏飞舞的心HTML动画,CSS3制作蝴蝶飞舞动画
  20. php打印文字到图片,【PHP】打开一个图片然后加上水印(图片上生成文字)

热门文章

  1. 小程序picker标题_微信小程序-自定义picker选择器
  2. linux vps 命令,CentOS最常用Linux vps操作命令整理大全
  3. 便携式不锈钢管道焊接机器人_304不锈钢管居然可以发黑?
  4. 前端工程师应该达到什么水平,找工作薪资才比较高?
  5. mysql as tmp,启动mysql时显示:/tmp/mysql.sock 不存在的解决办法
  6. Telnet初试(本地测试)
  7. 浅谈servlet与jsp的关系
  8. AngularJS XMLHttpRequest
  9. vue使用v-for循环,动态修改element-ui的el-switch
  10. 仿淘宝网站的TabPage导航效果