数据结构与算法
数据结构的定义
数据:能被计算机识别,存储,和计算的东西(二进制)。
数据结构:将零散的数据整齐划一方便后续的操作。
数据的逻辑结构----- 是指数据元素之间的相互关系,并没有实质性的存储在计算机中。
逻辑结构
1.集合结构:集合结构中的数据元素除了同属于一个集合外,他们之间没有其他关系。
2.线性结构:线性结构中的数据元素之间是一对一的关系。
3.树形结构:树形结构中的数据元素之间存在一对多的层次关系。
4 .图形结构:图形结构的数据元素是多对多关系。
数据的物理结构:(根据不通场景灵活选择)
顺序存储结构:开辟一组连续的空间存储数据,通常用数组来实现,数组中空间本身是连续的,保证了数据之间的关系。
链示存储结构:开辟一组随机的空间存储数据,通常用节点来实现,节点不仅要存储数据,还要存储下一个节点的位置以保证数据之间的关系
数组:查找和修改快,,内存连续,通过下标访问。
链表:增加和删除快。查询只能从第一个开始。空间利用高。
算法
算法:解决特定问题求解步骤的描述(求解问题的步骤)。
时间复杂读
方案1:
int sum =0;
int N =100;
for(int i=1;i<=N;i++){
sum+=i;
}
方案2
int N=100;
int sum =(N+1)*N/2;
方案1随着N的增大,循环的次数也会增大,也就意味着执行的次数和运行的时间也会增大。
方案2随着N的增大其执行次数只有一次,不会随着N的增大而增大。
同一种问题,可以有多种不同的解决方案,也就是说可以用不同的算法去解决同一个问题。
时间复杂度:
常数阶:O(1)不随N的增大而增大
线性阶:O(n)忽略常数,忽略N的系数
对数解: O(logn):虽有循环,也随N的增大而增大,
平方阶: O(n*n)
算法评价
设计算法要提高程序运行的效率,这里效率大多指算法的执行时间
事后统计方法:这种方法主要通过设计好的程序和数据,利用计算机计时器对不同算法程序的运行时间进行比较,从而确定算法效率的高低。
缺点:必须先编好程序,在运行。花费大量时间。
事前分析估算法:这种方法主要在计算机程序编制前,依据统计方法对算法进行估算。
一个高级程序语言编写的程序在计算机上运行所消耗的时间取决于下列因素:
算法采用的策略,方法。
编译产生的代码质量
问题的输入规模。
机器执行指令的速度。
动态数组
1.java内置数组的特点:
数组的长度一旦却确定则不可更改。
数组只能存储同一类型的数据。
数组中每个存储空间大小一致且地址连续。
数字提供角标访问元素 。
2java内置数字的潜在问题
当容量不够用时,需要对数组进行 扩容。
指定位置插入或删除元素,(可以通过数组下标进行插入或删除)。
数组对象只有length属性。
3.动态数组的封装:我们可以把数组的相关属性和相关行为封装在类种,类似字符串String 类,通过方法进行调用。
4.封装动态数组
属性方面
int size 数组的有效元素个数
int capacity 数组的最大容量data.length
E[] data 数据的存储容器
线性表的存储结构
线性表的定义
零个或多个元素的有限序列
若将线性表标记为(a1,…ai-1,ai,ai+1,…an)则表中ai-1领先于ai,ai领先于ai+1,称ai-1是ai的直接前去元素,ai+1是ai的直接后继元素。当i=1,2…n-1时,ai有且仅有一个直接后继,当i=2,3,…n时,ai有且只有一个直接前驱。
所以线性表的个数n(n>0定义为线性表的长度),当n=0时称为空表。
线性表list接口的定义
/*
* list是线性表的最终父接口
* @param <E>
*/
public interface List<E> {
/**
* 获取线性表中的元素个数(线性表的长度) 线性表中有效元素的个数
*/
public int getSize();
/**
* 判断线性表是否为空
* @return 是否为空的布尔类型
*/
public boolean isEmpty();
/**
* 在线性标中指定的index的角交表出添加元素e index 指定的角标0<=index<=线性表达长度 e 插入的元素
*/
public void add(int index, E e);
/**
* 在线性表的表头位置添加一个元素元素e
* @param e 要插入的元素 指定在角标0处
*/
public void addFrist(E e);
/**
* 在线性表的表尾处插入一个元素e
*
* @param e 插入的元素指定在角标size处
*/
public void addLast(E e);
/**
* 在线性表中获取指定的index角标处的元素
*
* @param index 指定的角标 0<=index<size
* @return 该角标所对应的元素
*/
public E get(int index);
/**
* @return
*/
public E getFrist();
/**
* 获取线性表中表头的元素
* @return 表头元素 index =0
*/
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 removeFrist();
/**
* 删除线性表的的表尾头元素
* @return 表尾元素
*/
public E removeLsat();
/**
* 在线性表中删除指定元素e
*/
public void removeElement(E e);
/**
* 清空线性表
*/
public void clear();
}
数组进行扩容或缩容:
/*
* 改变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;
}
重新创建一个数组大小为原数组的2倍,将原数组的元素放到新数组中并将新数组的地址赋给原数组。
线性表顺序存储的定义
指的是用一段地址连续的存储单元一次存储线性表的数据元素。
ArrayList类的封装属性
private E[] data; // 存储数据元素的容器
private int size; // 线性表有效元素的个数
// data.length表示线性表的最大容量
private static int DEFAULT_SIZE = 10;// 容器默认容量
ArrayList类实现List接口
/**
* 用顺序存储结构实现的list顺序线性表
* @author lenovo
* @param <E>
*/
public class ArrayList<E> implements List<E> {
private E[] data; // 存储数据元素的容器
private int size; // 线性表有效元素的个数
// data.length表示线性表的最大容量
private static int DEFAULT_SIZE = 10;// 容器默认容量
/**
* 创建一个容量默认为10的线性表
*/
public ArrayList() {
this(DEFAULT_SIZE);
}
/**
* 创建一个容量为capacity的线性表
*/
public ArrayList(int capacity) {
this.data = (E[]) new Object[capacity];
this.size = 0;
}
/**
* 将一个数组封装成一个线性表
*/
@Override
public int getSize() {
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 addFrist(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函数下标越界");
}
return data[index];
}
@Override
public E getFrist() {
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("set函数下标越界");
}
}
@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函数角标越界");
}
E e = get(index);
for (int i = index + 1; i <= size - 1; i++) {
data[i - 1] = data[i];
}
size--;
// 判断是否缩容
// 最短不能缩过默认容量
// 有效元素个数小于等于原容量的1/4
if (data.length > DEFAULT_SIZE && size <= data.length / 4) {
resize(data.length / 2);
}
return e;
}
@Override
public E removeFrist() {
remove(0);
return null;
}
@Override
public E removeLsat() {
remove(size - 1);
return null;
}
@Override
public void removeElement(E e) {
int index = find(e);
if (index == -1) {
throw new IllegalArgumentException("删除元素不存在");
}
remove(index);
}
@Override
public void clear() {
size = 0;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("ArrayList:size=" + size + ",capacticy=" + 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 class Main {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<Integer>();
System.out.println(list);
for(int i=1;i<=5;i++){
list.addFrist(i);
}
System.out.println(list);
for(int i=6;i<=10;i++){
list.addLast(i);
}
System.out.println(list);
list.add(5, 0);
System.out.println(list);
for(int i=11;i<=30;i++){
list.addLast(i);
}
System.out.println(list);
for(int i=1;i<=10;i++){
System.out.println(list.removeFrist());
}
System.out.println(list);
for(int i=1;i<=10;i++){
System.out.println(list.removeFrist());
}
System.out.println(list);
list.remove(5);
}
}