java拆装_JAVA线性表拆解

线性表(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为a4ec902e620b74114a88cab4afbd95b7.png

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单链表的概念

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

296e311210df5ad63f4345a29f0ce327.png

节点:

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.在链表中间插入新节

024be381dcc0e9fb85edaeed7a2ebff2.png

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

a52c612ea3bd8115823fac5e81fb80af.png

得知要删除的节点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单循环链表

5866eee9569c539ba176b9bdc9340ace.png

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

在建立循环链表时,必须使最后一个节点的指针指向表头节点,而不是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;//一定要注意顺序

faa25e7287b455054634825555d422e1.png

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)基于环境的考虑(语言)

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

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

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

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

不得转载。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/376085.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【BZOJ】【1041】【HAOI2008】圆周上的点

数学 orz hzwer 完全不会做…… 很纠结啊&#xff0c;如果将来再遇到这种题&#xff0c;还是很难下手啊…… 引用题解&#xff1a; 【分析】&#xff1a; 样例图示&#xff1a; 首先,最暴力的算法显而易见&#xff1a;枚举x轴上的每个点&#xff0c;带入圆的方程&#xff0c;检…

【Android】配置APK开发环境

【Android】配置APK开发环境1.安装java jdk去oracle公司下载jdk-7u15-windows-i586.exehttp://www.oracle.com/technetwork/cn/java/javase/downloads/jdk7-downloads-1880260-zhs.html---C:\Documents and Settings\XXXX>java -versionjava version "1.7.0_15"Ja…

20135127陶俊杰 实验一

北京电子科技学院(BESTI) 《Java程序设计》课实验报告 班 级&#xff1a;201351 姓名及学号&#xff1a;陶俊杰 20135127 指导教师&#xff1a;娄佳鹏 必修/选修&#xff1a;选修 实验日期&#xff1a; 2015年4月16日 实验时间&…

Google Code Jam 2015 Round 1A Haircut 二分

题意&#xff1a;给你每个理发师的理发时间&#xff0c;问你排在队列中的第N个位置&#xff0c;问你应该被哪个理发师剪发。 解题思路&#xff1a;二分时间&#xff0c;看这个时间到第几个人理发了&#xff0c;然后找到临界值&#xff0c;看这个值的时候有那些理发师接待了新旅…

Base64 百科词条

Base64是一种基于64个可打印字符来表示二进制数据的表示方法。由于2的6次方等于64&#xff0c;所以每6个位元为一个单元&#xff0c;对应某个可打印字符。三个字节有24个位元&#xff0c;对应于4个Base64单元&#xff0c;即3个字节需要用4个可打印字符来表示。它可用来作为电子…

java获取mysql执行计划_好程序员Java学习路线之MySQL的执行计划

好程序员Java学习路线之MySQL的执行计划。什么是执行计划&#xff1f;执行计划通常是开发者优化SQL语句的第一步。MySQL在解析SQL语句时&#xff0c;会生成多套执行方案&#xff0c;然后内部会进行一个成本的计算&#xff0c;然后通过优化器选择一个最优的方案执行&#xff0c;…

Web系统开发构架再思考-前后端的完全分离

前言 前后端完全分离其实一直是Web开发人员的梦想,也一直是我的梦想,遥想当年,无论是直接在代码里面输出HTML,还是在HTML里面嵌入各种代码,都不能让人感到满意.期间的痛苦和纠结,我想所有Web开发人员都深有感触. 由于最近几年一直在MS平台,从Web Form到MVC,MS平台虽然易用好学,…

文科思维Java_开源之Processing:这好玩的编程语言是为文科生艺术家准备的

说起编程语言&#xff0c;我们很多时候第一反应就是很难&#xff0c;都是理工科计算机相关行业的人才学的&#xff0c;都是为理科生掉头发准备的。的确&#xff0c;计算机的严谨&#xff0c;注定要求开发应用的人有缜密的理工科的理性逻辑思维&#xff0c;然而一人客从另一方面…

poj 1862 Stripies/优先队列

原题链接&#xff1a;http://poj.org/problem?id1862 简单题&#xff0c;贪心优先队列主要练习一下stl大根堆 写了几种实现方式写成类的形式还是要慢一些。。。 手打的heap&#xff1a; 1&#xff1a; 1 #include<cstdio>2 #include<cstdlib>3 #include<cmath&…

java timezone id_java.util.TimeZone.setID()方法实例

全屏setID(String ID)方法被用于设置时区ID。这不会改变的时区对象中的任何其他数据。声明以下是java.util.TimeZone.setID()方法的声明。public void setID(String ID)参数ID--这是新的时区ID。返回值NA异常NA例子下面的例子显示java.util.TimeZone.setID()方法的使用package …

创建一个自己的GitHub,创建自己的开源项目

作者是一个大学在读学生&#xff0c;自己在平时的学习中&#xff0c;GitHub上的开源项目给自己提供了很大的帮助。GitHub是目前使用最广泛的分布式项目管理软件&#xff0c;GitHub上面托管了许多非常优秀的开源项目。我觉得每一个从事IT行业都应该有一个属于自己的GitHub。下面…

Ubuntu如何安装setuptools

首先百度setuptools&#xff0c;基本第一个就是官网的结果然后我们看到有两个这样的文件第一个不用想了&#xff0c;如果你要使用第一个的话&#xff0c;还要首先安装wheel。我们这里直接用鼠标选中第二个zip文件&#xff0c;然后右键&#xff0c;复制链接。然后在我们的Ubuntu…

JMeter学习(四)参数化、断言、集合点

1.参数化 录制脚本中有登录操作&#xff0c;需要输入用户名和密码&#xff0c;假如系统不允许相同的用户名和密码同时登录&#xff0c;或者想更好的模拟多个用户来登录系统。 这个时候就需要对用户名和密码进行参数化&#xff0c;使每个虚拟用户都使用不同的用户名和密码进行访…

php class使用方法,php的类使用方法问题

php的类使用方法&#xff1a;1、类通过class关键字来定义&#xff1b;2、访问对象的时候&#xff0c;属性名前不要加【$】&#xff1b;3、通过【->】访问修改类内成员变量&#xff1b;4、函数的返回值通过return来返回。php的类使用方法&#xff1a;1.语法说明和其他语言一样…

详解汇编语言中乘法指令:MUL、IMUL

本文参考了马维华老师的《微机原理与接口技术》一书 指令格式&#xff1a; MUL REG/MEM &#xff1b;REG寄存器&#xff0c;MEM存储器 IMUL REG/MEM MUL和IMUL指令分别用于实现无符号数的乘法和有符号数的乘法运算。都只有一个源操作数&#xff0c;可以使寄存器或存储…

构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(44)-工作流设计-设计表单...

构建ASP.NET MVC4EF5EasyUIUnity2.x注入的后台管理系统&#xff08;44&#xff09;-工作流设计-设计表单 原文:构建ASP.NET MVC4EF5EasyUIUnity2.x注入的后台管理系统&#xff08;44&#xff09;-工作流设计-设计表单系列目录 设计表单是比较复杂的一步&#xff0c;完成一个表单…

php如何转类型,PHP数据类型转换

指的是将数据(变量)的值转换成目标数据类型。PHP中有两种数据类型转换方式&#xff1a;自动转换&#xff0c;强制转换自动转换&#xff1a;系统根据操作所需要的类型将变量的值进行对应类型的转换自动转换都是系统本身所做的事情&#xff0c;不需要用户去干预。强制转换&#x…

dz打不开plugin. php,Discuz!应用中心打不开空白的解决方法

近期&#xff0c;很多使用Discuz!程序建论坛的站长都会发现&#xff0c;Discuz!后台的应用中心打不开了。这二天Discuz!终于给出了原因&#xff1a;十分抱歉的通知您&#xff0c;由于资源和人力投入问题&#xff0c;我们已经关闭了 www.discuz.net 的发言权限&#xff0c;但是历…

ECshop安装及报错解决方案总结

一、安装ECshop ECShop是一款B2C独立网店系统 &#xff0c;适合企业及个人快速构建个性化网上商店。系统是基于PHP语言及MYSQL数据库构架开发的跨平台开源程序。2006年3月推出以来1.0版以来&#xff0c;受到市场的检验&#xff0c;广受好评。 1.安装准备 ECshop最新版本为2.7.3…