博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
数据结构 Java实现单链表和线性表
阅读量:5323 次
发布时间:2019-06-14

本文共 16461 字,大约阅读时间需要 54 分钟。

Java数据结构与算法基础

数据的逻辑结构可以采用两个方法来描述:二元组、图形

数据结构的二元组形式为:

数据结构={D,S}

其中D是数据元素的集合;S是D中数据元素之间的关系集合,并且数据元素之间的关系使用序偶来表示。记作<x,y>,x是它的第一个元素,y是它的第二个元素。

对于数据元素中,可以有多个直接前驱元素也可以有多个直接后驱元素。数据元素之间的关系是M对N的联系,我们把具有此种特点的数据结构称为图结构

 

 

1-1 setlinearitytreegraph的图形表示

由于是在Java这种高级语言中讨论数据结构,所以在讨论数据的存储结构的时候时不会在真正的物理地址的基础上去讨论顺序存储和链式存储,而是在Java提供的一维数组和对象的引用基础上讨论和实现数据的存储结构。

1.1 抽象数据类型ADT

数据类型:Java中提供了八种基本的数据类型,整数类型(byte、short、int、long)、字符类型(char)、浮点类型(float、double)和布尔类型(只占用一个比特)。定义数据类型有两个作用:①是隐藏计算机硬件的特性和差别,使的硬件对于用于而言是透明的,即用户不需要关心数据类型是怎么实现的而可以去使用它(就和Java中的封装一样);②用于可以使用数据类型定义的操作,方便问题的求解。

抽象数据类型(abstract data type,简称ADT)由一种数据模型和在该数据模型上的一组操作组成。ADT包括定义实现两个方面。

ADT可以使用一个三元组来表示:

ADT=(D,S,P)

其中D是数据对象,S是D上的关系集,P是加在D上的一组操作。在定义ADT时,我们使用以下的格式:

ADT 抽象数据类型名{

数据对象:<数据对象的定义>

数据关系:<数据关系的定义>

基本操作:<基本操作的定义>

}

1.2 算法及性能分析

算法通常来说有五个特性:输入、输出、可行性、有穷性确定性

1.2.1 渐进时间复杂度

我们假设一些基本操作都可以在一个常数时间内完成。例如,逻辑运算、赋值运算等都是基本操作。这样算法执行的基本操作次数就可以反映算法的运行时间,在后面提到算法的运行时间都是指运行基本操作的次数。

一旦去掉表示算法运行时间中的低阶项和常数项,就称我们在度量算法的渐进时间复杂度。为了进一步说明,我们定义了如下符号Ο、Ω和Θ;

定义算法T(n)如下:

(其中c为某个常数)

 

也就是表示当时间复杂度为0(n2)。复杂度的定义如下:设T(n)的一个辅助函数,定义为当n大于等于某一个足够大的正整数n0时,存在两个正的常数A和B(其中A<=B),使得A≤T(n)/g(n)≤B均成立。通俗的来说就是当时n趋近于无穷时,使得T(n)/g(n)= A。 

  1. Ο符号

0(n2)解释为只有当排序元素的个数大于某个阈值N时,那么这个对于某个常量c0,运行时间最多为cn2。也就是说Ο符号提供了一个运行时间的上界。

  1. Ω符号

可以解释为,如果输入大于等于某个阈值N,算法的运行时间的下界是f(n)c倍,其中c是一个正常数,则称算法的时间复杂度时Ω(f(n))

  1. Θ符号

可以解释为算法的精确阶。

1.2.2 空间复杂度

空间频率:一个算法在执行过程中所占用的内存开销,称为空间频度。

空间复杂度是指在计算机内存中执行所占用的内存开销规模。

线性表

线性表是n个类型相同的数据元素的有限序列,通常记作(a0,a1,an)

线性表的ADT类型,定义如下

ADT List {

数据对象:D={ai|aiD0i=0,1,2n-1D0为某一数据对象}

数据关系:R={<ai,ai+1>|ai,ai+1Di=0,1,2n-2}

基本操作:

  • getSize()返回线性表的大小;
  • isEmpty()返回线性表是否为空;
  • Contains(e)判断线性表是否含有元素e
  • indexOf(e)返回元素e在线性表中的索引,如果不存在则返回-1
  • insert(i,e)将元素e插入到线性表i中的位置,如果i越界,则报错;
  • insertBefore(p,e)将元素e插入到p之前,成功返回true
  • remove(i)删错线性表中索引为i的元素,并返回值;
  • remove(e)删错线性表中e元素,成功返回true
  • replace(i,e)替换线性表中索引为i的数据元素为e,返回原数据元素,如果i越界则报错;
  • get(i)返回线性表中索引为i的元素,如果i越界则报错。

}

其中这部分可以翻译成Java代码,就是定义一个List接口,List接口代码如下:

1 package dataStruct; 2  3 /** 4  * 如何将抽象数据类型所提供的操作利用Java语言来明确的定义。 5  * ADT的操作就是在Java中就可以认为是定义一个接口 6  * 7  */ 8  9 public interface List {10     11     /**12      * 返回线性表的大小,即元素的个数13      */14     public int getSize();15     /**16      * @return 判断数据元素是否为空17      */18     public boolean isEmpty();19     /**20      * 判断线性表中是否包含了数据元素e21      * @param e 22      * @return 23      */24     public boolean contain(Object e);25     /**26      * 返回将数据元素e在链表中的序号27      * @param e28      * @return29      */30     public int indexOf(Object e);31     /**32      * 将数据元素e插入到线性表中i号位置33      * @param i34      * @param e35      * @throws OutOfBoundaryException 插入越界异常36      */37     public void insert(int i, Object e)throws OutOfBoundaryException;38     /**39      * 将数据元素e插入到元素obj之前40      * @param obj41      * @param e42      * @return43      */44     public boolean insertBefore(Object obj, Object e);45     /**46      * 将数据元素e插入到元素obj之后47      * @param obj48      * @param e49      * @return50      */51     public boolean insertAfter(Object obj, Object e);52     /**53      * 删除线性表中索引为i的元素,并且返回之54      * @param i55      * @return56      * @throws OutOfBoundaryException57      */58     public Object remove(int i)throws OutOfBoundaryException;59     /**60      * 删除线性表中第一个元素为e的元素61      * @param e62      * @return63      */64     public boolean remove(Object e);65     /**66      * 替换线性表中索引为i的元素为e67      * @param i68      * @param e69      * @return70      * @throws OutOfBoundaryException71      */72     public Object replace(int i, Object e)throws OutOfBoundaryException;73     /**74      * 返回线性表中需要为i的元素75      * @param i76      * @return77      * @throws OutOfBoundaryException78      */79     public Object get(int i)throws OutOfBoundaryException;80  81 }
View Code

 Java中不支持运算符的重载,所以需要使用Strategy接口来实现不同数据元素之间的独立的比较策略。重写类的equal()。我们编写线性表中使用Object来指定数据域,虽然具有很好地通用性,但是不同的数据类型元素互相之间不好比较,需要实现Strategy类来实现不同类之间的比较。Strategy类的接口定义如下:

2.1 Java中的Strategy接口 

1 package dataStruct; 2  3 /** 4  * 在List定义的方法中,我们将所有的数据元素都用了Object来代替 5  * ,具有通用性,但同时不同元素之间的比较策略也需要考虑。 6  * Strategy策略用来比较两个不同的对象 7  * 8  */ 9 public interface Strategy {10     /**11      * 判断两个数据元素是否相等12      * @param obj113      * @param obj214      * @return15      */16     public boolean equal(Object obj1, Object obj2);17     /**18      * 比较两个元素之间的大小19      * if obj1 < obj2 return -1;20      * if obj1 = obj2 return 1;21      * if obj1 > obj2 return 1;22      * @param obj123      * @param obj224      * @return25      */26     public int compare(Object obj1, Object obj2);27 }
View Code

2.2 线性表中的顺序存储和实现

线性表中的顺序存储

  2-1 线性表的顺序存储

如果线性表中存放的是对象时,数组存放的是对象的引用,即线性表中所有数据元素的对象引用是存放在一组连续的地址空间中。

 

2-2 数组存储对象的引用

基于线性表的数组实现,编写成ListArray

1 package dataStruct;  2   3 /**  4  * 线性表的数组实现 *  5  */  6 public class ListArray implements List {  7     private final int LEN = 8; // 数组的默认大小  8     private Strategy strategy; // 数据元素的比较策略  9     private Object[] elements; // 线性表中数据元素的个数 10     private int size; // 线性表中数据元素的个数 11     public ListArray() { 12         this(new DefaultStrategy()); 13     } 14  15     public ListArray(Strategy strategy) { 16         this.strategy = strategy; 17         size = 0; 18         elements = new Object[LEN]; 19     } 20  21     @Override 22     public int getSize() { 23         return this.size; 24     } 25  26     @Override 27     public boolean isEmpty() { 28         return size ==0; 29     } 30  31     @Override 32     public boolean contain(Object e) { 33         for(int i=0; i
size) { 55 throw new OutOfBoundaryException("错误,指定插入索引越界"); 56 } 57 if(size>=elements.length) 58 expendSpace(); // 扩展数组 59 for (int j = size; j>i ; j-- ) { 60 elements[j] = elements[j-1]; 61 } 62 elements[i] = e; 63 size++; 64 } 65 /** 66 * 扩展数组,新数组大小为旧数组的2倍 67 */ 68 private void expendSpace(){ 69 Object[] a = new Object[elements.length*2]; 70 for (int i = 0; i < elements.length ; i++) { 71 a[i] = elements[i]; 72 } 73 elements = a; 74 } 75 76 @Override 77 public boolean insertBefore(Object obj, Object e) { 78 int i = indexOf(obj); 79 if (i<0) { 80 return false; 81 } 82 insert(i, e); 83 return true; 84 } 85 86 @Override 87 public boolean insertAfter(Object obj, Object e) { 88 int i = indexOf(obj); 89 if (i<0) { 90 return false; 91 } 92 insert(i+1, e); 93 return true; 94 } 95 96 @Override 97 public Object remove(int i) throws OutOfBoundaryException { 98 if (i<0||i>=size) { 99 throw new OutOfBoundaryException("错误,删除指定索引越界");100 }101 Object obj = elements[i];102 for (int j = i; j < size-1; j++) {103 elements[j] = elements[j+1]; 104 }105 elements[--size] = null;106 return obj;107 }108 109 @Override110 public boolean remove(Object e) {111 int i = indexOf(e);112 if(i<0) return false;113 remove(i);114 return true;115 }116 117 @Override118 public Object replace(int i, Object e) throws OutOfBoundaryException {119 if (i<0||i>=size) {120 throw new OutOfBoundaryException("错误,指定索引越界");121 }122 Object obj = elements[i];123 elements[i] = e;124 return obj;125 }126 127 @Override128 public Object get(int i) throws OutOfBoundaryException {129 if (i<0||i>=size) {130 throw new OutOfBoundaryException("错误,指定索引越界");131 }132 return elements[i];133 }134 public void display(){135 for(int i = 0; i < size; i++){136 System.out.print(elements[i]+" ");137 }138 System.out.println();139 }140 141 public static void main(String[] args) {142 // 测试的代码的运行143 ListArray listArray = new ListArray(); 144 for(int i=0; i<10; i++){145 listArray.insert(i,i);146 }147 System.out.println("顺序表的大小:"+listArray.getSize());148 System.out.println("顺序表是否为空:"+listArray.isEmpty());149 System.out.println("顺序表是否含有元素1:"+listArray.contain(1));150 System.out.println("元素1在顺序表中的位置:"+listArray.contain(1)); 151 listArray.display();152 System.out.println("在索引为10的位置上插入888:");153 listArray.insert(10, 888);154 listArray.display();155 listArray.insertBefore(888, 777);156 listArray.display();157 listArray.insertAfter(888, 999);158 listArray.display();159 System.out.println("移除索引为8的元素:"+listArray.remove(8));160 listArray.display();161 System.out.println("移除元素888:"+listArray.remove((Object)888));162 listArray.display();163 System.out.println("替换在索引10处的元素为520:"+listArray.replace(10, (Object)520));164 listArray.display();165 }166 }
View Code

2.3.1 单链表2.3 线性表中链式存储和实现

单链表的结构:一个域用于数据元素的存储,一个域用于指向其他单元的指针

 

2-3 单链表结点的结构

Java中没有显示的使用指针,实际上,对象的引用就是使用指针来实现的。也就是在Java中使用对象的引用来替代指针。结点的数据域data可以使用一个Object类型的对象来实现,用于存储任何类型的数据元素,并通过对象的引用指向该元素;而指针域next可以通过结点对象的引用来实现。我们先定义一个Node接口,用来规范所有线性表中结点的特性。

1 /** 2  * 单链表中的结点是结点的最简单的一种形式,在Node接口中 3  * 定义所有结点均支持的操作,即对结点中存储数据的存取 4  * 5  */ 6 public interface Node { 7     /** 8      * @return 返回结点的数据域 9      */10     public Object getData();11     /**12      * 设置结点数据域13      */14     public void setData(Object obj);15 }

给出了结点接口定义之后,单链表的结点定义就可以实现结点的接口来完成。 

1 /** 2  * 单链表中结点的定义  3  */ 4 public class SLNode implements Node { 5     protected Object element; // 定义数据域 6     protected SLNode next; // 定义的指针域 7     public SLNode(){ 8         this(null,null); 9     }10     11     public SLNode(Object obj, SLNode next){12         this.element = obj;13         this.next = next;14     }15     16     @Override17     public Object getData() {18         return this.element;19     }20 21     @Override22     public void setData(Object obj) {23         this.element = obj;24     }25 26 }

 一个单链表(single linked list)的结构如下: 

 

2-4 单链表的结构

在单链表中的查询操作只能从链表的首节点开始,通过每个结点的next引用来一次访问链表中的每个结点以完成相应的查找操作。

 

2-5 在单链表中实现查找操作

 

2-6在单链表中插入结点

单链表的实现代码如下:

1 package dataStruct;  2   3 /**  4  * 带头结点的单链表  5  *  6  */  7 public class ListSLinked implements List {  8     private Strategy strategy; // 数据元素的比较策略  9     private SLNode head; // 单链表中的头结点 10     private int size; // 线性表中数据元素的个数 11     public ListSLinked(){ 12         this(new DefaultStrategy()); 13     } 14     public ListSLinked(Strategy strategy){ 15         this.strategy = strategy; 16         head = new SLNode(); 17         size = 0; 18     } 19      20     /** 21      * 辅助方法:获取数据元素e所在结点的前驱结点 22      * @param e 23      * @return 24      */ 25     public SLNode getPreNode(Object e){ 26         SLNode p = head; 27         while (p.next !=null) { 28             if(strategy.equal(p.next.getData(), e)){ 29                 return p; 30             } 31             else { 32                 p = p.next; 33             } 34         } 35         return null; 36     } 37     /** 38      * 辅助方法:获取序号为0<=i<=size的元素所在的前驱结点 39      * @param e 40      * @return 41      */ 42     public SLNode getPreNode(int i){ 43         SLNode p = head; 44         for (; i>0 ;i-- ) { 45             p = p.next; 46         } 47         return p; 48     } 49     /** 50      * 辅助方法:获取序号为0<=i<=size的元素所在的结点 51      * @param e 52      * @return 53      */ 54     public SLNode getNode(int i){ 55         SLNode p = head.next; 56         for (; i>0 ;i-- ) { 57             p = p.next; 58         } 59         return p; 60     } 61  62     @Override 63     public int getSize() { 64         return size; 65     } 66  67     @Override 68     public boolean isEmpty() { 69         return size==0; 70     } 71  72     @Override 73     public boolean contain(Object e) { 74         SLNode p = head.next; 75         while(p!=null){ 76             if (strategy.equal(p.getData(), e)) { 77                 return true; 78             } 79             else{ 80                 p = p.next; 81             } 82         } 83         return false; 84     } 85  86     @Override 87     public int indexOf(Object e) { 88         SLNode p = head.next; 89         int index = 0; 90         while(p!=null){ 91             if (strategy.equal(p.getData(), e)) { 92                 return index; 93             } 94             else{ 95                 index++; 96                 p = p.next; 97             } 98         } 99         return -1;100     }101 102     @Override103     public void insert(int i, Object e) throws OutOfBoundaryException {104         if(i<0||i>size)105             throw new OutOfBoundaryException("错误,指定插入索引越界");106         SLNode p = getPreNode(i);107         SLNode q = new SLNode(e, p.next);108         p.next = q;109         size++;110     }111 112     @Override113     public boolean insertBefore(Object obj, Object e) {114         SLNode p = getPreNode(obj);            115         if (p!=null) {116             SLNode q = new SLNode(e, p.next);117             p.next = q;118             size++;119 //            display();120             return true;121         }122         return false;123     }124 125     @Override126     public boolean insertAfter(Object obj, Object e) {127         SLNode p = head.next;128         while(p!=null){129             if (strategy.equal(p.getData(), obj)) {130                 SLNode q = new SLNode(e, p.next);131                 p.next = q;132                 size++;133                 return true;134             }135             else136                 p = p.next;137         }138         return false;139     }140 141     @Override142     public Object remove(int i) throws OutOfBoundaryException {143         if (i<0||i>=size) {144             throw new OutOfBoundaryException("错误,删除指定索引越界");145         }146         SLNode p = getPreNode(i);147         Object obj = p.next.getData();148         p.next = p.next.next;149         size--;150         return obj;151     }152 153     @Override154     public boolean remove(Object e) {155         SLNode p = getPreNode(e);156         if (p!=null) {157             p.next = p.next.next;158             size--;159             return true;160         }161         return false;162     }163 164     @Override165     public Object replace(int i, Object e) throws OutOfBoundaryException {166         if (i<0||i>=size) {167             throw new OutOfBoundaryException("错误,指定索引越界");168         }169         SLNode p = getNode(i);170         Object obj = p.getData();171         p.setData(e);172         return obj;173     }174 175     @Override176     public Object get(int i) throws OutOfBoundaryException {177         if (i<0||i>=size) {178             throw new OutOfBoundaryException("错误,指定索引越界");179         }180         SLNode p = getNode(i);181         return p.getData();182     }183     public void display(){184         SLNode p = head.next;185         while(p!=null){186             System.out.print(p.getData()+" ");187             p = p.next;188         }189         System.out.println();190     }191 192     public static void main(String[] args) {193         ListSLinked LSL1 = new ListSLinked();194         for(int i = 0; i<10 ; i++){195             LSL1.insert(i, 2*i-1);196         }197         System.out.println("顺序表的大小:"+LSL1.getSize());198         System.out.println("顺序表是否为空:"+LSL1.isEmpty());199         System.out.println("顺序表是否含有元素1:"+LSL1.contain(1));200         System.out.println("元素2在顺序表中的位置:"+LSL1.indexOf(2));        201         LSL1.display();202         System.out.println("在索引为10的位置上插入888:");203         LSL1.insert(10, 888);204         LSL1.display();205         System.out.println("测试几个辅助函数:1、获取索引为10的前结点"+LSL1.getPreNode(10).getData()+"--"+LSL1.getPreNode(10).next);206         System.out.println("测试几个辅助函数:2、获取元素为5的前结点"+LSL1.getPreNode((Object)5).getData()+"--"+LSL1.getPreNode((Object)5).next);207         System.out.println("测试几个辅助函数:3、获取索引为5的结点"+LSL1.getNode(5).getData()+"--"+LSL1.getPreNode(5).next);208         LSL1.insertBefore((Object)888, (Object)777);209         LSL1.display();210         LSL1.insertAfter(888, 999);211         LSL1.display();212         System.out.println("移除索引为8的元素:"+LSL1.remove(8));213         LSL1.display();214         System.out.println("移除元素888:"+LSL1.remove((Object)888));215         LSL1.display();216         System.out.println("替换在索引10处的元素为520:"+LSL1.replace(10, (Object)520));217         LSL1.display();218     }219 220 }

转载于:https://www.cnblogs.com/yutianaiqingtian-sky/p/6911761.html

你可能感兴趣的文章
但我现在要将其中的“pageEncoding="ISO-8859-1"”默认为“pageEncoding="GBK"”,请问怎么修改MyEclipse?...
查看>>
英语音节知识
查看>>
IEEE 802.15.4协议学习之MAC层
查看>>
AngularJS学习篇(十三)
查看>>
JavaScript Function.apply() 函数详解
查看>>
Tableau 学习资料
查看>>
中断和异常
查看>>
lucene 全文检索工具的介绍
查看>>
C# MD5-16位加密实例,32位加密实例
查看>>
无线点餐系统初步构思
查看>>
AJAX
查看>>
前端之CSS
查看>>
List注意点【修改】
查看>>
sqoop导入导出对mysql再带数据库test能跑通用户自己建立的数据库则不行
查看>>
拓扑排序的原理及其实现
查看>>
对StageWebView捕获位图时空白
查看>>
Provison Profile管理及存放路径
查看>>
Highcharts使用指南(转自博客园一位博友可米小子的文章 http://www.cnblogs.com/liuhaorain)很好的一片文章,大家共同学习...
查看>>
shop--8.店铺列表展示--前端开发
查看>>
锁机制
查看>>