数组
1.数组是有限个相同类型的变量所组成的有序集合,数组中每一个变量称为元素.特点是在内存中的顺序存储.
2.Java内置数组的特点:
(1)长度一旦确定就不能更改(扩容和缩容都要重新创建一个新的数组,把元素放入其中)
(2)只能存储同一类型的数据
(3)数组中的每个存储空间大小一致且地址连续
(4)提供角标的方式访问数组
线性表
线性表中元素之间关系是一对一的关系(除了第一个和最后一个元素外,其他元素都是首尾相接的),本质为数据结构中的逻辑结构.
1.线性表的顺序存储结构(用数组存储)
(1)定义:用一段地址连续的存储单元依次存储线性表的数据元素.
(2)操作:
增:void add(int index,E e)//在线性表中的index角标处插入E类型的元素e
删:E remove(int index)//删除并返回线性表中角标index处的元素.
查:boolean contains(E e)//判断线性表中是否包含元素e
int find(E e)//查找元素e的角标
改:void set(int index,E e )//修改线性表角标index处的元素为新元素e.
(3)代码:
package DS01.动态数组;
/*
定义线性表的接口List
List支持泛型E
该List线性表中所存储的具体数据类型由外界决定
*/
public interface List<E> extends Iterable<E>{
int getSize();//获取线性表中元素的有效个数
boolean isEmpty();//判断线性表是否为空表
void add(int index,E e); //在线性表指定的index角标处插入元素e
void addFirst(E e);//在线性表的表头处插入元素e
void addLast(E e);//在线性表的表位处插入元素e
E get(int index); //获取线性表中指定角标index处的元素
E getFirst();//获取表头元素
E getLast();//获取表尾元素
void set(int index,E e);//修改线性表中角标index处的元素为新元素e
boolean contains(E e);//判断线性表中是否包含元素e
int find(E e);//查找元素e的角标(从左到右默认第一个出现的元素角标)
E remove(int index);//删除并返回线性表中指定角标index处的元素
E removeFirst(); //删除并返回表头元素
E removeLast();//删除并返回表尾元素
void removeElement(E e);//删除指定元素e
void clear();//清空线性表
}
package DS01.动态数组;
import java.util.Iterator;
/*
创建线性表List的顺序存储结构实现类ArrayList
*/
public class ArrayList<E> implements List<E>{
//创建E类型的一维数组
private E[] data;
//维护元素个数
private int size;
//默认最大容量为10
private static int DEFAULT_CAPACITY=10;
//创建一个默认大小的顺序表
public ArrayList(){
this(DEFAULT_CAPACITY);
}
//创建一个容量由用户指定的顺序表
public ArrayList(int capacity){
if(capacity<=0){
throw new IllegalArgumentException("容量>0:"+capacity);
}
data=(E[])(new Object[capacity]);
size=0;
}
//用户传入一个数组 将该数组封装成一个顺序表
public ArrayList(E[] data){
if(data==null){
throw new IllegalArgumentException("数组不能为空");
}
this.data=(E[])(new Object[data.length]);
for (int i = 0; i <data.length ; i++) {
this.data[i]=data[i];
}
size=data.length;
}
@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 IllegalArgumentException("角标越界");
}
if(size==data.length){
//扩容
resize(data.length*2);
}
for (int i = size; i >index ; i--) {
data[i]=data[i-1];
}
data[index]=e;
size++;
}
private void resize(int newLength) {
E[] newData=(E[])(new Object[newLength]);
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(isEmpty()){
throw new IllegalArgumentException("线性表为空");
}
if(index<0||index>=size){
throw new IllegalArgumentException("角标越界");
}
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(isEmpty()){
throw new IllegalArgumentException("线性表为空");
}
if(index<0||index>=size){
throw new IllegalArgumentException("角标越界");
}
data[index]=e;
}
@Override
public boolean contains(E e) {
return find(e)!=-1;
}
@Override
public int find(E e) {
if(isEmpty()){
throw new IllegalArgumentException("线性表为空");
}
for (int i = 0; i < size; i++) {
if(data[i].equals(e)){
return i;
}
}
return -1;
}
@Override
public E remove(int index) {
if(isEmpty()){
throw new IllegalArgumentException("线性表为空");
}
if(index<0||index>=size){
throw new IllegalArgumentException("角标越界");
}
E ret=data[index];
for(int i=index+1;i<size;i++){
data[i-1]=data[i];
}
size--;
if(size<=data.length/4&&data.length/2>=10){
resize(data.length/2);
}
return ret;
}
@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){
remove(index);
}else{
throw new IllegalArgumentException("元素不存在");
}
}
@Override
public void clear() {
size=0;
data=(E[])(new Object[DEFAULT_CAPACITY]);
}
public int getCapacity(){
return data.length;
}
@Override
public String toString() {
StringBuilder sb=new StringBuilder();
sb.append(String.format("ArrayList: %d/%d \n",size,data.length));
sb.append('[');
if(isEmpty()){
sb.append(']');
}else{
for (int i = 0; i < size; i++) {
sb.append(data[i]);
if(i == size - 1){
sb.append(']');
}else{
sb.append(',');
}
}
}
return sb.toString();
}
//返回当前数据结构的一个迭代器对象
//迭代器用于在没有角标支持的环境下遍历元素
@Override
public Iterator<E> iterator() {
return new ArrayListIterator();
}
private class ArrayListIterator implements Iterator{
private int index=-1;
@Override
public boolean hasNext() {
return index<size-1;
}
@Override
public E next() {
index++;
return data[index];
}
}
}
测试:
package DS01.动态数组;
public class TestArrayList {
ArrayList<String> arrayList = new ArrayList<>();
arrayList.addLast("3");
arrayList.addLast("3");
arrayList.add(0,"1");
arrayList.add(2,"2");
System.out.println(arrayList);
System.out.println(arrayList.remove(2));
System.out.println(arrayList);
}
结果:
ArrayList: 4/10
[1,3,2,3]
2
ArrayList: 3/10
[1,3,3]
2.线性表链式存储(用链表存储)
(1)定义:为了表示每个数据元素ai与其直接后继数据元素ai+1之间的逻辑关系,对数据元素ai来说,除了存储其本身的信息之外,还需存储一个指示其直接后继的信息(即直接后继的存储位置).我们把存储数据元素信息的域称为数据域,把存储直接后继位置的域称为指针域.指针域中存储的信息称做指针或链.这两部分信息组成数据元素ai的存储映像,称为结点(Node).n个结点(a的存储映像)链结成一个链表,即为线性表(a1,a2,…,an)的链式存储结构,因为此链表的每个结点中只包含一个指针域,所以叫做单链表.
(2)头结点与头指针
头结点是指链表的第一个节点,有真实节点和虚拟头结点两种.
真实头结点:第一个节点存储数据
虚拟头结点:第一个节点不存储数据
头指针:一个引用变量,存储头结点地址的指针
尾指针:一个引用变量,存储最后一个节点地址的指针
(3)操作:
增:void add(int index,E e)//在线性表中的index角标处插入E类型的元素e
删:E remove(int index)//删除并返回线性表中角标index处的元素.
查:boolean contains(E e)//判断线性表中是否包含元素e
int find(E e)//查找元素e的角标
改:void set(int index,E e )//修改线性表角标index处的元素为新元素e.
(4)代码:
package DS01.动态数组;
/*
定义线性表的接口List
List支持泛型E
该List线性表中所存储的具体数据类型由外界决定
*/
public interface List<E> extends Iterable<E>{
int getSize();//获取线性表中元素的有效个数
boolean isEmpty();//判断线性表是否为空表
void add(int index,E e); //在线性表指定的index角标处插入元素e
void addFirst(E e);//在线性表的表头处插入元素e
void addLast(E e);//在线性表的表位处插入元素e
E get(int index); //获取线性表中指定角标index处的元素
E getFirst();//获取表头元素
E getLast();//获取表尾元素
void set(int index,E e);//修改线性表中角标index处的元素为新元素e
boolean contains(E e);//判断线性表中是否包含元素e
int find(E e);//查找元素e的角标(从左到右默认第一个出现的元素角标)
E remove(int index);//删除并返回线性表中指定角标index处的元素
E removeFirst(); //删除并返回表头元素
E removeLast();//删除并返回表尾元素
void removeElement(E e);//删除指定元素e
void clear();//清空线性表
}
package Ds02.动态链表;
import java.util.Iterator;
public class LinkedList<E> implements List<E> {
private Node head; //链表的头指针(虚头结点)
private Node rear; //链表的尾指针
private int size; //链表的元素个数(结点个数)
public LinkedList(){
head=new Node();
rear=head;
}
private class Node{
E data; //数据域
Node next; //指针域
Node(){
this(null,null);
}
Node(E data,Node next){
this.data=data;
this.next=next;
}
@Override
public String toString() {
return data.toString();
}
}
@Override
public int getSize() {
return size;
}
@Override
public boolean isEmpty() {
return size==0&&head==rear;
}
@Override
public void add(int index, E e) {
if(index<0||index>size){
throw new IllegalArgumentException("角标越界");
}
Node n=new Node();
n.data=e;
if(isEmpty()){ //空表状态 特殊处理
head.next=n;
rear=n;
}else if(index==0){ //头插法
n.next=head.next;
head.next=n;
}else if(index==size){ //尾插法
rear.next=n;
rear=n;
}else{ //中间插
Node p=head;
for(int i=0;i<index;i++){
p=p.next;
}
n.next=p.next;
p.next=n;
}
size++;
}
@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(isEmpty()){
throw new IllegalArgumentException("空表");
}
if(index<0||index>=size){
throw new IllegalArgumentException("角标越界");
}
if(index==0){
return head.next.data;
}else if(index==size-1){
return rear.data;
}else{
Node p=head;
for(int i=0;i<=index;i++){
p=p.next;
}
return p.data;
}
}
@Override
public E getFirst() {
return get(0);
}
@Override
public E getLast() {
return get(size-1);
}
@Override
public void set(int index, E e) {
if(isEmpty()){
throw new IllegalArgumentException("空表");
}
if(index<0||index>=size){
throw new IllegalArgumentException("角标越界");
}
Node p=head;
for(int i=0;i<=index;i++){
p=p.next;
}
p.data=e;
}
@Override
public boolean contains(E e) {
return find(e)!=-1;
}
@Override
public int find(E e) {
Node p=head;
for(int i=0;i<size;i++){
p=p.next;
if(p.data.equals(e)){
return i;
}
}
return -1;
}
@Override
public E remove(int index) {
if(isEmpty()){
throw new IllegalArgumentException("表空");
}
if(index<0||index>=size){
throw new IllegalArgumentException("角标越界");
}
E ret=null;
if(size==1){
ret=rear.data;
head.next=null;
rear=head;
}else if(index==0){
Node del=head.next;
ret=del.data;
head.next=del.next;
del.next=null;
del=null;
}else if(index==size-1){
Node p=head;
while(true){
if(p.next!=rear){
p=p.next;
}else{
break;
}
}
ret=p.next.data;
p.next=null;
rear=p;
}else{
Node p=head;
for(int i=0;i<index;i++){
p=p.next;
}
Node del=p.next;
ret=del.data;
p.next=del.next;
del.next=null;
del=null; // 释放空间 free(del)
}
size--;
return ret;
}
@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){
remove(index);
}else{
throw new IllegalArgumentException("找不到!");
}
}
@Override
public void clear() {
head.next=null;
rear=head;
size=0;
}
@Override
public String toString() {
StringBuilder sb=new StringBuilder();
sb.append("LinkedList : "+size+"\n");
sb.append('[');
if(isEmpty()){
sb.append(']');
}else{
Node p=head;
while(true){
if(p.next!=rear){
p=p.next;
sb.append(p.data);
sb.append(',');
}else{
sb.append(rear.data);
sb.append(']');
break;
}
}
}
return sb.toString();
}
@Override
public Iterator<E> iterator() {
return new LinkedListIterator();
}
public class LinkedListIterator implements Iterator<E>{
private Node p=head;
@Override
public boolean hasNext() {
return p.next!=null;
}
@Override
public E next() {
p=p.next;
return p.data;
}
}
}
测试:
package Ds02.动态链表;
import java.util.*;
public class TestLinkedList {
public static void main(String[] args) {
LinkedList<Integer> list=new LinkedList<>();
list.addLast(2);
System.out.println(list);
list.addLast(3);
System.out.println(list);
list.addFirst(1);
System.out.println(list);
}
}
结果:
LinkedList : 1
[2]
LinkedList : 2
[2,3]
LinkedList : 3
[1,2,3]