数据结构:描述和组织数据的一种方式
1.顺序表
物理上(内存)和逻辑上都是连续的
对于顺序表来说:增删改查
增/删:移动数据时间复杂度 O(n)
查找/修改:给定一个下标进行查找 O(1)
适合经常进行查找或者修改的时候,使用顺序表好一点
频繁的插入和删除 不适合 因为每次都要移动数据
【插入扩容的话会浪费空间】
1. 1打印顺序表
1.2. 在顺序表指定位置新增元素
public class MyArrayList {
public int[] elem;
public int usedSize;
public MyArrayList(){
this.elem = new int[5];//构造方法,分配大小位5的空间
}
//打印顺序表
public void display(){
for (int i = 0; i <this.usedSize ; i++) {
System.out.print(this.elem[i]+" ");
}
System.out.println();
}
//在pos位置(指定位置)新增元素
public void add(int pos,int data){
if(pos < 0 || pos > this.usedSize){
System.out.println("pos位置不合法!");
return;
}
//如果elem满了,用扩容函数对其进行扩容
if(this.isFull()){
System.out.println("扩容了");
this.elem = Arrays.copyOf(this.elem,2*this.elem.length);
}
//挪开函数
for (int i = this.usedSize-1; i >= pos ; i--) {
this.elem[i+1] = this.elem[i];
}
this.elem[pos] = data;
this.usedSize++;
}
public boolean isFull(){
if(this.usedSize == this.elem.length){
return true;
}
return false;
}
}
调用:
public static void main(String[] args) {
MyArrayList myArrayList = new MyArrayList();//实例化有了一个顺序表
myArrayList.add(0,11);
myArrayList.add(1,12);
myArrayList.add(2,13);
myArrayList.add(3,14);
myArrayList.add(4,15);
myArrayList.add(5,16);
myArrayList.display();
}
结果:
1.3.判定是否包含某个元素
//3.判定是否包含某个元素
//首先判断是否为空
public boolean isEmpty(){
return this.usedSize == 0;
}
public boolean contains(int toFind) {
if (isEmpty()) {
System.out.println("顺序表为空!");
return false;
}
for (int i = 0; i < this.usedSize; i++) {
if (this.elem[i] == toFind) {
return true;
}
}
return false;
}
1.4. 查找某个元素对应的位置【下标】
//4.查找某个元素对应的位置【下标】 找不到返回-1
public int search(int toFind) {
if (isEmpty()) {
System.out.println("顺序表为空!");
return -1;
}
for (int i = 0; i < this.usedSize; i++) {
if (this.elem[i] == toFind) {
return i;
}
}
return -1;
}
1.5. 获取pos位置的元素
//5.获取pos位置的元素 pos != usedSize
public int getPos(int pos) {
/* if(pos <0 || pos >= usedSize){
System.out.println("pos位置不合法");
return -1;//不好的地方是pos可能真是-1
}
return this.elem[pos];
}*/
if (pos < 0 || pos >= usedSize) {
throw new ArrayIndexOutOfBoundsException("pos位置不合法");
//自定义的异常
}
return this.elem[pos];
}
1.6. 获取顺序表有效数据的长度
//6.获取顺序表有效数据的长度
public int size(){
return this.usedSize;
}
1.7. 给pos位置的元素设为value 更新
//7.给pos位置的元素设为value 更新
public void setPos(int pos,int value){
if (pos < 0 || pos >= this.usedSize) {
throw new ArrayIndexOutOfBoundsException("pos位置不合法!");
}
this.elem[pos] = value;
}
1.8. 删除第一次出现的关键字key
//8.删除第一次出现的关键字key
public void remove(int toRemove){
//首先判断是否为空
//找到要删除的元素的下标
int index = search(toRemove);
if (index == -1) {
System.out.println("没有你要删除的数字"+toRemove);
return;
}
for (int i = index; i < usedSize-1; i++) {
this.elem[i] = this.elem[i+1];
}
this.usedSize--;//有效数据-1
System.out.println("删除成功了!");
}
1.9.清空顺序表
//9.清空顺序表
public void clear(){
//this.usedSize = 0; 法一
//法二
for (int i = 0; i < this.usedSize; i++) {
this.elem[i] = 0;//把每一个元素置为0,如果是引用类型的话,要全置为null
}
this.usedSize = 0;
}
2. 链表
逻辑上是连续的,内存(物理)上不一定连续
单链表
双向链表
头结点:
- 数据域中不存放数据 / 数据中的数据没有意义
- 头结点是不动的
2.1 创建链表 遍历链表
//创建链表
class Node{
public int val;//默认值0
public Node next;//默认值NULL
public Node(int val){
this.val = val;
}
}
//创建链表
public class MyLinkedList {
public Node head;//单链表的头结点的引用
public void createLinkedList(){
Node node1 = new Node(12);//node存储的就是节点的地址
Node node2 = new Node(23);
Node node3 = new Node(34);
Node node4 = new Node(45);
node1.next = node2;//next域存储的是下一个节点的地址
node2.next = node3;
node3.next = node4;
this.head = node1;//头结点
}
//遍历链表
public void show(){
Node cur = this.head;
while (cur != null) {
System.out.print(cur.val+" ");
cur = cur.next;
}
System.out.println();
}
//调用
public static void main(String[] args) {
MyLinkedList myLinkedList = new MyLinkedList();
myLinkedList.createLinkedList();
myLinkedList.show();
}
}
2.2 头插法
//头插法 插入一个节点时,一定要先绑后面
public void addFirst(int data){
Node node = new Node(data);
node.next = head;
head = node;
}
2.3 尾插法
//尾插法
public void addLast(int data){
Node node = new Node(data);
if(this.head == null){
this.head = node;
return;
}
Node cur = this.head;
//找到尾节点
while (cur.next != null) {
cur = cur.next;
}
cur.next = node;
}
2.4 任意位置插入,第一个数据节点为0号下标
//任意位置插入
//1.index的合法判断
//2.两种特殊的情况 0 size
//3.找到index-1位置的节点 cur
//4.node.next = cur.next
// cur.next = node;
public boolean addIndex(int index,int data){
if (index < 0 || index > getSize()) {
System.out.println("index位置不合法!");
return false;
}
if (index == 0) {
addFirst(data);
return true;
}
if (index == getSize()) {
addLast(data);
return true;
}
Node node = new Node(data);
Node cur = findIndexSubOne(index);
node.next = cur.next;
cur.next = node;
return true;
}
private Node findIndexSubOne(int index){
Node cur = this.head;
while (index-1 != 0) {
cur = cur.next;
index--;
}
return cur;
}
2.5 删除第一次出现关键字为key的节点
private Node searchPrev(int key){
Node cur = this.head;
while (cur.next != null) {
if (cur.next.val == key) {
return cur;
}
}
return null;
}
public void remove(int key){
if (this.head.val == key) {
this.head = this.head.next;
return;
}
Node prev = searchPrev(key);
if(prev == null){
System.out.println("没有你要删除的节点!");
return;
}
Node del = prev.next;
prev.next = del.next;
}
2.6 删除所有值为key的列表 只遍历单链表一遍
//删除所有值为key的列表 只遍历单链表一遍
//cur当前需要删除的节点
//prev当前需要删除的节点的前驱
public void removeAllKey(int key){
if (head == null) {
System.out.println("空!");
return;
}
Node cur = this.head.next;
Node prev = this.head;
//从第二个节点开始遍历
while (cur !=null) {
if (cur.val == key) {
prev.next = cur.next;
cur = cur.next;
}else{
prev = cur;
cur = cur.next;
}
}
//头结点
if (this.head.val == key) {
this.head = this.head.next;
}
}
//清空列表
public void clear(){
this.head = null;//稍微粗暴
}