线性表的Java实现
一、概念
对于常用的数据结构,可分为线性结构和非线性结构,线性结构主要是线性表,非线性结构主要是数和图。当n>0时,表可表示为:(a0,a1,a2,a3,…an)
1、 线性表的特征:
1、存在唯一的被称作”第一个”的数据元素
2、存在唯一的一个称作”最后一个的”数据元素”
3、除第一个之外,集合中的每个数据元素均只有一个前驱
4、除最后一个之外,集合中每个元素均只有一个后继
2、线性表的基本操作
1、初始化:
2、返回线性表长度
3、获取指定索引处元素
4、按值查找元素位置
5、直接插入数据元素
6、向指定位置插入元素
7、直接删除元素
8、删除指定位置元素
二、顺序存储结构
线性表的顺序结构是指用一组地址连续的存储单元依次存放线性表的元素。下面采用数组实现顺序结构线性表。
import java.util.Arrays;
public class Sequence<T> {
privateObject[] elementData;//定义一个数组
privateint DEFAULT_SIZE = 1; //数组默认大小
privateint capacity; //数组容量
privateint size = 0; //当前数组大小
//初始化
public Sequence(){
capacity= this.DEFAULT_SIZE;
elementData= new Object[capacity];
} public Sequence()(T element){
this();
elementData[0]= element;
size++;
} //返回线性表长度
public int length(){
return this.size;
} //返回指定索引处元素。
public T getElementByIndex(int index){ if(index< 0 || index > (size-1)){
System.out.println("索引范围越界!!!");
System.exit(0);
}
return (T)elementData[index];
}
//按值查找数据元素的位置
public int getIndexByValue(T value){
for(int i = 0; i < elementData.length;i++ ){
if(value.equals(elementData[i])){
return i;
}
}
return -1;//未找到则返回-1
} //向指定位置插入元素
public void insert(T element,int index){
ensureCapacity(); //确保线性表容量够
if(index>= 0 && index < size){
int i = 0;
//将插入位置之后元素挨个后移1
for(i= (size-1); i >= index;i--){
elementData[i+1]= elementData[i];
}
elementData[i+1]= element;//插入该元素
size++; //数组当前容量+1
}
else{
throw new IndexOutOfBoundsException("插入元素位置越界!!!");
}
} //想线性表末尾添加元素
public void add(T element){
ensureCapacity(); //确保线性表容量够
elementData[size]= element;
size++;
} //删除线性表中指定位置元素
public void delete(int index){
if(index>= 0 && index < size){
int i;
//将要删除元素位置之后的元素挨个前移1,通过覆盖删除
for(i= index+1;i < size;i++){
elementData[i-1]= elementData[i];
}
elementData[size-1]= null;
}
else{
thrownew IndexOutOfBoundsException("所要删除元素位置越界!!!");
}
} //删除指定元素
public void delete(T value){
int index = this.getIndexByValue(value);
if(index!= -1){
this.delete(index);
}
else{
System.out.println("您要删除的元素并不存在");
System.exit(0);
}
size--;
} //判断线性表是否为空
public boolean isEmpty(){
boolean b = false;
if(this.length()!= 0){
b= true;
}
return b;
} //清空线性表
public void clear(){
for(Object o:elementData){
o= null;
}
size= 0;
} //显示线性表中所有元素
public void view(){
System.out.print("当前线性表中元素为:");
for(int i = 0;i < size;i++){
System.out.print(elementData[i]+ " ");
}
System.out.print("\n");
} //扩充线性表容量
public void ensureCapacity(){
while((size+1)> capacity){
capacity=capacity * 2; //线性表容量每次增大一倍
elementData= Arrays.copyOf(elementData, capacity);
}
} public static void main(String[] args) {
Sequence<String> sequence = new Sequence<>();
sequence.add("hello");
sequence.add("world");
sequence.add("java");
sequence.add("perfect");
sequence.view();
sequence.insert("haha",1);
sequence.view();
System.out.println("索引为3的元素为:" +sequence.getElementByIndex(3));
System.out.println("字符串perfect的索引号为:"+ sequence.getIndexByValue("perfect"));
sequence.delete("hello");
sequence.view();
sequence.clear();
System.out.println("clear之后线性表长度为:"+ sequence.length());
}
}
三、链式存储结构
1、概念
链式存储结构的线性表(简称为链表)采用一组任意的存储单元存放线性表中的数据元素。链式存储结构的线性表不是按线性的逻辑顺序来保存数据元素,它需要在每个数据元素里保存一个引用下一个数据元素的引用。
节点 = 数据元素 + 引用下一个节点的引用 + 引用上一个节点的引用
2、单链表基本操作
建立单链表方法:1头插法建表 2尾插法建表
查找操作:1按index查找指定数据元素 2在链表中查找指定的数据元素的index
插入操作:在第index个索引处插入元素
删除操作:删除第index个节点
3、单链表具体实现
public class LinkList<T>{
//定义Node节点
private class Node{
private T data;
private Node next; public Node(){ }
public Node(T element,Node next){
this.data= element;
this.next= next;
}
}
//成员变量
private Node header;//头节点
private Node tail; //尾节点
private int size = 0; //链表长度 public LinkList(){
header= null;
tail= header;
} public LinkList(T element){
header= new Node(element,null);
tail= header;
} //获取链表中指定索引处的元素
public T get(int index){
return this.getNodeByIndex(index).data;
} //获取链表中指定索引处Node
public Node getNodeByIndex(int index){
this.checkBorder(index);
Node currentNode = header;
for(int i = 0;i < size && currentNode !=null;i++,currentNode =currentNode.next){
if(i== index){
return currentNode;
}
}
return null;
} //向指定索引处插入元素
public void insert(T element,int index){
this.checkBorder(index);
if(index== 0){
this.addAtHeader(element);
}
else{
NodeprevNode =this.getNodeByIndex(index-1);//获取插入位置的前向Node
prevNode.next=new Node(element,prevNode.next);
}
size++;
} //删除指定索引处Node
public T delete(int index){
this.checkBorder(index);
Nodedel = null;
//删除的是header
if(index== 0){
del= header;
header= header.next;
}
else{
NodeprevNode =this.getNodeByIndex(index);
del= prevNode.next;
prevNode.next= del.next; //将prevNode的后向Node设置为del.next
del.next= null;
}
size--;
returndel.data;
} //头插法向链表中添加元素
public void addAtHeader(T element){
header= new Node(element,header);//将新添加的Node的next设置为原先的header,然后将新的Node设置为新的header
if(tail==null){
tail= header;
}
size++;
} //尾插法
public void add(T element){
//链表为空的情况
if(header==null){
header= new Node(element,null);
tail= header;
}
else{
tail.next= new Node(element, null); //将tail节点的next设置为new Node
tail= tail.next;//将new Node设置为tail
}
size++;
}
//遍历整个链表
public void view(){
NodecurrentNode = header;
System.out.print("当前链表元素:");
while(currentNode!=null){
System.out.print(currentNode.data+ " ");
currentNode= currentNode.next;
}
System.out.println(""); } //检测索引是否越界
private void checkBorder(int index){
if(index< 0 || index > size-1){
thrownew IndexOutOfBoundsException("链表索引已越界");
}
} public int length(){
return this.size;
} public static void main(String args[]){
LinkList<String> linkList =new LinkList<>();
linkList.add("hello");
linkList.add("world");
linkList.addAtHeader("header");
System.out.println("当前链表长度为:"+ linkList.length());
linkList.view();
System.out.print("插入test之后,");
linkList.insert("test",2);
linkList.view();
linkList.delete(2);
System.out.print("删除索引2处元素后,");
linkList.view();
System.out.println("索引1处元素为:" +linkList.get(1));
}
}
4、双链表实现
public class DoubleLinkList<T> { //定义双向链表节点
private class Node{
private T data;
private Node prev;
private Node next;
public Node(){ }
public Node(T element,Node prev,Node next){
this.data= element;
this.prev= prev;
this.next= next;
}
} private Node header;
private Node tail;
private int size = 0; public DoubleLinkList(){
header= null;
tail= null;
} public DoubleLinkList(T element){
header= new Node(element,null,null);
tail= header;
size++;
}
//获取链表长度
public int length(){
return this.size;
} //检测index是否越界
public void checkBorder(int index){
if(index< 0 || index > size-1){
throw new IndexOutOfBoundsException("链表索引已越界");
}
} //获取指定索引处Node
public Node getNodeByIndex(int index){
checkBorder(index);//越界检测
if(index< size/2){
NodecurrentNode = header;
for(int i = 0;i < size/2;i++,currentNode = currentNode.next ){
if(i== index){
return currentNode;
}
}
}
else{
NodecurrentNode = tail;
for(int i = size-1;i >= size/2;i--,currentNode = currentNode.prev){
if(i== index){
returncurrentNode;
}
}
}
return null;
} //获取链表中指定索引处的元素值
public T get(int index){
return this.getNodeByIndex(index).data;
} //根据元素值查找元素索引
public int locate(T element){
Node currentNode = this.header;
for(int i = 0;i < size-1;i++,currentNode = currentNode.next){
if(currentNode.data.equals(element)){
returni;
}
}
return -1; } //向链表中以尾插法添加元素
public void add(T element){
if(size== 0){
header= new Node(element,null,null);
tail= header;
}
else{
Node newNode =new Node(element,tail,null);
tail.next= newNode;
tail= newNode;
}
size++;
} //头插法向链表添加元素
public void addAtHeader(T element){
if(size== 0){
header= new Node(element,null,null);
tail= header;
}
else{
Node newNode =new Node(element,null,header);
header.prev= newNode;
header= newNode;
}
size++;
} //根据索引插入元素
public void insert(T element,int index){
this.checkBorder(index);
Node prevNode = this.getNodeByIndex(index-1);
Node nextNode = this.getNodeByIndex(index);
Node insertNode = new Node(element, prevNode, nextNode);
nextNode.prev= insertNode;
prevNode.next= insertNode;
size++;
} //根据索引删除元素
public void delete(int index){
this.checkBorder(index);
Node prevDelNode = this.getNodeByIndex(index-1);
Node nextDelNode = this.getNodeByIndex(index+1);
prevDelNode.next= nextDelNode;
nextDelNode.prev= prevDelNode;
size--;
} //遍历链表中元素
public void view(){
System.out.print("当前链表中元素为:");
for(int i = 0;i < size;i++){
System.out.print(this.get(i)+ " ");
}
System.out.println();
} public static void main(String[] args) {
DoubleLinkList<String> doubleLinkList =new DoubleLinkList<>();
doubleLinkList.add("hello");
doubleLinkList.add("world");
doubleLinkList.insert("test",1);
doubleLinkList.addAtHeader("first");
doubleLinkList.view();
System.out.println("索引为0处的元素值为:"+ doubleLinkList.get(0));
System.out.println("test字符串在链表中索引号为:" + doubleLinkList.locate("test"));
doubleLinkList.delete(1);
System.out.print("删除索引号为1元素后,");
doubleLinkList.view();
} }
注:本文部分内容参考自《疯狂Java程序员的基本修养》和《数据结构(C语言版)》
线性表的Java实现的更多相关文章
- 数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解
数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解 对数组有不了解的可以先看看我的另一篇文章,那篇文章对数组有很多详细的解析,而本篇文章则着重讲动态数组,另一篇文章链接 ...
- 线性表 及Java实现 顺序表、链表、栈、队列
数据结构与算法是程序设计的两大基础,大型的IT企业面试时也会出数据结构和算法的题目, 它可以说明你是否有良好的逻辑思维,如果你具备良好的逻辑思维,即使技术存在某些缺陷,面试公司也会认为你很有培养价值, ...
- 线性表(java)
线性表 概念:零个或者多个数据元素的有限序列. 特点:除了第一个元素没有前驱结点,最后一个元素没有后继结点外,其它元素有且仅有一个直接前驱和一个直接后继结点.元素的个数必定为有限个. 实现: 定义一个 ...
- 线性表的Java实现--链式存储(双向链表)
有了单向链表的基础,双向链表的实现就容易多了. 双向链表的一般情况: 增加节点: 删除节点: 双向链表的Java实现: package com.liuhao.algorithm; publi ...
- 线性表的Java实现--链式存储(单向链表)
单向链表(单链表)是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始. 链式存储结构的线性表将采用一组任意的存储单元存放线性表中的数据元素.由于不需要按顺序存储,链表在 ...
- 常用数据结构-线性表及Java 动态数组 深究
[Java心得总结六]Java容器中——Collection在前面自己总结的一篇博文中对Collection的框架结构做了整理,这里深究一下Java中list的实现方式 1.动态数组 In compu ...
- 数据结构(Java描述)之线性表
基础概念 数据结构:是相互之间存在一种或多种关系的数据元素的集合. 逻辑结构和物理结构 关于数据结构,我们可以从逻辑结构和物理结构这两个维度去描述 逻辑结构是数据对象中数据元素之间的关系,是从逻辑意义 ...
- Java Se :线性表
Java的集合框架分为两个系列,Collection和Map系列.在大学期间,学习数据结构时,好像学习了线性表.非线性表.树,哎,都给忘了.其实,在Collection系列内部又可以分为线性表.集合两 ...
- Java数据结构之线性表(2)
从这里开始将要进行Java数据结构的相关讲解,Are you ready?Let's go~~ java中的数据结构模型可以分为一下几部分: 1.线性结构 2.树形结构 3.图形或者网状结构 接下来的 ...
随机推荐
- 关于oracle动态视图v$datafile和v$datafile_header(转)
v$datafile是从oracle的控制文件中获得的数据文件的信息v$datafile_header是从数据文件的头部在正常运行下,两者的检查点SCN值是一致的,但当datafile出现损坏时可以用 ...
- JavaEE Tutorials (30) - Duke综合案例研究示例
30.1Duke综合应用的设计和架构456 30.1.1events工程458 30.1.2entities工程459 30.1.3dukes—payment工程461 30.1.4dukes—res ...
- svn小技巧——重定向svn diff
svn diff的默认输出模式比较冗长,如果遇到修改比较多的情况,有时会较难看清diff.svn本身提供了自定义diff输出的选项,可能的修改方法如下: 建立一个脚本文件(如svndiff.sh),调 ...
- 心急的C小加(两种解法)
心急的C小加 时间限制:1000 ms | 内存限制:65535 KB 难度:4 描述 C小加有一些木棒,它们的长度和质量都已经知道,需要一个机器处理这些木棒,机器开启的时候需要耗费一个单位的 ...
- 逐渐深入地理解Ajax
Ajax的基本原理是:XMLHttpRequest对象(简称XHR对象),XHR为向服务器发送请求和解析服务器响应提供了流畅的接口.能够以异步方式从服务器获得更多信息.意味着用户不必刷新页面也能取得新 ...
- ffmpeg学习笔记
对于每一个刚開始学习的人,刚開始接触ffmpeg时,想必会有三个问题最为关心,即ffmpeg是什么?能干什么?怎么開始学习?本人前段时间開始接触ffmpeg,在刚開始学习过程中.这三个问 ...
- hdu1106 字符串水题strtok()&&strchr()&&sscanf()+atoi()使用
字符串的题目 用库函数往往能大大简化代码量 以hdu1106为例 函数介绍 strtok() 原型: char *strtok(char s[], const char *delim); 功能: 分解 ...
- sql server去除重复信息,
SELECT st_id FROM ( SELECT *,ROW_NUMBER() OVER( PARTITION BY st_code ORDER BY st_code ) AS num FROM ...
- 《JavaScript 闯关记》之函数
函数是一段代码,它只定义一次,但可以被执行或调用任意次.在 JavaScript 里,函数即对象,程序可以随意操控它们.比如,可以把函数赋值给变量,或者作为参数传递给其他函数,也可以给它们设置属性,甚 ...
- net 2.0使用ajax
asp.net ajax中用到了几个dll文件,这些可以从网上下载.http://ajax.asp.net站点下可以找到相关的下载.这其中包括:System.Web.Extensions.dll.Sy ...