数据结构与算法-概述

一、数据结构的概述

数据结构:是相互之间存在一种或多种特定关系的数据元素的集合
1.数据结构的逻辑结构
是指数据元素之间的相互关系,是我们想象出来的,并没有实质性的将其存储在计算机中
1)集合结构:集合结构中的数据元素除了同属于一个集合外,它们之间没有其他关系(比如同一片区域的人,他们同处于一个集合,但他们之间是没有其他关系的)
2)线性结构:线性结构中的数据元素之间是一对一的关系
3)树形结构:树形结构中的数据元素之间存在一对多的层次关系
4)图形结构:图形结构的数据元素是多对多的关系

2.数据结构的物理结构
是指数据的逻辑结构在计算机中的存储形式
1)顺序存储结构:开辟一组连续的空间存储数据,通常用数组来实现,数据中的空间本身是连续的,保证了数据之间的关系
2)链式存储结构:开辟一组随机的空间存储数据,通常用节点来实现,节点不仅要存储数据,还要存储下一个节点的位置以保证数据之间的关系
3.顺序存储结构和链式存储结构的区别
1)顺序存储查找数据元素快,链式插入和删除元素快
2)顺序所占用的空间较大,链式占用空间小

二、算法

算法:解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列,并且每条指令表示一个或多个操作。
算法的五个基本特性:输入、输出、有穷性、确定性和可行性。
如何衡量一个算法的好坏呢?
一个好的算法包括以下特征:正确性、可读性、健壮性、时间效率高和存储量低、
1.时间复杂度
定义:在进行算法分析时,语句总的执行次数T(n)是关于问题规模n的函数,进而分析T(n)随n的变化情况并确定T(n)的数量级。算法的时间复杂度,也就是算法的时间量度,记作:T(n)=O(f(n))。它表示随着问题规模n的增大,算法执行时间的增长率和f(n)的增长率相同,称作算法的渐进时间复杂度。简称时间复杂度。其中f(n)是问题规模n的某个函数
1)常数阶O(1)

int N=100;                    //执行一次
int sum = (N+1)*N/2;   //执行一次

随着N的增大,运行次数不变,所以时间复杂度为O(1)
2)线性阶O(n)

int sum = 0;                      //执行1次
int N=100;                        //执行1次
for(int i =1;i<=N;i++){       //执行N+1次
	sum+=i;                       //执行N次
}

上述代码执行了2N+3次,时间复杂度为O(n) (通常可以忽略n的常数,n的系数)
3)对数阶O(logn)

int count = 1;
int N = 100000;
while(count<N){
	count = count * 2;  
}

假设循坏运行了x次,那么2^x=N,则log2(N)
4)平方阶O(n^2)

int N=1000;                        
for(int i =0;i<N;i++){            //执行N+1次
	for(int j =0;j<N;j++){        //执行N+1次
		........						   //执行N^2次
	}
}

对于n²来说可以忽略常数、幂高项的系数,只保留幂的最高项,因为随着n的增大,它的值会大幅度的增高,所以说系数、常数可以忽略不记。

执行次数函数非正式术语
12O(1)常数阶
2n+3O(n)线性阶
3n²+2n+1O(n²)平方阶
5log2(n)+20O(logn)对数阶
2n+3nlog2(n)+19O(nlogn)nlogn阶
6n³+2n²+3n+4O(n³)立方阶
2^nO(2^n)指数阶

在这里插入图片描述
注意:我们考虑的时间复杂度都是最坏情况!

三、动态数组

注意:动态数组就是顺序存储结构的具体实现
1.Java内置数组的特点:

  • 数组的长度一旦确定则不可更改
  • 数组只能存储同一类型的数据
  • 数据中每个存储空间大小一致且地址连续
  • 数据提供角标的方式访问元素

2.线性表的顺序存储结构
线性表:
1)零个或多个数据元素的有限序列
2)可通过索引访问元素
3)除了第一个元素没有前驱,最后一个元素没有后继,其他元素都有唯一的前驱和后继

3.List 线性表接口定义

/**
 * List是线性表的最终父接口
 * @author ABC
 *  * @param <E>
 */
public interface List<E> {
	
	/**
	 * 获取线性表中元素的个数(线性表的长度)
	 * @return 线性表中有效元素的个数
	 */
	public int getSize();
	
	/**
	 * 判断线性表是否为空
	 * @return 是否为空的布尔类型值
	 */
	public boolean isEmpty();
	
	/**
	 * 在线性表中指定的index角标处添加元素e
	 * @param index 指定的角标 0<=index<=size
	 * @param e 要插入的元素
	 */
	public void add(int index,E e);
	
	/**
	 * 在线性表的表头位置插入一个元素
	 * @param e 要插入的元素 指定在角标0处
	 */
	public void addFirst(E e);
	
	/**
	 * 在线性表的表尾位置插入一个元素
	 * @param e 要插入的元素 指定在角标size处
	 */
	public void addLast(E e);
	
	/**
	 * 在线性表中获取指定index角标处的元素
	 * @param index 指定的角标0<=index<size
	 * @return 该角标所对应的元素
	 */
	public E get(int index);
	
	/**
	 * 获取线性表中表头的元素
	 * @return 表头元素 index=0
	 */
	public E getFirst();
	
	/**
	 * 获取线性表中表尾的元素
	 * @return 表尾的元素 index=size-1
	 */
	public E getLast();
	
	/**
	 * 修改线性表中指定的index处元素为新元素e
	 * @param index 指定的角标
	 * @param e 新元素
	 */
	public void set(int index,E e);
	
	/**
	 * 判断线性表中是否包含指定元素e 默认从前往后找
	 * @param e 要判断是否存在的元素
	 * @return 元素的存在性布尔类型值
	 */
	public boolean contains(E e);
	
	/**
	 * 在线性表中获取指定元素e的角标,默认从前往后
	 * @param e 要查询的数据
	 * @return 数据在线性表中的角标
	 */
	public int find(E e);
	
	/**
	 * 在线性表中删除指定角标处的元素,并返回
	 * @param index 指定的角标 0<=index<size
	 * @return 删除掉的老元素
	 */
	public E remove(int index);
	
	/**
	 * 删除线性表中的表头元素
	 * @return 表头元素
	 */
	public E removeFirst();
	
	/**
	 * 删除线性表中的表尾元素
	 * @return 表尾元素
	 */
	public E removeLast();
	
	/**
	 * 在线性表中删除指定元素
	 * @param e 指定元素
	 */
	public void removeElement(E e);
	
	/**
	 * 清空线性表
	 */
	public void clear();
}

4.ArrayList 顺序表类定义

  • 定义成员属性
private static int DEFAULT_SIZE=10; //容器的默认容量
private E[] data; //存储数据元素的容器
private int size; //线性表中的有效元素的个数 
				  //data.length表示线性表中的最大容量Capacity
  • 定义构造函数
	/**
	 * 创建一个容量默认值为10的一个线性表
	 */
	public ArrayList(){
		this(DEFAULT_SIZE);
	}
	
	/**
	 * 创建一个容量为指定capacity的一个线性表
	 * @param capacity
	 */
	public ArrayList(int capacity){
		this.data=(E[]) new Object[capacity];
		this.size=0;
	}

	/**
	 * 将一个数组封装成为一个线性表
	 * @param arr 
	 */
	public ArrayList(E[] arr){
		data = (E[]) new Object[arr.length];
		for(int i=0;i<data.length;i++){
			data[i]=arr[i];
		}
		size = data.length;
	}
  • 定义成员函数
    (1)添加元素的思路:添加元素时可分为三种情况:表头、表尾、中间。
    • 如果添加的位置不正确,则抛出异常
    • 如果表长大于数组的长度,则抛出异常或者扩容
    • 从最后一个元素开始向前遍历到第i个元素,分别将它们向后移动一个位置
    • 将要添加的元素放入i位置
    • 表长+1

(2)删除元素的思路:
* 如果删除位置不合理,则抛出异常
* 取出删除元素
* 从删除元素的位置开始遍历到最后一个元素,分别将它们向前移动一个位置
* 表长-1
(3)扩容和缩容思路:当存入较多的数据时,要对数组进行扩容,同理当删除较多的数据时,为了避免浪费空间,要进行缩容。扩容操作和缩容操作都是创建一个新的数组,指定新的长度,将旧数组里面的元素copy到新数组当中。

	@Override
	public int getSize() {
		// TODO Auto-generated method stub
		return size;
	}

	@Override
	public boolean isEmpty() {
		
		return size==0;
	}

	@Override
	public void add(int index, E e) {
		
		if(index<0 || index>size){
			throw new ArrayIndexOutOfBoundsException("add():角标越界");
		}
		//判断是否已满
		if(size==data.length){
			resize(2*data.length);
		}
		for(int i=size-1;i>=index;i--){
			
			data[i+1] = data[i];
		}
		data[index]=e;
		size++;
	}
	
	/**
	 * 改变data的长度(扩容、缩容)
	 * @param newlen 新数组的长度
	 */
	private void resize(int newlen){
		
		E[] newData = (E[]) new Object[newlen];
		for(int i=0;i<size;i++){
			
			newData[i] = data[i];
		}
		data = newData;
	}

	@Override
	public void addFirst(E e) {
		
		add(0,e);
	}

	@Override
	public void addLast(E e) {
		
		add(size,e);
	}

	@Override
	public E get(int index) {
		
		if(index<0 || index>size-1){
			throw new ArrayIndexOutOfBoundsException("get():index out of range");
		}
		
		return data[index];
	}

	@Override
	public E getFirst() {
		
		return get(0);
	}

	@Override
	public E getLast() {
		
		return get(size-1);
	}

	@Override
	public void set(int index, E e) {
		
		if(index<0 || index>size-1){
			throw new ArrayIndexOutOfBoundsException("get():index out of range");
		}
		data[index]=e;
	}

	@Override
	public boolean contains(E e) {
		
		if(isEmpty()){
			return false;
		}
		for(int i=0;i<size;i++){
			if(data[i]==e){
				return true;
			}
		}
		return false;
	}

	@Override
	public int find(E e) {
		
		if(isEmpty()){
			return -1;
		}
		for(int i=0;i<size;i++){
			if(data[i]==e){
				return i;
			}
		}
		return -1;
	}

	@Override
	public E remove(int index) {
		if(index<0 || index>size-1){
			throw new ArrayIndexOutOfBoundsException("remove():index out of range");
		}
		E e = get(index);
		for(int i=index+1;i<=size-1;i++){
			data[i-1] = data[i];
		}
		size--;
		//判断是否缩容
		//1.最短不能缩过默认容量
		//2.有效元素的个数小于等于容量的1/4
		if(data.length > DEFAULT_SIZE && size<=data.length/4){
			resize(data.length/2);
		}
		return e;
	}

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

	@Override
	public E removeLast() {
		
		return remove(size-1);
	}

	@Override
	public void removeElement(E e) {
		
		int index =find(e);
		if(index==-1){
			throw new IllegalArgumentException("删除元素不存在");
		}
		remove(index);
		
	}

	@Override
	public void clear() {
		
		size=0;
	}
	
	public String toString(){
		
		StringBuilder sb = new StringBuilder();
		sb.append("ArrayList: size="+size+",capacity="+data.length+"\n");
		if(isEmpty()){
			sb.append("[]");
		}else{
			sb.append('[');
			for(int i =0; i <size;i++){
				sb.append(data[i]);
				if(i == size-1){
					sb.append(']');
				}else{
					sb.append(',');
				}
			}
		}
		return sb.toString();
	}
	
	public int getCapacity(){
		return data.length;
	}
	
	public void swap(int i, int j){
		//判断 i j
		E temp = data[i];
		data[i] = data[j];
		data[j] = temp;
	}
	
	@Override
	public boolean equals(Object obj) {
		if(obj==null){
			return false;
		}
		if(obj==this){
			return true;
		}
		if(obj instanceof ArrayList){
			ArrayList l = (ArrayList) obj;
			if(getSize() == l.getSize()){
				for(int i = 0;i<getSize();i++){
					if(get(i)!=l.get(i)){
						return false;
					}
				}
				return true;
			}
		}
		return false;
	}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值