大话数据结构(1.线性表)

1.数据结构概述

1.1.数据结构的分类

1.1.1.数据结构主要分为

1.线性结构 --数组,队列,链表,哈希表…
2.树结构 --二叉树,二分搜索树,AVL,堆…
3.图结构 --邻接表,邻接矩阵…

1.1.2.数据结构的逻辑结构

1.集合结构

元素同属于一个集合外,它们之间没有其他的关系

2.线性结构

数据元素是一一对应的关系

3.树状结构

元素存在一对多的关系

4.图形结构

元素存在多对多的关系

1.1.3.数据结构的物理结构

1.顺序存储结构
利用数组将元素存储,将元素存储在连续的地址单元
2.链式存储结构
利用链表随机存储元素。只需要该元素有前驱即可查找。

1.2.时间复杂度计算

1.2.1.定义

在进行算法分析时,语句总的执行次数T(n)是关于问题规模n的函数,进而分析T(n)随n
的变化情况并确定T(n)的数量级。算法的时间复杂度,也就是算法的时间量度,记作:
T(n)=O(f(n))。它表示随着问题规模n的增大,算法执行时间的增长率和f(n)的增长率相同,
称作算法的渐进时间复杂度。简称时间复杂度。其中f(n)是问题规模n的某个函数。

1.2.2.计算方法

1.常数阶 O(1)
如果代码没有循环体,则复杂度为O(1)
2.线性阶O(n)
如果代码只有一层循环体且为单指针,则复杂度为O(n)
3.对数阶O(logn)
虽有循环且随着N的增大而增大,但增大的速度一直在减小。譬如我们以前直到的二分查找。
4.平方阶O(n^2)
双层嵌套循环。
大话数据结构(1.线性表)_第1张图片

2.动态数组

2.1.为什么要有动态数组?

由于静态数组具有以下的缺点:
1.数组长度一旦确定就不可更改
2.增删元素时时间复杂度太大
3.数组只有length这一个属性

2.2.线性表(List)

线性表为零个或多个数据元素的有限序列

首先他是个序列,所以元素之间是有顺序,若元素存在多个,则第一个元素无前驱,最后一个元素无后继。其余元素都有前驱或后继。

大话数据结构(1.线性表)_第2张图片且注意,一个线性表支持一种数据类型,数据类型可以自己定义。

2.3.线性表的存储方式(顺序存储)

2.3.1.顺序存储的定义

线性表的顺序存储结构,指的是用一段地址连续的存储单元存储线性表中的数据元素。
大话数据结构(1.线性表)_第3张图片

2.3.2.顺序存储方式

由于线性表要分配一段连续的存储单元来存储数据元素,这是我们就可以想到一维数组。由于一维数组就是一段连续的地址,且数组中都是相同的数据类型,所以List中用数组最为合适。
数据存储结构需要三个属性:
1.存储空间的起始单元:数据data,它的存储位置就是存储空间的存储单元。
2.线性表存储元素的有效个数size
3.线性表最多可以存储元素的个数data.length

这里得注意:size永远是小于等于data.length的,size可以等于0

所以,我们可以定义出ArrayList类以及一些基本的增删改查等操作:
这里我将这些操作定义成了list1接口,在方法中只需要实现这些接口的方法即可。

public class ArrayList implements List1 {
	private E []data;
	private int size;//元素的有效个数
	private static final int CAPICITY=10;
	public ArrayList() {
		data=(E[]) new Object[CAPICITY];
		this.size=0;
	}
	public ArrayList(int length) {
		data=(E[])new Object[length];
		this.size=0;
	}
	@Override
//1.获取有效存储个数
	public int getSize() {
		return size;
	}

	@Override
//2.判空
	public boolean isEmpty() {
		return size==0;
	}

	@Override
//3.增
	public void add(int index, E e) {//添加元素
		if(index<0||index>size) {
			throw new IllegalArgumentException("下标越界");
		}
		if(size==data.length) {
			resize(data.length*2);//这里将数组扩容
		}
		for(int i=size;i>index;i--) {
			data[i]=data[i-1];
		}
		data[index]=e;
		size++;
	}
	private void resize(int length) {
		E[] newdata=(E[])new Object [length];
		for(int i=0;i=size) {
			throw new IllegalArgumentException("下标越界");
		}
		E e=null;
		for(int i=index;i=CAPICITY) {
			resize(data.length/2);
		}
		return e;
	}

	@Override
	public E removeFirst() {
		return remove(0);
	}

	@Override
	public E removeLast() {
		return remove(size-1);
	}
//6.改
	@Override
	public void set(int index, E e) {
		data[index]=e;
	}
//7.判断是否包含元素e
	@Override
	public boolean contains(E e) {
		return find(e)==-1;
	}
//8.查找元素
	@Override
	public int find(E e) {
		for(int i=0;i=size||index2<0||index2>=size) {
			throw new IllegalArgumentException("下标异常");
		}
		E temp=data[index1];
		data[index1]=data[index2];
		data[index2]=temp;
		
	}
//12.重写toString方法
	public String toString() {
		if(isEmpty()) {
			return "[]";
		}else {
			StringBuilder sb=new StringBuilder();
			sb.append("[");
			for(int i=0;i

2.3.3.线性表存储元素的优缺点

首先来分析线性表增删改查元素的时间复杂度:
增(删):O(n)
改(查):O(1)
至于为何会算出来这样的时间复杂度,看一遍代码就明白了。
所以线性表存储元素的优点是:
1.无需为表示表中元素之间的逻辑关系而增加额外的存储个数
2.可以快速的查找,修改元素或与之相关的操作。
但也有其缺点:
1.插入或删除元素时需要移动大量元素,时间复杂度较高
2.当线性表长度变化较大时难以确定存储空间的容量
3.造成空间存储的浪费

2.4.线性表存储方式(链式存储)

2.4.1.链式存储的定义

链式线性表的存储特点是用一组任意的存储单元存储线性表中的元素,这组存储单元可以是连续的,也可以是不连续的。这就意味着这些数据可以存在于任意的存储位置大大提升了对内存的使用。以前每个数据只需要存储数据元素即可,但现在在链式结构中除了存储元素val之外,还需要存储他的后继元素的地址next;我们把存储数据元素的域称为数据域,把存储直接后继位置的域称为指针域。指针域中存储的信息称为指针。这两部分信息组成的数据元素ai的存储映像称为结点(Node)。
大话数据结构(1.线性表)_第4张图片如图,N个结点链接而成的链表,即为线性表的链式存储结构,因此此链表的每个结点中只包含一个指针域,叫做单链表。

2.4.2.头结点和头指针

头指针:链表中第一个结点的存储位置叫做头指针。
头结点:为了方便操作在链表第一个元素前设置一个不存任何元素只存第一个元素的地址的结点。
大话数据结构(1.线性表)_第5张图片

2.4.3.有关链表的操作

链表的操作不同于数组,首先它要有一个头结点(最好是第一个虚拟头结点方便操作),而且要注意链表的每一个结点都只知道它的后驱地址,却没有它的前驱地址。

2.4.3.1.首先要进行链表的初始化

public class LinkedList  implements List{
	private Node head;
	private Node rear;
	private int size;
	public LinkedList() {
		head=new Node();//创建虚拟头结点
		rear=head;  
		size=0;
	}
	private class Node{
		E data;
		Node next;
		public Node() {
			this(null,null);
		}
		public Node(E data) {
			this(data,null);
		}
		public Node(E data,Node next) {
			this.data=data;
			this.next=next;
		}
	}

2.4.3.2.增add()

public void add(int index, E e) {
		if(index<0||index>size) {
			throw new IllegalArgumentException("下表错误");
		}
		Node p=new Node(e);
		//1.头插
		if(index==0) {
			p.next=head.next;
			head.next=p;
			if(isEmpty()) {
				rear=p;				
			}
		}//2.尾插
		else if(index==size) {
			p.next=rear.next;
			rear.next=p;
			rear=p;						
		}
		//3.中间插
		else {
			Node n=head;
			for(int i=0;i

2.4.3.3.删romove()

public E remove(int index) {
		if(index<0||index>=size) {
			throw new IllegalArgumentException("下表错误");
		}
		E e=null;
		if(index==0) {
			e=head.next.data;
			head.next=head.next.next;
			if(size==1) {
				rear=head;
			}
		}else if(index==size-1) {
			Node p=head;
			while(p.next!=rear) {
				p=p.next;
			}
			e=rear.data;
			p.next=rear.next;
			rear=p;
		}else {
			Node p=head;
			for(int i=0;i

2.4.3.4.改set()

public void set(int index, E e) {
		if(index<0||index>=size) {
			throw new IllegalArgumentException("下表错误");
		}
		Node p=head;
		for(int i=0;i

2.4.4.4.查find()

public int find(E e) {
		if(isEmpty()) {
			return -1;
		}
		int index=-1;
		Node p=head;
		while(p.next!=null) {
			index++;
			p=p.next;
			if(p.data.equals(e)) {
				return index;
			}
		}
		return -1;
	}

2.4.4.单链表结构和顺序存储结构的对比

1.存储分配方式
顺序存储结构用一段连续的存储单元依次存储线性表中的数据元素
单链表采用链式存储结构,用一组任意的存储单元存放线性表中的元素
2.时间性能
大话数据结构(1.线性表)_第6张图片3.空间性能
大话数据结构(1.线性表)_第7张图片

你可能感兴趣的:(大话数据结构(1.线性表))