数据结构(Java描述)之线性表
基础概念
数据结构:是相互之间存在一种或多种关系的数据元素的集合。
逻辑结构和物理结构
关于数据结构,我们可以从逻辑结构和物理结构这两个维度去描述
逻辑结构是数据对象中数据元素之间的关系,是从逻辑意义上去描述的数据之间的组织形式。
逻辑结构有4种:
- 集合结构(数据元素之间仅以集合的方式体现,元素之间没有别的关系)
- 线性结构(数据元素之间存在一对一的关系)
- 树(数据元素之间为一对多或多对一的关系)
- 图(数据元素之间为多对多的关系)
物理结构则是逻辑结构在计算机中内存中的存储形式,分为两种:
- 顺序存储结构
- 链式存储结构
线性表(list)
线性表是零个或多个数据元素的的有限序列
线性表是线性结构,元素之间存在一对一的关系,线性表可通过顺序和链式两种方式来实现。
顺序存储结构,是用一段地址连续的存储单元依次存储线性表的数据元素

链式存储结构,用一组任意的存储单元来存储数据元素,不要求物理存储单元的连续性,由一系列结点组成,每个结点除了要存储数据外,还需存储指向后继结点或前驱结点的存储地址。

顺序存储和链式存储对比
- 顺序存储结构
- 优点
- 实现比较简单
- 查找指定位置的元素效率很快,时间复杂度为常数阶O(1)
- 无需额外存储元素之间的逻辑关系(链式存储由于存储空间随机分配,需要存储元素之间的逻辑关系)
- 缺点
- 需要预先分配存储空间,如果数据元素数量变化较大,很难确定存储容量,并导致空间浪费
- 若频繁进行插入删除操作,则可能需要频繁移动大量数据元素
- 优点
- 链式存储结构
- 优点
- 不需要提前分配存储空间,元素个数不受限制
- 对于插入删除操作,在已找到目标位置前提下,效率很高,仅需处理元素之间的引用关系,时间复杂度为O(1)
- 缺点
- 实现相对复杂
- 查找效率较低,最坏情况下需要遍历整张表
- 由于物理存储位置不固定,需要额外存储数据元素之间的逻辑关系
- 优点
链式存储代码实现
单链表
package listdemo;
/**
* Created by chengxiao on 2016/10/18.
*/
public class MyLinkedList {
/**
* 指向头结点的引用
*/
private Node first ;
/**
* 线性表大小
*/
private int size;
/**
* 结点类
*/
private static class Node{
//数据域
private int data;
//指向后继结点的引用
private Node next;
Node(int data){
this.data = data;
}
}
/**
* 从头部进行插入
* 步骤:1.新结点的next链指向当前头结点;2.将first指向新节点
* 时间复杂度:O(1)
* @param data
*/
public void insertFirst(int data){
Node newNode = new Node(data);
newNode.next = first;
first = newNode;
size++;
}
/**
* 从头部进行删除操作
* 步骤:1.将头结点的next链置空 2.将first引用指向第二个结点
* 时间复杂度为:O(1)
* @return
*/
public boolean deleteFirst(){
if(isEmpty()){
return false;
}
Node secondNode = first.next;
first.next = null;
first = secondNode;
size--;
return true;
}
/**
* 取出第i个结点
* 步骤:从头结点进行遍历,取第i个结点
* 时间复杂度:O(n),此操作对于利用数组实现的顺序存储结构,仅需常数阶O(1)即可完成。
* @param index
* @return
*/
public int get(int index) throws Exception {
if(!checkIndex(index)){
throw new Exception("index不合法!");
}
Node curr = first;
for(int i=0;i<index;i++){
curr = curr.next;
}
return curr.data;
}
/**
* 遍历线性表
* 时间复杂度:O(n)
*/
public void displayList(){
Node currNode = first;
while (currNode!=null){
System.out.print(currNode.data+" ");
currNode = currNode.next;
}
System.out.println();
} /**
* 链表是否为空
* @return
*/
public boolean isEmpty(){
return first == null;
} /**
* index是否合法
* @param index
* @return
*/
private boolean checkIndex(int index){
return index >= 0 && index < size;
}
/**
* 链表大小
* @return
*/
public int size() {
return size;
}
public static void main(String []args) throws Exception { MyLinkedList myLinkedList = new MyLinkedList();
//从头部插入
myLinkedList.insertFirst(1);
myLinkedList.insertFirst(2);
myLinkedList.insertFirst(3);
myLinkedList.insertFirst(4);
//遍历线性表中元素
myLinkedList.displayList();
//获取第二个元素
System.out.println(myLinkedList.get(2));
//删除结点
myLinkedList.deleteFirst();
myLinkedList.displayList();
}
}
输出结果
4 3 2 1
2
3 2 1
双端链表
上面罗列了线性表中的几种基本操作,考虑下,如果要提供一个在链表尾部进行插入的操作insertLast,那么由于单链表只保留了指向头结点的应用first,需要从头结点不断通过其next链找后继结点来遍历,时间复杂度为O(n)。其实,我们可以在保留头结点引用的时候,也保留一个尾结点的引用。这样,在从尾部进行插入时就方便多了
双端链表同时保存对头结点和对尾结点的引用
/**
* 指向头结点的引用
*/
private Node first ;
/**
* 指向尾结点的引用
*/
private Node rear;
从尾部进行插入
/**
* 双端链表,从尾部进行插入
* 步骤:将当前尾结点的next链指向新节点即可
* 时间复杂度:O(1)
* @param data
*/
public void insertLast(int data){
Node newNode = new Node(data);
if(isEmpty()){
first = newNode;
rear = newNode;
size++;
return;
}
rear.next = newNode;
rear = newNode;
size++;
}
做其他操作的时候也需注意保持对尾结点的引用,此处不再赘述。
双向链表
再考虑下,如果我们要提供一个删除尾结点的操作,步骤很简单:在删除尾结点的过程中需要将其前驱结点(即倒数第二个结点)的next链引用置为空,但由于我们的链表是单链表,一条道走到黑,要找倒数第二个结点得从头开始遍历,这种情况下,我们就可以考虑使用双向链表。
双向链表的的每一个结点,包含两个指针域,一个指向它的前驱结点,一个指向它的后继结点。

/**
* 删除尾结点
* 主要步骤:1.将rear指向倒数第二个结点 2.处理相关结点的引用链
* 时间复杂度:O(1)
* @return
*/
public void deleteLast() throws Exception {
if(isEmpty()){
throw new Exception("链表为空");
}
Node secondLast = rear.prev;
rear.prev = null;
rear = secondLast;
if(rear == null){
first = null;
}else{
rear.next = null;
}
size--;
}
其他操作同理,在过程中需要同时保持对结点的前驱结点和后继结点的引用,删除操作时,需要注意解除废弃结点的各种引用,便于GC。
总结
本文对数据结构的一些基本概念,逻辑结构和物理结构,线性表等概念进行了基本的阐述。同时,介绍了线性表的顺序存储结构和链式存储结构,对线性表的链式存储结构(单链表,双端链表,双向链表),使用Java语言做了基本实现。数据结构的重要性毋庸置疑,它是软件设计的基石,由于自己非科班出身,虽曾自学过一段时间,也不够系统,最近希望能重新系统地梳理下,本篇就当自己数据结构再学习的开篇吧,共勉。
数据结构(Java描述)之线性表的更多相关文章
- 第一阶段:Java内功秘籍-线性表
前言 为什么要学习数据结构与算法,如果你学会了做安卓,javaweb,前端等,都是你的武功秘籍,但是如果你的内功不够好,再厉害的功夫也是白费. 数据结构和算法:什么是数据结构,什么是数据,在计算机内部 ...
- Java数据结构与算法(1):线性表
线性表是一种简单的数据类型,它是具有相同类型的n个数据元素组成的有限序列.形如如A0,A1,...,An-1.大小为0的表为空表,称Ai后继Ai-1,并称Ai-1前驱Ai. printList打印出表 ...
- JAVA通过继承线性表来实现有序表
1,对于线性表而言,里面的元素是无序的,可以随意地将新元素增加到线性表中而不需要考虑该元素在线性表中的位置.但是,对于有序表而言,其中的元素是按照某种方式进行排序的,因此在有序表中插入元素时,需要按照 ...
- Java Se :线性表
Java的集合框架分为两个系列,Collection和Map系列.在大学期间,学习数据结构时,好像学习了线性表.非线性表.树,哎,都给忘了.其实,在Collection系列内部又可以分为线性表.集合两 ...
- 数据结构Java实现02----线性表与顺序表
[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...
- 数据结构Java实现01----线性表与顺序表
一.线性结构: 如果一个数据元素序列满足: (1)除第一个和最后一个数据元素外,每个数据元素只有一个前驱数据元素和一个后继数据元素: (2)第一个数据元素没有前驱数据元素: (3)最后一个数据元素没有 ...
- JAVA迭代器学习--在JAVA中实现线性表的迭代器
1,迭代器是能够对数据结构如集合(ADT的实现)进行遍历的对象.在遍历过程中,可以查看.修改.添加以及删除元素,这是它与一般的采用循环来遍历集合中的元素不同的地方.因为,通常用循环进行的遍历操作一般是 ...
- [数据结构 - 第3章] 线性表之双向链表(C语言实现)
一.什么是双向链表? 双向链表(double linked list)是在单链表的每个结点中,再设置一个指向其前驱结点的指针域.所以在双向链表中的结点都有两个指针域,一个指向直接后继,另一个指向直接前 ...
- 数据结构学习笔记 <1> 线性表
一.线性表的抽象数据类型描述 类型名:线性表(List) 数据对象集:线性表示n(>=0)个元素构成的有序序列(a1,a2,……,an) 操作集:线性表L∈List, 整数i表示位置,元素X∈ ...
随机推荐
- [Asp.net 5] Logging-其他日志系统的实现
Microsoft.Framework.Logging.NLog 使用Nlog扩展日志系统:按照我们上节说的,对于扩展的日志系统都要实现俩个接口ILogger.ILoggerProvider.所以在当 ...
- Entity Framework 代码先行之约定配置
要更改EF中的默认配置有两个方法,一个是用Data Annotations(在命名空间System.ComponentModel.DataAnnotations;),直接作用于类的属性上面;还有一个就 ...
- C#之tcp自动更新程序
.NETTCP自动更新程序有如下几步骤: 第一步:服务端开启监听 ServiceHost host; private void button1_Click(object sender, EventAr ...
- html中<radio>单选按钮控件标签用法解析及如何设置默认选中
<input type="radio" name="radio" value="1">单选1 <input type=&q ...
- 初识Java
Java是一种简单的.面向对象的.分布式的.解释的.安全的.可移植的.性能优异的多线程语言.它以极强的安全性.平台无关性.硬件结构无关性.语言简洁.面向对象的特点,在网络编程语言中占据了无可比拟的优势 ...
- sql执行循序
(8) select (9) distinct (11) top 1 (6) Table1.id,COUNT(Table1.name) as nameCount (1) from Table1 (3) ...
- ExpandableListView实现展开更多和收起更多
[需求]: 如上面图示 当点开某个一级菜单的时候,其他菜单收起: 子级菜单默认最多5个: 多于5个的显示"展开更多" 点击"展开更多",展开该级所有子级菜单,同 ...
- 【工匠大道】Git的使用总结
初衷是想将一些常用的代码整理在博客园上,但是考虑到博客园上的代码量多,需要折叠,折叠后就不能直接修改,于是想到了 大家都常用的 gitHub来进行代码的管理. 其实之前我是用过 Osa的git的,但是 ...
- GJM : 中断被Socket.Accept阻塞的线程
原帖地址:http://blog.csdn.net/kingfox/article/details/7233350 原文作者:狐帝 刚刚学习C#,在编写一个网络通讯的程序的时候,遇到了点麻烦.监听代码 ...
- 前端实战Demo:一张图片搞定一页布局
对前端程序员来说,从设计师的手中拿过设计图和素材之后根据需要进行切图是必要的基本功,但是一般的程序员可能对切图并非那么熟悉,所以可能有很多时间都花在使用Photoshop上,那么这里就有一种方法可以减 ...