java线性表降序_数据结构(java)之线性表

1.线性表的抽象数据类型

a)数据元素:任意同属一类对象的数据对象

b)数据关系:线性关系,除第一个元素外,每个元素都有唯一的直接前驱元素,除最后一个元素外,每个元素都有唯一后继元素

c)数据操作:定义在IList结构中,代码如下

publicinterfaceIList {

booleanadd(Ee);

booleaninsert(Ee,intindex);

E remove(intindex);

intindexof(Ee);

E get(intindex);

intsize();

voidclear();

booleanisEmpty();

booleanisFull();

}

2.线性表实现之顺序表:使用MyArrayList类实现IList接口

a)顺序表的存储结构:由一个数组存储,下标为0的元素为顺序表第一个元素

b)顺序标基本操作

i.初始化顺序表:创建一个空顺序表,申请一个存储大小为maxsize的数组空间,并将数组已存储元素个数size设置为0

ii.向顺序表末尾添加元素:找到顺序表最后一个元素下标size,在第size+1个位置添加元素,并将size自增

iii.删除元素:首先找到顺序表中数组下标为i的元素并将其存放在临时变量中,然后从第i个元素开始到最后一个元素,使每个元素值等于其下一个元素的指,然后将size自减,并返回临时变量

c)代码实现

publicclassMyArrayListimplementsIList {

privateEdata[];

privateintmaxsize;

privateintsize;

//构造方法初始化线性表

publicMyArrayList(intmaxsize) {

super();

this.maxsize=maxsize;

this.data=(E[])newObject[maxsize];//不能创建泛型数组,通过Object类来强转为泛型

this.size=0;

}

@Override

publicbooleanadd(Ee) {

while(!this.isFull()) {

this.size++;

this.data[this.size]=e;

returntrue;

}

returnfalse;

}

@Override

//在下标为index的位置插入e

publicbooleaninsert(Ee,intindex) {

this.check(index);//检查下表是否合法

while(!this.isFull()) {

for(inti=this.size;i>=index;i--) {

this.data[i+1]=data[i];

}

this.data[index]=e;

this.size++;

returntrue;

}

returnfalse;

}

@Override

//删除下标为index的元素

publicE remove(intindex) {

this.check(index);//检查下标

Etemp;

temp=this.data[index];

for(inti=index;i

this.data[i]=this.data[i+1];

}

this.size--;

returntemp;

}

@Override

publicintindexof(Ee) {

for(inti=1;i<=this.size;i++) {

if(this.data[i]==e)

returni;

}

return-1;

}

@Override

publicE get(intindex) {

this.check(index);//检查下表

returnthis.data[index];

}

@Override

publicintsize() {

returnthis.size;

}

@Override

publicvoidclear() {

this.size=0;

}

@Override

publicbooleanisEmpty() {

if(this.size==0)

returntrue;

returnfalse;

}

@Override

publicbooleanisFull() {

if(this.size>=this.maxsize-1)

returntrue;

returnfalse;

}

//判断输入的下标是否越界

publicvoidcheck(intindex) {

if(index<=0||index>this.size)

thrownewIndexOutOfBoundsException("index is "+index+",last element's index is "+(this.size-1));

}

}

3.线性表实现之单链表:使用MyLinkList类实现IList接口

a)单链表的存储结构:由节点组成,每个节点存储一个元素并指向下一个节点,每个单链表都有一个头节点,头节点中不存储数据元素,只存储指向下一个节点

b)单链表的基本操作

i.初始化单链表:为头节点申请空间,将头节点数据元素和下一节点元素都设为null,并将单链表元素个数size设为0

ii.在末尾添加节点:首先通过遍历得到最后一个节点对象,然后申请一个新的节点,节点数据元素设位给定的数据,指向下一节点值设为null,然后将最后一个节点对象的next设为新申请的节点,并将单链表元素个数size自增

iii.删除指定节点元素:通过遍历得到指定节点对象的上一个节点对象和下一个节点对象,然后将上一个节点的next设置为指定节点的下一个节点,将指定节点对象的next设为null,并返回指定节点的数据,然后将单链表节点个数size自减

c)代码实现

classNode{

privateEe;

privateNodenext;

publicNode(Ee, Nodenext) {

super();

this.e=e;

this.next=next;

}

publicE getE() {

returnthis.e;

}

publicvoidsetE(Ee) {

this.e=e;

}

publicNode getNext() {

returnthis.next;

}

publicvoidsetNext(Nodenext) {

this.next=next;

}

}

publicclassMyLinkListimplementsIList {

privateNodestart;

privateintsize;

publicMyLinkList() {

super();

this.start=newNode(null,null);

this.size=0;

}

@Override

publicbooleanadd(Ee) {

Nodetemp=this.start;

while(temp.getNext()!=null){

temp=temp.getNext();

}

if(temp.getNext()==null) {

Nodenode=newNode(e,null);

temp.setNext(node);

this.size++;

returntrue;

}

else

returnfalse;

}

@Override

publicbooleaninsert(Ee,intindex) {

if(index>this.size||index<0) {

thrownewIndexOutOfBoundsException("下标错误");

}

else{

Nodetemp=this.start;

Nodenode=newNode(e,null);

for(inti=0;i

temp=temp.getNext();

}

Nodecurr=temp.getNext();

temp.setNext(node);

node.setNext(curr);

this.size++;

returntrue;

}

}

@Override

publicE remove(intindex) {

if(index>this.size||index<=0) {

thrownewIndexOutOfBoundsException("下标错误");

}

else{

Nodetemp=this.start;

for(inti=1;i

temp=temp.getNext();

}

Nodenode=temp.getNext();

Nodecurr=temp.getNext().getNext();

temp.setNext(curr);

node.setNext(null);

this.size--;

returnnode.getE();

}

}

@Override

publicintindexof(Ee) {

Nodetemp=this.start;

intindex=0;

while(temp.getNext()!=null) {

temp=temp.getNext();

index++;

if(temp.getE()==e) {

returnindex;

}

}

return-1;

}

@Override

publicE get(intindex) {

if(index>this.size||index<=0) {

thrownewIndexOutOfBoundsException("下标错误");

}

Nodetemp=this.start;

for(inti=1;i<=index;i++) {

temp=temp.getNext();

}

returntemp.getE();

}

@Override

publicintsize() {

returnthis.size;

}

@Override

publicvoidclear() {

this.start.setNext(null);

this.size=0;

}

@Override

publicbooleanisEmpty() {

if(this.size==0)

returntrue;

returnfalse;

}

@Override

publicbooleanisFull() {

//TODOAuto-generated method stub

returnfalse;

}

}

4.线性表实现之双向链表

a)双向链表的存储结构:由节点组成,每个节点由数据元素以及指向前一个节点的pre和指向后一个节点的next组成,每个双向链表都有一个头节点,头节点的数据元素和pre都是null,next指向下一个元素

b)双向链表的基本操作

i.初始化双向链表:为头节点申请空间,并将头节点的数据元素、pre、next都设为null,链表节点个数size设为0

ii.向末尾添加元素:为新节点申请空间,并将数据设为指定数据,将链表最后一个元素的next指向新节点,将新节点的pre设为链表最后一个元素,新节点的next设为null

5.线性表实现之循环链表:将最后一个元素的next指向头节点的单向链表

6.应用:约瑟夫环

a)约瑟夫环:假设编号从1、2、3…n的n个人顺时针围坐一圈,每人持有随机生成的一个密码m(1-5),从指定编号为1的位置开始报数,到1号的密码m位置,m出列,并将他的密码作为m,他的下一个位置为1重新开始报数,知道所有人全部出列,设计一个程序求出出列顺序

b)代码实现

//约瑟夫节点,包括号码和密码

classJosephusNode {

privateintno;

privateintpwd;

publicJosephusNode(intno,intpwd) {

super();

this.no=no;

this.pwd=pwd;

}

publicintgetNo() {

returnno;

}

publicvoidsetNo(intno) {

this.no=no;

}

publicintgetPwd() {

returnpwd;

}

publicvoidsetPwd(intpwd) {

this.pwd=pwd;

}

@Override

publicString toString() {

return"("+this.no+","+this.pwd+")";

}

}

publicclassJosephus {

privateIListlist;

privateintnum;

//初始化约瑟夫环,为环中每个节点分配no和1-5的密码

publicJosephus(IListlist,intnum) {

super();

this.list=list;

this.num=num;

for(inti=1;i<=num;i++) {

intno=i;

intpwd=(int)(Math.random()*5)+1;

list.add(newJosephusNode(no,pwd));

}

}

publicintgetNum() {

returnnum;

}

publicvoidsetNum(intnum) {

this.num=num;

}

//返回环中序号为index的节点

publicJosephusNode get(intindex) {

returnlist.get(index);

}

//出环游戏

publicvoidgame() {

intstart=1;//从1号开始

intcnt;

System.out.println("游戏开始");

for(inti=1;i<=this.num;i++) {

//出列号码是start开始计数start对应的密码位

cnt=(start+this.list.get(start).getPwd()-2)%this.list.size()+1;

System.out.println(this.list.remove(cnt));

if(this.list.size()==0)

break;

start=(cnt-1)%this.list.size()+1;

}

}

}

7.不同结构的线性表复杂度分析

a)顺序表

i.插入:boolean insert(E e,int index);顺序表的插入时间主要耗费在移动数据元素上,时间复杂度为O(n)

ii.删除:E remove(int index);顺序表的删除时间主要耗费在移动数据元素上,时间复杂度为O(n)

iii.取表元素:E get(int index);顺序表的取表元素只需要按照给定序号查找对应数组元素,时间复杂度为O(1)

iv.定位元素:int indexOf(E e);顺序表的定位时间主要耗费在元素比较上,时间复杂度为O(n)

b)单链表

i.插入:boolean insert(E e,int index);单链表的插入时间主要耗费在查找插入位置上,时间复杂度为O(n)

ii.删除:E remove(int index);单链表的删除时间主要耗费在查找删除位置上,时间复杂度为O(n)

iii.取表元素:E get(int index);单链表的取表元素时间主要耗费在查找取表元素位置上,时间复杂度为O(n)

iv.定位元素:int indexOf(E e);单链表的定位时间主要耗费在元素比较上,时间复杂度为O(n)

c)总结:由于顺序表的元素存储是连续的,所以查找很方便,效率很高,但是插入和删除需要移动大量的元素,效率很低;单链表中由于数据存储是不连续的,所以插入和删除的效率很高,但是查找需要从头开始遍历,所以效率较低。因此,如果需要进行大量的查找等操作而不经常插入或删除,采用顺序表,反之,采用链表。

1.线性表的抽象数据类型

a)数据元素:任意同属一类对象的数据对象

b)数据关系:线性关系,除第一个元素外,每个元素都有唯一的直接前驱元素,除最后一个元素外,每个元素都有唯一后继元素

c)数据操作:定义在IList结构中,代码如下

publicinterfaceIList {

booleanadd(Ee);

booleaninsert(Ee,intindex);

E remove(intindex);

intindexof(Ee);

E get(intindex);

intsize();

voidclear();

booleanisEmpty();

booleanisFull();

}

2.线性表实现之顺序表:使用MyArrayList类实现IList接口

a)顺序表的存储结构:由一个数组存储,下标为0的元素为顺序表第一个元素

b)顺序标基本操作

i.初始化顺序表:创建一个空顺序表,申请一个存储大小为maxsize的数组空间,并将数组已存储元素个数size设置为0

ii.向顺序表末尾添加元素:找到顺序表最后一个元素下标size,在第size+1个位置添加元素,并将size自增

iii.删除元素:首先找到顺序表中数组下标为i的元素并将其存放在临时变量中,然后从第i个元素开始到最后一个元素,使每个元素值等于其下一个元素的指,然后将size自减,并返回临时变量

c)代码实现

publicclassMyArrayListimplementsIList {

privateEdata[];

privateintmaxsize;

privateintsize;

//构造方法初始化线性表

publicMyArrayList(intmaxsize) {

super();

this.maxsize=maxsize;

this.data=(E[])newObject[maxsize];//不能创建泛型数组,通过Object类来强转为泛型

this.size=0;

}

@Override

publicbooleanadd(Ee) {

while(!this.isFull()) {

this.size++;

this.data[this.size]=e;

returntrue;

}

returnfalse;

}

@Override

//在下标为index的位置插入e

publicbooleaninsert(Ee,intindex) {

this.check(index);//检查下表是否合法

while(!this.isFull()) {

for(inti=this.size;i>=index;i--) {

this.data[i+1]=data[i];

}

this.data[index]=e;

this.size++;

returntrue;

}

returnfalse;

}

@Override

//删除下标为index的元素

publicE remove(intindex) {

this.check(index);//检查下标

Etemp;

temp=this.data[index];

for(inti=index;i

this.data[i]=this.data[i+1];

}

this.size--;

returntemp;

}

@Override

publicintindexof(Ee) {

for(inti=1;i<=this.size;i++) {

if(this.data[i]==e)

returni;

}

return-1;

}

@Override

publicE get(intindex) {

this.check(index);//检查下表

returnthis.data[index];

}

@Override

publicintsize() {

returnthis.size;

}

@Override

publicvoidclear() {

this.size=0;

}

@Override

publicbooleanisEmpty() {

if(this.size==0)

returntrue;

returnfalse;

}

@Override

publicbooleanisFull() {

if(this.size>=this.maxsize-1)

returntrue;

returnfalse;

}

//判断输入的下标是否越界

publicvoidcheck(intindex) {

if(index<=0||index>this.size)

thrownewIndexOutOfBoundsException("index is "+index+",last element's index is "+(this.size-1));

}

}

3.线性表实现之单链表:使用MyLinkList类实现IList接口

a)单链表的存储结构:由节点组成,每个节点存储一个元素并指向下一个节点,每个单链表都有一个头节点,头节点中不存储数据元素,只存储指向下一个节点

b)单链表的基本操作

i.初始化单链表:为头节点申请空间,将头节点数据元素和下一节点元素都设为null,并将单链表元素个数size设为0

ii.在末尾添加节点:首先通过遍历得到最后一个节点对象,然后申请一个新的节点,节点数据元素设位给定的数据,指向下一节点值设为null,然后将最后一个节点对象的next设为新申请的节点,并将单链表元素个数size自增

iii.删除指定节点元素:通过遍历得到指定节点对象的上一个节点对象和下一个节点对象,然后将上一个节点的next设置为指定节点的下一个节点,将指定节点对象的next设为null,并返回指定节点的数据,然后将单链表节点个数size自减

c)代码实现

classNode{

privateEe;

privateNodenext;

publicNode(Ee, Nodenext) {

super();

this.e=e;

this.next=next;

}

publicE getE() {

returnthis.e;

}

publicvoidsetE(Ee) {

this.e=e;

}

publicNode getNext() {

returnthis.next;

}

publicvoidsetNext(Nodenext) {

this.next=next;

}

}

publicclassMyLinkListimplementsIList {

privateNodestart;

privateintsize;

publicMyLinkList() {

super();

this.start=newNode(null,null);

this.size=0;

}

@Override

publicbooleanadd(Ee) {

Nodetemp=this.start;

while(temp.getNext()!=null){

temp=temp.getNext();

}

if(temp.getNext()==null) {

Nodenode=newNode(e,null);

temp.setNext(node);

this.size++;

returntrue;

}

else

returnfalse;

}

@Override

publicbooleaninsert(Ee,intindex) {

if(index>this.size||index<0) {

thrownewIndexOutOfBoundsException("下标错误");

}

else{

Nodetemp=this.start;

Nodenode=newNode(e,null);

for(inti=0;i

temp=temp.getNext();

}

Nodecurr=temp.getNext();

temp.setNext(node);

node.setNext(curr);

this.size++;

returntrue;

}

}

@Override

publicE remove(intindex) {

if(index>this.size||index<=0) {

thrownewIndexOutOfBoundsException("下标错误");

}

else{

Nodetemp=this.start;

for(inti=1;i

temp=temp.getNext();

}

Nodenode=temp.getNext();

Nodecurr=temp.getNext().getNext();

temp.setNext(curr);

node.setNext(null);

this.size--;

returnnode.getE();

}

}

@Override

publicintindexof(Ee) {

Nodetemp=this.start;

intindex=0;

while(temp.getNext()!=null) {

temp=temp.getNext();

index++;

if(temp.getE()==e) {

returnindex;

}

}

return-1;

}

@Override

publicE get(intindex) {

if(index>this.size||index<=0) {

thrownewIndexOutOfBoundsException("下标错误");

}

Nodetemp=this.start;

for(inti=1;i<=index;i++) {

temp=temp.getNext();

}

returntemp.getE();

}

@Override

publicintsize() {

returnthis.size;

}

@Override

publicvoidclear() {

this.start.setNext(null);

this.size=0;

}

@Override

publicbooleanisEmpty() {

if(this.size==0)

returntrue;

returnfalse;

}

@Override

publicbooleanisFull() {

//TODOAuto-generated method stub

returnfalse;

}

}

4.线性表实现之双向链表

a)双向链表的存储结构:由节点组成,每个节点由数据元素以及指向前一个节点的pre和指向后一个节点的next组成,每个双向链表都有一个头节点,头节点的数据元素和pre都是null,next指向下一个元素

b)双向链表的基本操作

i.初始化双向链表:为头节点申请空间,并将头节点的数据元素、pre、next都设为null,链表节点个数size设为0

ii.向末尾添加元素:为新节点申请空间,并将数据设为指定数据,将链表最后一个元素的next指向新节点,将新节点的pre设为链表最后一个元素,新节点的next设为null

5.线性表实现之循环链表:将最后一个元素的next指向头节点的单向链表

6.应用:约瑟夫环

a)约瑟夫环:假设编号从1、2、3…n的n个人顺时针围坐一圈,每人持有随机生成的一个密码m(1-5),从指定编号为1的位置开始报数,到1号的密码m位置,m出列,并将他的密码作为m,他的下一个位置为1重新开始报数,知道所有人全部出列,设计一个程序求出出列顺序

b)代码实现

//约瑟夫节点,包括号码和密码

classJosephusNode {

privateintno;

privateintpwd;

publicJosephusNode(intno,intpwd) {

super();

this.no=no;

this.pwd=pwd;

}

publicintgetNo() {

returnno;

}

publicvoidsetNo(intno) {

this.no=no;

}

publicintgetPwd() {

returnpwd;

}

publicvoidsetPwd(intpwd) {

this.pwd=pwd;

}

@Override

publicString toString() {

return"("+this.no+","+this.pwd+")";

}

}

publicclassJosephus {

privateIListlist;

privateintnum;

//初始化约瑟夫环,为环中每个节点分配no和1-5的密码

publicJosephus(IListlist,intnum) {

super();

this.list=list;

this.num=num;

for(inti=1;i<=num;i++) {

intno=i;

intpwd=(int)(Math.random()*5)+1;

list.add(newJosephusNode(no,pwd));

}

}

publicintgetNum() {

returnnum;

}

publicvoidsetNum(intnum) {

this.num=num;

}

//返回环中序号为index的节点

publicJosephusNode get(intindex) {

returnlist.get(index);

}

//出环游戏

publicvoidgame() {

intstart=1;//从1号开始

intcnt;

System.out.println("游戏开始");

for(inti=1;i<=this.num;i++) {

//出列号码是start开始计数start对应的密码位

cnt=(start+this.list.get(start).getPwd()-2)%this.list.size()+1;

System.out.println(this.list.remove(cnt));

if(this.list.size()==0)

break;

start=(cnt-1)%this.list.size()+1;

}

}

}

7.不同结构的线性表复杂度分析

a)顺序表

i.插入:boolean insert(E e,int index);顺序表的插入时间主要耗费在移动数据元素上,时间复杂度为O(n)

ii.删除:E remove(int index);顺序表的删除时间主要耗费在移动数据元素上,时间复杂度为O(n)

iii.取表元素:E get(int index);顺序表的取表元素只需要按照给定序号查找对应数组元素,时间复杂度为O(1)

iv.定位元素:int indexOf(E e);顺序表的定位时间主要耗费在元素比较上,时间复杂度为O(n)

b)单链表

i.插入:boolean insert(E e,int index);单链表的插入时间主要耗费在查找插入位置上,时间复杂度为O(n)

ii.删除:E remove(int index);单链表的删除时间主要耗费在查找删除位置上,时间复杂度为O(n)

iii.取表元素:E get(int index);单链表的取表元素时间主要耗费在查找取表元素位置上,时间复杂度为O(n)

iv.定位元素:int indexOf(E e);单链表的定位时间主要耗费在元素比较上,时间复杂度为O(n)

c)总结:由于顺序表的元素存储是连续的,所以查找很方便,效率很高,但是插入和删除需要移动大量的元素,效率很低;单链表中由于数据存储是不连续的,所以插入和删除的效率很高,但是查找需要从头开始遍历,所以效率较低。因此,如果需要进行大量的查找等操作而不经常插入或删除,采用顺序表,反之,采用链表。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值