数据结构01——线性表及其相关操作(增删改查)java版

数据结构 —— 线性表——顺序表和单链表的增删改查(java实现版)

前言:最近在复习数据结构,进行分章总结复习到的知识点,当作笔记以加深记忆。同时以java语言进行具体的操作实现(eclipse实现),需要的同学可以适当作为参考,有不正确的地方欢迎指正

#一:线性表的定义

   什么是线性表呢?首先我们得明白,线性表是一种用来存储数据的线性结构!
   一般我们这样来定义线性表:线性表是n(n>=0)个数据特性相同的元素的组成有限序列。
这里我们应该注意:线性表内的数据元素类型应该是相同的!

二:线性表的特点

 从线性表的定义中其实我们就可以看出线性表的大概特点(非空线性表中,即n>0.n=0时称为空表):

1.“有限”——说明有头有尾 专业术语为:存在唯一一个被称为“第一个”的数据元素,存在唯一一个被称为“最后一个”的数据元素
2.“序列“——在此我简单的将它理解为站好队,因此也就有前后的问题 专业术语为:除第一个元素外,每个元素都有唯一的一个”直接前驱“。除最后一个元素外,每一个元素都有唯一的”直接后继“(说的就是麻烦哈,其实就是前面有人和后面有人呗)

三:线性表的存储方式(最重要)

线性表是存储数据的一种数据结构,那么它到底是怎样存储的呢?这是我们学习线性表务必要掌握的知识。

线性表的存储——分为顺序存储结构(顺序表)和链式存储结构(链表)。(画重点)

1:顺序表

定义:顺序表,一般使用数组实现。也就是在内存中找个初始地址,然后数据元素依次排队,数组大小有两种方式指定——静态分配和是动态扩展。(在此我把它比喻为操场上排队,带头的找个位置站好,其他的人依次往后排)
该图片来源于百度
(图片百度找的)

特点:在存储空间中连续(紧挨着),数据有长度(此处为5)

2.链表

定义:用一组任意的存储单元存储线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的),包括数据域和指针域,数据域存数据,指针域指示其后继的信息。
在这里插入图片描述
(图片百度找的)

可以抽象为:
在这里插入图片描述

特点:存储空间中不连续(满天飞哈)具有数据域和指针域(茫茫人海中,知道要去牵谁滴手)

3:顺序表和链表对数据的操作及优缺点(非常重要)

用线性表干嘛?肯定是用来操作数据啦。线性表对数据最多的操作就是——查找,插入和删除啦。(此处先用文字描述,具体实现在代码里,包括注释,很多东西一看到代码就懂了)

1:查找
顺序表的查找:(依然用这个图)

现在我要查3 知道了1的位置 那么从一开始 查3次(查1,2,3)第三次得到是3停止查找(因为数据在内存中是连续的,所以可以这样查找)
单链表的查找:

依旧是查3号,现在直到头节点1号的位置,然后就开始往后依次往后找,中间隔了多少个空间就得查多少次!(真累,至于为啥不能用索引呢?因为存储的不连续,满天飞的下场)

由此可以看出,在查找方面,一般来讲顺序表是比单链表要有优势的。

2:插入

顺序表的插入:
说到这个就不得不说上面的排队,这就是插队啊!有人插队了咋办?揍他一顿呗,是领导揍不起那没办法,排在领导要插队的位置后面的人都像后挪一个位。当然如果最后一个人后面是墙了那不好意思,这队差不了(大致就是这意思)

单链表的插入:领导要要插队,没关系,您随意。(反正再胖空位都能容下你),前面的人知道后面的人变成了领导,后面的人知道前面的现在是领导了就ok了;

3:删除

删除和插入差不多,都是位置相同移动的问题。

由此可以看出,在插入和删除方面,一般来讲,单链表是比较有优势的。

四:顺序表与线性表的优缺点

下面对顺序表和线性表进行简单的总结
顺序表优缺点
优点:
(1)空间利用率高(理由:连续存放)
(2)存取速度高效,通过下标直接进行存储和读取。(想想排队哈)
(3)顺序存储,随机读取(不算是优点,算是特点)
缺点:
(1)插入和删除比较慢。(想想插队,后面的全部需要往后移一个位)
(2)顺序表开始时就要定义一个长度,因此是存在空间限制的。当需要存储的元素个数可能多于顺序表元素时,可能出现“溢出”问题。(想想那个领导插队最后一个人靠墙的,总不能把人给挤扁了)。当然当你放的元素个数远远小于预先分配的空间是,就
产生浪费

单链表优缺点
优点:
(1)插入和删除的速度快,保留原有的物理顺序(只改变下指针。想想上述的插队问题就明白了)。
(2)没有空间限制,基本只与内存空间大小有关。(满天飞)
(3)随机存储,顺序读取(算是特点)
缺点:
(1)存取元素比较慢(不能进行索引访问,只能从头结点开始顺序查找)
(2)占用额外的空间用来存储指针(不是连续存放的(满天飞了解下),空间碎片多)
造成空间浪费。

五.代码实现!(最关键的点来了!)

为了节省空间,所以我将操作都封装成一个函数,用哪个直接调用那个就行了。
(当然jdk本身是提供这些方法的,不过我们是学习原理而不是学习使用,所以这些操作还是要自己写滴)

先贴出我的整体的项目结构
在这里插入图片描述

一:首先定义一个接口MyList
package com.wang.first.LinearTable;

/*
 *首先 创建顺序表的接口
 */

public interface MyList {
	//1:返回线性表大小
	public int getSize();
	
	//2:判断线性表是否为空:false:true
	public boolean isEmpty();
	
	//3:判断线性表是否含有元素e
	public boolean contains(Object e);

	
	//4: 查找 返回e元素所在的位置
	public int indexOf(Object e);

	//4.1:查找 返回第i个位置的元素
	public Object get(int i);
	//5:将元素e插入到顺序表的第i个位置
	public void add(int i,Object e) throws Exception;
	public void add(Object e) throws Exception;
	//6:将元素e插入到obj之前
	public boolean addBefore(Object obj,Object e) throws Exception;
	
	//7:将元素e插入到obj之后
	public boolean addAfter(Object obj,Object e) throws Exception;
	
	//8:删除第i个位置元素
	public void remove(int i) throws Exception;
	
	//9:删除线性表中第一个为e的元素
	public boolean removed (Object e) throws Exception;
	
	//10:替换第i个元素为e
	public Object replace(int i,Object e) throws Exception;
	 
	//11:输出线性表
	public void display();
	
	
}

二、顺序表的代码实现(增删改查)
1 首先实例化接口
package com.wang.first.LinearTable;
/*
 * 顺序表
 * 执行MyList接口
 */

public class MyArrayList implements MyList {
	
	//创建一个存储空间为maxSize的顺序表
	private Object[] myList;//顺序表的存储空间
	private int size;//顺序表的当前长度
	private int maxSize;
	
	//构建顺序表
	 public MyArrayList(int maxsize) {
		size=0;
		maxSize=maxsize;
		myList=new Object[maxSize];
		
	}

	@Override
	public int getSize() {//获取顺序表大小
		
		// TODO Auto-generated method stub
		return this.size;
	}

	@Override
	public boolean isEmpty() { //空表
		// TODO Auto-generated method stub
		return size==0;
	}

	@Override
	public boolean contains(Object e) {//判断是否含有元素e
		// TODO Auto-generated method stub
		for (int i=0;i<size;i++){//遍历
			if(myList[i].equals(e)){
				return true;				
			}
			
		}
		return false;
		
	}

	@Override
	public int indexOf(Object e) { //返回元素e的位置
		// TODO Auto-generated method stub
		for (int i=0;i<size;i++){
			if(myList[i].equals(e)){
				return i;				
			}
		}
		return -1;
	}
	public Object get(int i){//返回第i个位置的元素

		return myList[i];
		//return -1;
		
	}

	@Override
	public void add(int i, Object e) throws Exception { //插入到i位置
		// TODO Auto-generated method stub
		if(size==maxSize)
			throw new Exception("顺序表已满,不可插入");//throw为手动抛出异常
		if(i<0||i>size)
		   throw new Exception("插入位置不合法");
		for(int j=size;j>i;j--){ 
			myList[j]=myList[j-1];//i之后的数据依次后移
		}
		myList[i]=e;
		size++;
		
	}

	@Override
	public void add(Object e) throws Exception {
		// TODO Auto-generated method stub
		this.add(size,e);
		
	}
	@Override
	public boolean addBefore(Object obj, Object e) throws Exception {//obj前插入e
		// TODO Auto-generated method stub
		//找到obj所在的位置 调用插入就行
		int i=indexOf(obj);
		if(i<0) return false;
		add(i,e);
		return true;
		
	}

	@Override
	public boolean addAfter(Object obj, Object e) throws Exception { //obj后插入e
		// TODO Auto-generated method stub
		int i=indexOf(obj); //获取obj元素位置
		if(i<0) return false; //没找到obj就会返回-1 此时i=-1;
		add(i+1,e); //找到了调用插入即可
		return true;
		
		
	}

	@Override
	public void remove(int i) throws Exception {//移除第i个位置的元素 
		// TODO Auto-generated method stub
		if(i<0||i>size-1)  //判断是否越界
			throw new Exception("删除位置不合法");
		for(int j=i;j<size-1;j++){
			myList[j]=myList[j+1];  //后面的依次向前移一个位置
			
		}
		size--;//移除了一个 所以长度-1 
		
		
	}

	@Override
	public boolean removed(Object e) throws Exception {//直接移除元素e(第一个匹配的e)移除所有的没有写
		// TODO Auto-generated method stub
		//找到e的位置调用上面的删除 (先判断有没有)
		 int i=indexOf(e);
		 if(i<0) return false; //判断有没有e
		 remove(i);
		 return true;
		
	}

	@Override
	public Object replace(int i, Object e) throws Exception { //替换第i位置的元素为e
		// TODO Auto-generated method stub
	   if(i<0||i>size)
		   throw new Exception("位置不合法");
	  
	   Object obj=myList[i];
	   myList[i]=e;
	   
		return obj;
	}

	@Override
	public void display() {//输出顺序表
		// TODO Auto-generated method stub
		for(int i=0;i<size;i++){
			System.out.print(myList[i]+" ");
			
		}
		System.out.println("\n");
		
	}



}

2、小程序调用具体实现
package com.wang.first.LinearTable;
/*
 * 小测试1: 在0——9中作查看,插入 ,删除,和修改 
 * 
 * @:北城
 */

public class arraylistTest01 extends MyArrayList { //继承
	public arraylistTest01(int maxsize) {
		super(maxsize);
		// TODO Auto-generated constructor stub
	}
public static void main(String[] args) throws Exception {
	arraylistTest01 t1=new arraylistTest01(100); //申请空间 注意此处如果是10插入的时候会抛出手写的那个异常
	for(int i=0;i<10;i++){
		t1.add(i, i); //调用insert依次插入构成顺序表
		}
	System.out.print("初始化的顺序表为:");
	t1.display();//显示插入的顺序表
	//1:查看
	System.out.print("元素4位置为:"+t1.indexOf(4));//查看元素4的位置 从第0个开始
	System.out.println("\n");
	//2:插入
	t1.add(2, 50);//第二个位置插入元素50
	System.out.print("插入元素后的顺序表为:");
	t1.display();
	//3:删除某个位置的元素
	t1.remove(5);
	System.out.print("删除第5个元素后的顺序表为:");
	t1.display();
	//4:删除某个元素 :看着函数一样但是参数属性不一样 调用要注意
	t1.removed(5);
	System.out.print("删除元素5后的顺序表为:");
	t1.display();
	//修改
	t1.replace(8,100);
	System.out.print("将第8个元素替换成100后的顺序表为:");
	t1.display();	
	
	}

}

3、结果如下图

在这里插入图片描述

二、单链表的实现
1、首先定义结点类

为了便于理解与使用,此处Node中的data和next暂时定义为public型

package com.wang.first.LinearTable;
/*
 * 单链表采用了结点,所以需要定义下结点
 * 主要是两个数据:内容和指向下一个结点的指针
 */
public class Node {
//	private Object data;
//	private Node next;
	//为了便于理解与使用,此处暂时定义为public型
	 Object data;
	 Node next;
	
	
	//生成方法
	public Node() {
		super();
	}
	
	public Node(Object data, Node next) {
		super();
		this.data = data;
		this.next = next;
	}

	
	public Node(Object data) {
		super();
		this.data = data;
	}

	
	
	public Object getData() {
		return data;
	}
	public void setData(Object data) {
		this.data = data;
	}
	public Node getNext() {
		return next;
	}
	public void setNext(Node next) {
		this.next = next;
	}
	
	

	}

2、实例化接口方法
package com.wang.first.LinearTable;

public class MyLinkList implements MyList {
	private Node head=new Node();//定义一个头结点 不存数据,为了操作方便
	private int size;//定义有几个结点	
	@Override
	public int getSize() {
		
		return size;
	}

	@Override
	public boolean isEmpty() {
		// TODO Auto-generated method stub
		return size==0;
	}

	@Override
	public boolean contains(Object e) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public int indexOf(Object e) {
		// TODO Auto-generated method stub
		Node p=head;
		for(int j=0;j<size;j++){
			if(p.data==e)
				return j;
			p=p.next;
			
		}
		
		return -1;
	}
	public Object get(int i){
		Node p=head;
		for(int j=0;j<i;j++){
			p=p.next;
		}
		return p.data;
	}

	@Override
	public void add(int i, Object e) throws Exception {
		// TODO Auto-generated method stub
		if(i<0||i>size){
			throw new Exception("插入位置异常"+i);
		}
		Node p=head;
		for(int j=0;j<i-1;j++){
			p=p.next;
		}
		Node newNode=new Node();
		newNode.data=e;
		newNode.next=p.next;
		p.next=newNode;	
	
		size++;
		
	}
	public void add(Object e) throws Exception{ //上面的一种特殊情况
	 this.add(size, e);
	}

	@Override
	public boolean addBefore(Object obj, Object e) throws Exception {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean addAfter(Object obj, Object e) throws Exception {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void remove(int i) throws Exception {
		// TODO Auto-generated method stub
		if(i<0||i>size){
			throw new Exception("删除位置异常"+i);
		}
		Node p=head;
		for(int j=0;j<i-1;j++){
			p=p.next;
		}
		p.next=p.next.next;
		size--;
		
	}

	@Override
	public boolean removed(Object e) throws Exception {
		// TODO Auto-generated method stub
		
		int i=indexOf(e);
		
		remove(i);
		return true;
	}

	@Override
	public Object replace(int i, Object e) throws Exception {
		// TODO Auto-generated method stub
		if(i<0||i>size){
			throw new Exception("替换位置异常"+i);
		}
		Node p=head;
		for(int j=0;j<i;j++){
			p=p.next;
		}
		p.data=e;
		return p;
	}

	@Override
	public void display() {
		Node p=head;
		for(int j=0;j<size;j++){
			p=p.next;
			System.out.print(p.data+" ");
			
		}
		System.out.println("\n");
		
	}

}

3、具体程序实现
package com.wang.first.LinearTable;
/*
 * 小测试2: 在10——19中作查看,插入 ,删除,和修改 
 * 
 * @:北城
 */

public class linklistTest01 extends MyLinkList { //继承

public static void main(String[] args) throws Exception {
	MyList t1=new MyLinkList(); //申请空间 
	//t1.add(0, 1);
	
	for(int i=10;i<20;i++){
		t1.add(i); //调用add依次插入 构成单链表
		}
	System.out.print("初始化的顺序表为:");
	t1.display();//显示插入的顺序表
	//1:查看
	t1.indexOf(14);
	System.out.print("元素14位置为:");//查看元素14的位置 从第0个开始
	t1.display();
	
	System.out.println("第10个位置的元素为: "+t1.get(10)+"\n");

	
	//2:插入
	t1.add(2, 50);//第二个位置插入元素50
	System.out.print("插入元素后的顺序表为:");
	t1.display();
	//3:删除某个位置的元素
	t1.remove(2);
	System.out.print("删除第2个元素后的顺序表为:");
	t1.display();
	//4:删除某个元素 :看着函数一样但是参数属性不一样 调用要注意
	t1.removed(18);
	System.out.print("删除元素18后的顺序表为:");
	t1.display();
	//修改
	t1.replace(2,100);
	System.out.print("将第2个元素替换成100后的顺序表为:");
	t1.display();	
	
	}

}

4、结果如下

注意我设置的下标从0开始计数

在这里插入图片描述

到此基本要实现的功能算是完成啦,下一篇博客将会写出复习数据结构第二章——栈和队列的原理与java实现

  • 9
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值