一.数据结构
1.数据结构概述
数据结构是计算机存储、组织数据的方式, 通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率。数据结构的优良将直接影响着我们程序的性能;常用的数据结构有:数组(Array)、栈(Stack)、队列(Queue)、链表(Linked List)、树(Tree)、图(Graph)、堆(Heap)、散列表(Hash)等;
2.数据结构的分类
3.数据结构的实现
1.数组
(1)数组(Array):数组是有序元素的序列,在内存中的分配是连续的,数组会为存储的元素都分配一个下标(索引),此下标是一个自增连续的,访问数组中的元素通过下标进行访问;数组下标从0开始访问;
(2)数组的优点是:查询速度快;
(3)数组的缺点是:删除增加、删除慢;由于数组为每个元素都分配了索引且索引是自增连续的,因此一但删除或者新增了某个元素时需要调整后面的所有元素的索引;
4.我们自己封装的数组
1.定义数组的基本变量
//数据容器
private T[] data;
//数组大小
private int capacity;
//数组实际存入的元素数量
private int size;
public selfArray() {//构造方法,为数组定义默认的容量
this(10);
}
public selfArray(int capacity) {//初始化变量
this.capacity = capacity;
this.data = (T[]) new Object[this.capacity];//将新的容量的新数组赋给data
this.size = 0;
}
2.判断数组是否为空, 获取数组的大小,获取数组中实际元素的个数
//判断数组是否为空
public boolean isEmpty() {
return this.size == 0;
}
//获取数组的大小
public int getCapacity() {
return this.capacity;
}
//获取实际元素的个数
public int getSize() {
return this.size;
}
3.增加元素
//向任意位置添加元素
public void addmid(T val,int index) {
//对入参进行判断
if(index<0||index>size){
throw new IllegalArgumentException("数组越界异常");
}
//判断此容器有没有满
if(this.size==this.capacity){
int newcapa = this.capacity*2;//进行扩容,扩容到原来的2倍
reserve(newcapa);
}
//将指定的位置之后的元素向后移
for (int i = this.size-1; i >=index ; i--) {
this.data[i + 1] = this.data[i];
}
//将元素插入到指定位置
this.data[index]=val;
//更新size的值
this.size+=1;
}
扩容的方法:
public void reserve(int newcapa) {
T[]newdata = (T[])new Object[newcapa];
for (int i = 0; i <this.size ; i++) {
newdata[i]=this.data[i];
}
//更新新数组的属性
this.capacity=newcapa;
this.data=newdata;
}
(1)向头部添加元素
public void addHead(T val){
addmid(val,0);
}
(2)向尾部添加元素
public void addlast(T val){
addmid(val,this.size);
}
4.获取指定为值的元素,修改指定位置的元素
//获取指定位置的元素
public T getindex(int index){
if(index<0||index>=size){
throw new IllegalArgumentException("数组越界异常");
}
return this.data[index];
}
//修改指定位置的元素
public void updataindex(int index,T val){
if(index<0||index>=size){
throw new IllegalArgumentException("数组越界异常");
}
this.data[index]=val;
}
5.是否包含指定元素, 返回指定元素的索引
//是否包含指定元素
public boolean contains(T val){
for (int i = 0; i <size ; i++) {
if(this.data[i].equals(val)){
return true;
}
}
return false;
//anyMatch表示其中只要有一个就行
//利用流进行操作
return Arrays.stream(this.data).filter(item->item!=null).anyMatch(item->item.equals(val));
}
//返回指定元素的索引
public int findindex(T val){
for (int i = 0; i <this.size ; i++) {
if(this.data[i].equals(val)){
return i;
}
}
return -1;
}
6.删除任意位置的元素
//删除任意位置的元素
public T remove(int index){
if(index<0||index>=this.size){
throw new IllegalArgumentException("数组索引越界");
}
T a = this.data[index];
for (int i = index; i <size-1 ; i++) {
this.data[i]=this.data[i+1];
}
this.size-=1;
if(this.size<=this.capacity/4&&this.size>1){//进行一个缩容
int newcapa = this.capacity/2;
reserve(newcapa);
}
return a;
}
缩容的方法:
public void reserve(int newcapa) {
T[]newdata = (T[])new Object[newcapa];
for (int i = 0; i <this.size ; i++) {
newdata[i]=this.data[i];
}
//更新新数组的属性
this.capacity=newcapa;
this.data=newdata;
}
(1)删除头部的元素
//删除头部的元素
public T removeHead(){
T a1 = this.data[0];
remove(0);
return a1;
}
(2)删除尾部元素
//删除尾部的元素
public T removeTail(){
T a3 = this.data[this.size-1];
remove(this.size-1);
return a3;
}
7.重写toString方法
//重写tostring
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < size; i++) {
stringBuilder.append(this.data[i]+",");
}
return stringBuilder.substring(0,stringBuilder.lastIndexOf(",")==-1?0:stringBuilder.lastIndexOf(","));
}
5.时间复杂度
1.概述:在计算机科学中,时间复杂性,又称时间复杂度,算法的时间复杂度是一个函数,它定性描述该算法的运行时间, 在算法领域,使用复杂度分析的内容来评价你写的代码性能如何, 在一些题目中要求我们的代码在指定的时间内完成运行,所以可以用到时间复杂度的知识.
2.动态数组的时间复杂度的分析
3.时间复杂度震荡
当我们增加一个元素进行扩容以后,马上又删除该元素进行缩容,如此反复循环的话,复杂度仍会变成O(n),这称为复杂度震荡.