数据结构---线性表:
线性表:
由n个数据元素构成的有序序列,逻辑表示为:a0,a1,a2,a3,.....an-1,当n=0是线性表为空表。
线性表的存储结构(用数组表示线性表):
对线性表的操作:
插入:
在线性表尾插入:直接插入
在表中插入,将要插入位置的元素及其之后的元素都向后移一位,然后在要插入的位置插入新元素
删除:
删除表尾的元素:直接删除
删除表中的元素:将要删除的元素删除,将删除元素之后的元素向前移一位。
ArrayList代码如下:
接口提供方法
package 接口;
public interface List<E> extends Iterable<E> {
// 添加
public void add(E element);
// 添加到对应角标
public void add(int index,E element);
// 删除
public void remove(E element);
// 删除对应角标处元素
public E remove(int index);
// 获取对应角标处元素
public E get(int index);
// 替换对应角标的元素
public E set(int index,E element);
// 线性表长度
public int size();
// 获取对应元素所在的角标
public int indexof(E element);
// 判断元素是否在线性表中
public boolean contains(E element);
// 判空
public boolean isEmpty();
// 清空线性表
public void clear();
}
接口方法的实现:
package 实现;
import 接口.List;
import java.util.Arrays;
import java.util.Iterator;
public class Arraylist<E> implements List<E> {
//线性表默认容量
private static int DEFAULT_CAPACITY =10;
//线性表存储容器
private E[] data;
//线性表元素有效个数,末尾添加的角标
private int size;
//创建一个默认容量的线性表
public Arraylist(){
this(DEFAULT_CAPACITY);
}
//创建一个用户指定容量的线性表
public Arraylist(int capacity){
if (capacity<0){
throw new IllegalArgumentException("capacity must >= 0");
}
data= (E[]) new Object[capacity];
size = 0;
}
//将数组转化为线性表
public Arraylist(E[] arr){
if (arr==null){
throw new IllegalArgumentException("arr is null");
}
data = (E[]) new Object[arr.length];
for (int i = 0;i < arr.length;i++){
data[i]=arr[i];
}
size=arr.length;
}
@Override
public void add(E element) {
this.add(size,element);
}
//指定角标
@Override
public void add(int index, E element) {
if (index < 0||index > size){
throw new IndexOutOfBoundsException("index out of bounds");
}
//判断线性表是否需要扩容
if(size== data.length){
resize(data.length*2);
}
for(int i = size-1; i >= index ; i--) {
data[i+1]=data[i];
}
data[index]=element;
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 remove(E element) {
//获取角标
int index=indexof(element);
//若存在删除
if (index!=-1) {
remove(index);
}
}
//删除指定角标处的元素 角标范围0-(size-1)
@Override
public E remove(int index) {
if(index<0||index>= size){
throw new IndexOutOfBoundsException("index out of bounds");
}
E ret = data[index];
for(int i = index+1;i<size;i++){
data[i-1]=data[i];
}
size--;
//判断是否需要缩容 最小容量为DEFAULT_CAPACITY
if(size == data.length/4 && data.length>DEFAULT_CAPACITY){
resize(data.length/2);
}
return ret;
}
@Override
public E get(int index) {
if(index<0||index>= size){
throw new IndexOutOfBoundsException("index out of bounds");
}
return data[index];
}
@Override
public E set(int index, E element) {
if(index<0||index>= size){
throw new IndexOutOfBoundsException("index out of bounds");
}
E ret = data[index];
data[index]=element;
return ret;
}
@Override
public int size() {
return size;
}
//获取元素角标
@Override
public int indexof(E element) {
for (int i = 0; i < size; i++) {
if (element.equals(data[i])){
return i;
}
}
return -1;
}
@Override
public boolean contains(E element) {
return indexof(element)!=-1 ;
}
@Override
public boolean isEmpty() {
return size==0;
}
@Override
public void clear() {
data= (E[]) new Object[DEFAULT_CAPACITY];
size=0;
}
@Override
public Iterator<E> iterator() {
return new ArrayListIterator();
}
class ArrayListIterator implements Iterator<E>{
private int cur = 0;
//判断之后还有元素
@Override
public boolean hasNext() {
return cur<size;
}
//后移并返回元素
@Override
public E next() {
return data[cur++];
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(String.format("ArrayList:%d/%d[",size,data.length));
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();
}
}
测试:
package 测试;
import 实现.Arraylist;
public class ArrayListTest {
public static void main(String[] args) {
Arraylist<Integer> list = new Arraylist<>();
System.out.println(list);
for (int i = 1; i < 12; i++) {
list.add(i);
}
System.out.println(list);
}
}
结果展示 :
栈(基于上面的线性表实现,调用线性表中的方法)
定义;栈是一种用于存储数据的简单数据结构,有点类似链表或者顺序表(统称线性表),栈与线性表的最大区别是数据的存取的操作,我们可以这样认为栈(Stack)是一种特殊的线性表,其插入和删除操作只允许在线性表的一端进行。
入栈:先插入的元素靠近栈底,后插入的元素靠近栈顶
出栈:将靠近栈顶的元素依次出栈。
代码实现
接口定义方法:
package 接口;
public interface Stack<E> extends Iterable<E>{
//元素个数
public int size();
//判空
public boolean isEmpty();
//压栈
public void push(E element);
//弹栈
public E pop();
//获取栈顶元素
public E peek();
//清空栈
public void clear();
}
实现接口:
package 实现;
import 接口.Stack;
import java.util.Iterator;
//借用ArrayList(自己写的)
public class ArrayStack<E> implements Stack<E> {
//栈内部由线性表实现
private Arraylist<E> list;
//创建就一个默认容量的栈
public ArrayStack(){
list = new Arraylist<>();
}
//创建一个指定容量的栈
public ArrayStack(int capaticy){
list = new Arraylist<>(capaticy);
}
//获取栈的元素个数
@Override
public int size() {
return list.size();
}
//判空
@Override
public boolean isEmpty() {
return list.isEmpty();
}
//入栈(线性表表尾添加元素)
@Override
public void push(E element) {
list.add(element);
}
//弹栈一个元素(在线性表表尾删除元素)
@Override
public E pop() {
return list.remove(list.size()-1);
}
//查看栈顶元素
@Override
public E peek() {
return list.get(list.size()-1);
}
//清空栈(线性表)
@Override
public void clear() {
list.clear();
}
//迭代
@Override
public Iterator<E> iterator() {
return list.iterator();
}
//重写toString
@Override
public String toString() {
StringBuilder sb = new StringBuilder(String.format("ArrayStack:%d/%d[",size(),list.getCapacity()));
if (isEmpty()){
sb.append(']');
}else{
for (int i = 0; i < size(); i++) {
sb.append(list.get(i));
if (i!=size()-1){
sb.append(',');
}else {
sb.append(']');
}
}
}
return sb.toString();
}
}
测试:
package 测试;
import 实现.ArrayStack;
public class StackTest {
public static void main(String[] args) {
ArrayStack<Integer> stack = new ArrayStack<>();
System.out.println(stack);
for (int i = 1; i < 12; i++) {
stack.push(i);
}
System.out.println(stack);
}
}
结果展示:
双端栈
定义:一种特殊的栈,在两端都可进行增删操作。
代码实现
package 实现;
import java.util.Arrays;
public class ArrayDoubleStack<E> {
//定义容器
private E[] data;
//左端栈顶ltop==-1
private int ltop;
//右端栈顶rtop==-1
private int rtop;
//默认容量
private static int DEFAULT_SIZE=10;
public ArrayDoubleStack(){
data = (E[]) new Object[DEFAULT_SIZE];
ltop=-1;
rtop=data.length;
}
//入栈
public void push(E element , int stackId){
if (ltop+1==rtop){
resize(data.length*2);
}
switch (stackId){
case 0://左端入栈
data[++ltop] = element;
break;
case 1://右端入栈
data[--rtop]=element;
break;
}
}
//出栈
public E pop(int stackId){
if (isEmpty(stackId)){
throw new NullPointerException("stack is null");
}
E ret = null;
switch (stackId){
case 0:
ret=data[ltop--];
break;
case 1:
ret=data[rtop++];
break;
}
//缩容
if (size(0)+size(1)==data.length/4&&data.length>DEFAULT_SIZE){
resize(data.length/2);
}
return ret;
}
//改变容量
private void resize(int newLength) {
E[] newdata = (E[]) new Object[newLength];
//左端入栈
for (int i = 0; i <= ltop; i++) {
newdata[i]=data[i];
}
//右端入栈
int index = rtop;
for (int i = newLength-size(1); i <newLength ; i++) {
newdata[i]=data[index++];
}
rtop = newLength-size(1);
data = newdata;
}
public int size(int stackId){
switch (stackId){
case 0 :
return ltop+1;
case 1:
return data.length-rtop;
}
return -1;
}
//判空
private boolean isEmpty(int stackId) {
switch (stackId){
case 0:
return ltop==-1;
case 1 :
return rtop== data.length;
}
return false;
}
public E peek(int stackId){
if (isEmpty(stackId)){
throw new NullPointerException("stack is null");
}
switch (stackId) {
case 0:
return data[ltop];
case 1:
return data[rtop];
}
return null;
}
public void clear(int stackId){
switch (stackId){
case 0:
ltop=-1;
break;
case 1:
rtop=data.length;
break;
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(String.format("ArrayDoubleStack:%d/%d\n",size(0)+size(1),data.length));
if (isEmpty(0)){
sb.append("leftStack:[]");
}else{
sb.append("leftStack:[");
for (int i = 0; i <= ltop; i++) {
sb.append(data[i]);
if (i==ltop){
sb.append(']');
sb.append('\n');
}else{
sb.append(',');
}
}
}
if (isEmpty(1)){
sb.append("rightStack:[]");
}else{
sb.append("rightStack:[");
for (int i = data.length-1; i >= rtop; i--) {
sb.append(data[i]);
if (i==rtop){
sb.append(']');
sb.append('\n');
}else{
sb.append(',');
}
}
}
return sb.toString();
}
}
测试
package 测试;
import 实现.ArrayDoubleStack;
public class ArrayDoubleStackTest {
public static void main(String[] args) {
ArrayDoubleStack<Integer> stack = new ArrayDoubleStack<>();
System.out.println(stack);
for (int i = 1; i <= 6; i++) {
stack.push(i,0);
}
System.out.println(stack);
for (int i = 7; i <= 12; i++) {
stack.push(i,1);
}
System.out.println(stack);
}
}
结果展示
队列
定义:只允许在一端进行插入操作,而在另一端进行删除操作的线性表。队列是一种先进先出(First In First Out)的线性表,简称FIFO。允许插入的一端称为队尾,允许删除的一端称为队头
代码实现
接口定义方法
package 接口;
public interface Queue<E> extends Iterable<E> {
//队列长度
public int size();
//判空
public boolean isEmpty();
//入队
public void offer(E element);
//出队
public E pop(E element);
//获取队顶元素
public E element();
//清空
public void clear();
}
实现接口方法
package 实现;
import 接口.Queue;
import java.util.Iterator;
public class ArrayQueue<E> implements Queue<E> {
private Arraylist list;
public ArrayQueue(){
this(10);
}
public ArrayQueue(int capacity){
list= new Arraylist<>(capacity);
}
//有效元素个数
@Override
public int size() {
return list.size();
}
//判空
@Override
public boolean isEmpty() {
return list.isEmpty();
}
//入队
@Override
public void offer(E element) {
list.add(element);
}
//出队
@Override
public E pop(E element) {
return (E) list.remove(0);
}
//获取队首元素
@Override
public E element() {
return (E) list.get(0);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(String.format("ArrayQueen:%d/%d[",size(),list.getCapacity()));
if(isEmpty()){
sb.append(']');
}else{
for (int i = 0; i < size(); i++) {
sb.append(list.get(i));
if (i!=size()-1){
sb.append(',');
}else{
sb.append(']');
}
}
}
return sb.toString();
}
//清空
@Override
public void clear() {
list.clear();
}
//迭代
@Override
public Iterator<E> iterator() {
return list.iterator();
}
}
测试
package 测试;
import 实现.ArrayQueue;
public class ArrayQueueTest {
public static void main(String[] args) {
ArrayQueue<Integer> queen = new ArrayQueue<>();
System.out.println(queen);
for (int i = 1; i <=12 ; i++) {
queen.offer(i);
}
System.out.println(queen);
}
}
结果展示
队列---循环队列
定义:为充分利用向量空间,克服"假溢出"现象的方法是:将向量空间想象为一个首尾相接的圆环,并称这种向量为循环向量。存储在其中的队列
初始队列形状:定义两个指针
对队列进行插入操作:
当rear指向最后一个位置时,再添加元素:
初始:
插入后:
注:
- 判空:判断空间是否没有元素,front==rear且size=0;
- 判满:判断空间中的元素是否已满,(rear+1)%空间的长度
- 实际存储最大元素空间是空间的长度-1;
代码实现
实现
package 实现;
import 接口.Queen;
import java.util.Iterator;
public class ArrayLoopQueue<E> implements Queen<E> {
//容器
private E[] data;
//队首指针 front
private int front;
//队尾指针 rear 对空:rear==front 对满:(rear+1)%n=front
private int rear;
//有效元素个数
private int size;
//定义默认容量10,实际容量为9
private static int DEFAULT_SIZE=10;
public ArrayLoopQueue(){
this(DEFAULT_SIZE);
}
public ArrayLoopQueue(int capacity){
data= (E[]) new Object[capacity+1];
front=0;
rear=0;
size=0;
}
//长度
@Override
public int size() {
return size;
}
//判空
@Override
public boolean isEmpty() {
return size==0&&front==rear;
}
//添加
@Override
public void offer(E element) {
//扩容
if((rear+1)% data.length==front){
resize(data.length * 2 - 1);
}
data[rear]=element;
rear=(rear + 1)%data.length;
size++;
}
//出队
@Override
public E pop(E element) {
if(isEmpty()){
throw new NullPointerException("queen is null");
}
E ret = data[front];
front=(front+1)% data.length;
size--;
//缩容
if (size== (data.length-1)/4&&data.length-1>DEFAULT_SIZE){
resize(data.length/2+1);
}
return ret;
}
private void resize(int newLength) {
E[] newData= (E[]) new Object[newLength];
int index = 0;
for (int i = front; i!=rear; i=(i+1)% data.length) {
newData[index++] = data[i];
}
front=0;
rear=index;
data=newData;
}
@Override
public E element() {
if (isEmpty()){
throw new NullPointerException("data is null");
}
return data[front];
}
@Override
public void clear() {
data= (E[]) new Object[DEFAULT_SIZE+1];
front=0;
rear=0;
size=0;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(String.format("ArrayLoopQueen:[ %d/%d ", size, data.length - 1));
if (isEmpty()) {
sb.append(']');
} else {
for (int i = front; i != rear; i = (i + 1) % data.length) {
sb.append(data[i]);
if ((i + 1) % data.length == rear) {
sb.append(']');
} else {
sb.append(',');
}
}
}
return sb.toString();
}
@Override
public Iterator<E> iterator() {
return null;
}
class ArrayLoopQueenTterator implements Iterator<E>{
private int cur;
@Override
public boolean hasNext() {
return cur != rear;
}
@Override
public E next() {
E ret = data[cur];
cur = (cur+1)%data.length;
return ret;
}
}
}
测试
package 测试;
import 实现.ArrayLoopQueue;
public class ArrayLoopQueueTest {
public static void main(String[] args) {
ArrayLoopQueue<Integer> queen = new ArrayLoopQueue<Integer>();
System.out.println(queen);
for (int i = 1; i <= 12; i++) {
queen.offer(i);
}
System.out.println(queen);
}
}
结果展示
队列---双端队列
定义:其两端都可以入列和出列的数据结构,队列后面(rear)可以加入和移出数据,队列前面(front)可以加入和移出数据
代码实现:
接口定义方法
package 接口;
public interface Dqueue<E> extends Queen<E> {
//队首添加元素
public void addfirst(E element);
//队尾添加元素
public void addlast(E element);
//队首删除元素
public E removefirst();
//队尾删除元素
public E removelast();
//获取队首元素
public E getfirst();
//获取队尾元素
public E getlast();
//获取有效元素个数
public int size();
//判空
public boolean isEmpty();
//清空
public void clear();
}
实现接口方法
package 实现;
import 接口.Dqueue;
import 接口.Stack;
import java.util.Iterator;
public class ArrayDqueue<E> implements Dqueue<E>, Stack<E> {
//容器
private E[] data;
//左指针
private int front;
//右指针
private int rear;
//有效长度
private int size;
//默认容量
private static int DEFAUL_SIZE=10;
public ArrayDqueue(){
this(DEFAUL_SIZE);
}
public ArrayDqueue(int capacity){
data= (E[]) new Object[capacity+1];
front=0;
rear=0;
size=0;
}
//队首添加
@Override
public void addfirst(E element) {
if (isFull()){
resize(data.length*2-1);
}
front=(front-1+ data.length)% data.length;
data[front]=element;
size++;
}
//扩容
private void resize(int newLength) {
E[] newData= (E[]) new Object[newLength];
int index = 0;
for (int i = front; i!=rear; i=(i+1)% data.length) {
newData[index++] = data[i];
}
front=0;
rear=index;
data=newData;
}
//判满
private boolean isFull() {
return (rear+1)% data.length==front;
}
//队尾添加
@Override
public void addlast(E element) {
//判断是否需要扩容
if (isFull()){
resize(data.length*2-1);
}
data[rear]=element;
rear=(rear+1)% data.length;
size++;
}
//队首删除
@Override
public E removefirst() {
//判空
if (isEmpty()){
throw new NullPointerException("queen is null");
}
E ret = data[front];
front=(front+1)% data.length;
size--;
//判断是否要缩容
if(isSmall()){
resize(data.length/2+1);
}
return ret;
}
private boolean isSmall() {
return size== (data.length-1)/4 && data.length-1>DEFAUL_SIZE;
}
//队尾删除
@Override
public E removelast() {
//判空
if (isEmpty()){
throw new NullPointerException("queen is null");
}
E ret = data[(rear-1+ data.length)% data.length];
rear=(rear-1+ data.length)% data.length;
size--;
return ret;
}
//获取队首元素
@Override
public E getfirst() {
return data[front];
}
@Override
public E getlast() {
return data[(rear-1+ data.length)% data.length];
}
@Override
public int size() {
return size;
}
@Override
public boolean isEmpty() {
return size==0 && front==rear;
}
//入栈 front 栈底 rear 栈顶
@Override
public void push(E element) {
addlast(element);
}
@Override
public E pop() {
return removelast();
}
@Override
public E peek() {
return getlast();
}
//front 队首 rear 队尾
@Override
public void offer(E element) {
addlast(element);
}
@Override
public E pop(E element) {
return removefirst();
}
@Override
public E element() {
return getfirst();
}
@Override
public void clear() {
data= (E[]) new Object[DEFAUL_SIZE+1];
front=0;
rear=0;
size=0;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(String.format("ArrayDqueen:[ %d/%d ", size, data.length - 1));
if (isEmpty()) {
sb.append(']');
} else {
for (int i = front; i != rear; i = (i + 1) % data.length) {
sb.append(data[i]);
if ((i + 1) % data.length == rear) {
sb.append(']');
} else {
sb.append(',');
}
}
}
return sb.toString();
}
@Override
public Iterator<E> iterator() {
return null;
}
//迭代放向 front->rear
class ArrayLoopQueenTterator implements Iterator<E>{
private int cur;
@Override
public boolean hasNext() {
return cur != rear;
}
@Override
public E next() {
E ret = data[cur];
cur = (cur+1)%data.length;
return ret;
}
}
}
测试:
package 测试;
import 实现.ArrayDqueue;
public class ArrayDqueueTest {
public static void main(String[] args) {
ArrayDqueue<Integer> dqueen = new ArrayDqueue<Integer>();
System.out.println(dqueen);
dqueen.addlast(1);
dqueen.addfirst(2);
System.out.println(dqueen);
}
}
结果展示