线性表:
概念:零个或多个数据元素的有限集合;
线性表必须是一个序列,,也就是说元素之间是有顺序的,如果元素存在多个,则第一个元素无前驱,最后一个元素无后继,其余每一个元素都有各自唯一的前驱和后继;
当线性表内的元素为空时,这个表就是一个空表;
下标的位置是元素在线性表的位序;
线性表的存储结构:
用一段连续的存储单元依次存储线性表的数据元素;
在任意时刻。线性表的长度应该小于等于数组的长度;
地址计算:
第i个数据元素的ai的存储位置可以由a1推导:
LOC(ai) = LOC(a1) + (i-1)*C
线性表插入思路:
1.如果插入的位置不合适(插入的位置不能小于0,最大位置不能超过数组的长度),应该抛出异常;
2.线性表的长度要小于等于数组的长度;
3.从最后一个元素向前遍历,依次后移一位;
4.将要插入的元素插入到对应的位置;
Java实现(我直接正着后移了):
package com.lzl.linerTable;
import java.util.Arrays;
/**
* 向数组内插入元素,时间复杂度 O(n) 空间复杂度 O(1)
*
*/
public class InsertArray {
public static void main(String[] args) {
int[] arr = new int[]{1,2,5,7,4,6,8,9,12,34,56};
int num = 33;
int[] arr1 = new int[arr.length+1];
for (int i = 0; i < arr.length; i++) {
arr1[i] = arr[i];
}
for (int i = 2; i < arr1.length-1 ; i++) {
if (i == 2){
arr1[i+1] = arr1[i];
arr1[i] = num;
}else {
arr1[i + 1] = arr[i];
}
}
System.out.println(Arrays.toString(arr1));
}
}
删除算法的思路:
1.如果删除的位置不合理,抛出异常
2.取出删除元素;
3.从删除位置开始遍历到最后一个位置,分别将它们向前移一位
4.表长度-1
Java实现数组删除:
/**
* 数组删除算法,时间复杂度: O(n),空间复杂度:O(1)
* @param arr
* @param index
* @return
*/
public static int deleteArr(int[] arr,int index){
int result = 0;
if (index<0 || index>arr.length){
return -1;
}
result = arr[index];
for (int i = index ; i < arr.length - 1; i++) {
arr[i] = arr[i+1];
}
arr = new int[arr.length-1];
return result;
}
顺序表的优势:
无需为表示表中的逻辑关系额外增加存储空间;
可以快速的取表中的某一位置的元素
缺点:
插入和删除操作需要大量的移动元素;
当线性表变化较大时,难以确定其容量;
会造成空间的碎片化
线性表的链式存储结构:
概念:用一组任意的存储结构单元存储存储线性表的数据元素;
链式结构的每一个元素称为节点,它存储两个域;数据存储的域称为数据域,将存储后继节点的位置的域称为指针域;
只包含一个指针域的链表称为单链表;
头指针和尾指针:
我们把一个节点的存储位置称为头指针,每一个的后继节点的位置就是上一个节点的指针;
最后一个节点的指针通常为空
有时会在第一个节点前创建一个头结点节点,头结点的数据域可以没有数据,也可以存储链表的长度等信息,头指针指向存储区的第一个节点;
Java实现一个单链表:
创建一个节点:
package com.lzl.linerTable;
public class Node<E> {
//节点数据
public E data;
//节点的后继
public Node<E> nextNode;
public Node(E data) {
this.data = data;
}
}
创建一个链表:
public class TestLinkedList<E> {
//数组长度
private int size = 0;
//下标位置
private int index = 0;
//头结点
private Node<E> head;
//尾结点
private Node<E> end;
public TestLinkedList() {
this.head = null;
}
}
增加节点:
/**
* 添加元素
* 算法思路:设置一个boolean值记录运行结果;
* 1. 创建一个新的节点将data通过构造方法注入;
* 2. 如果尾结点 是空的,说明链表内没有节点,这个节点就是唯一节点,将下标位置+1;
* 3. 如果有节点,将这个节点加到尾结点的后面,并把这个节点作为新的尾结点,将下标+1;
* 4. 将链表的长度+1,将下标指针指回0位置;
* @param data
* @return
*/
public boolean add(E data){
boolean flag = false;
Node<E> node = new Node<>(data);
if (end == null){
head = end = node;
index++;
flag = true;
}else {
end.nextNode = node;
end = node;
index++;
flag = true;
}
size++;
index = 0;
return flag;
}
获取节点数据:
/**
* 获取下标节点数据
* 1. 首先判断请求的下标符不符合链表长度,如果不符合就抛出异常;
* 2. 定义一个当前节点currentNode,再定义一个当前节点的上一个节点preNode;
* 3. 如果当前的index和数组下标的index不相等,就执行while循环,将当前节点指向后继节点
* @param index
* @return
*/
public E get(int index){
if (this.size == 0){
return null;
}
if (index > this.size || index < 0){
throw new ArrayIndexOutOfBoundsException();
}
Node<E> currentNode = head;
while (this.index != index ){
currentNode = currentNode.nextNode;
this.index ++;
}
this.index = 0;
return currentNode.data;
}
删除节点:
/**
* 删除数据元素
* 1. 先判断元素是否合法;
* 2. 判断是否为头结点,如果为头结点,就直接将头结点变成头结点的下一个节点;
* 3. 判断当前节点是否为空,不为空进入循环,判断如果等于index,则将前一个节点的后继指向下一个节点的后继,链表长度-1;
* 4. 如果不是index节点,就将前一个节点指向当前节点,当前节点指向后一个节点,让位置+1;
* @param index
* @return
*/
public boolean delete(int index){
boolean flag = false;
if (index > this.size || index < 0){
throw new ArrayIndexOutOfBoundsException();
}
if (head == null){
return flag;
}
if (index == 1){
head = head.nextNode;
size --;
return true;
}
Node<E> currentNode = head.nextNode;
Node<E> preNode = head;
int i = 2;
while (currentNode != null){
if (i == index){
preNode.nextNode = currentNode.nextNode;
size --;
break;
}else {
preNode = currentNode;
currentNode = currentNode.nextNode;
i++;
}
}
return flag;
}
打印链表:
/**
* 打印链表数据元素
* 1. 创建一个节点作为当前节点;
* 2. 判断当前节点是否为空,不为空就打印节点内的数据,将数据进行拼接;
*/
public void printList(){
Node<E> currentNode = head;
System.out.print("[ ");
while (currentNode != null){
if (currentNode.nextNode != null) {
System.out.print(currentNode.data + ",");
}else {
System.out.print(currentNode.data );
}
currentNode = currentNode.nextNode;
}
System.out.println(" ] ");
}
返回链表长度:
/**
* 返回当前链表长度
* @return
*/
public int size(){
return this.size;
}
测试:
public static void main(String[] args) {
TestLinkedList<Integer> linkedList = new TestLinkedList<Integer>();
linkedList.add(1);
linkedList.add(1);
linkedList.add(1);
linkedList.add(2);
linkedList.add(3);
linkedList.add(55);
System.out.println(linkedList.size);
Integer integer = linkedList.get(4);
System.out.println(integer);
linkedList.delete(1);
linkedList.printList();
}
结果: