数组:
1.数组的存储内存地址是连续的
2.数据类型和长度是确定的
3.数组的每一个存储位置都有一个编号,叫做数组的索引或者下标,数组的下标是从0开始的连续整数
4.数组最大下标=数组长度-1
优点:数据是存放在一块连续的内存地址上查找效率高
缺点:在改变数据个数的时候[增加、插入、删除]的效率比较低
int [] a = new int [2] ; //将10存放到数组下标为0的位置 a [0] = 10; //将20存放到数组下标为1的位置 a [1] = 20;
int [] a = {10,20}; //获得数组中下标为1位置中的数 int t = a [1] ;
int [] a = {10,20,30,40}; //获得数组的长度 int len = a.length;
链式列表:
[链表] 数据在内存中可以在任意位置,通过引用来关联数据。链表的大小可以按需要伸缩,是一种动态结构
优点:插入、删除灵活,结点可以插入到链表的任何位置都可以,而且不必移动结点中的指针。
缺点:在查找结点的时候,只能从第一个结点开始顺着链表逐个查找。
数组的使用场景:
/**
* 自定义长度可变的数组[泛型]
*
* @author Administrator
*
*/
public class MyArray<E>{
// 定义一个长度为0的初始数组
private Object[] src = new Object[0];
/**
* 增加数据
* @param s 要增加的数据
*/
public void add(E s) {
// 定义一个新数组长度是源数组长度+1
Object[] dest = new Object[src.length + 1];
// 将原数组的数据拷贝到新数组中
System.arraycopy(src, 0, dest, 0, src.length);
// 将新数据放到新数组的最后一个位置
dest[dest.length - 1] = s;
// 将原数组指向新数组
src = dest;
}
/**
* 取出数据
* @param index 要取出的数据的下标
*/
public E get(int index) {
Object s = src[index];
return (E) s;
}
/**
* 根据下标删除数据
* @param index 要删除的数据的下标
*/
public void delete(int index) {
//定义一个新的数组长度是源数组的长度-1
Object s [] = new Object [src.length-1];
//将下标小于index的拷贝到新数组对应的小标位置
System.arraycopy(src, 0, s, 0, index);
//将下标大于index的拷贝到新数组下标的位置为原数组的下标位置-1
System.arraycopy(src, index+1, s, index, src.length-index-1);
//将src指向新数组
src = s;
}
/**
* 删除指定的数据
* @param s 要删除的数据,如果有重复的数据,就删除下标最小的
*/
public void delete(E s) {
int t = -1;
for(int i=0; i<src.length; i++){
if(src[i].equals(s)){
t = i;
break;
}
}
//如果s在数组中出现过,t一定会大于等于0
if(t>=0){
delete(t);
}
}
/**
* 将数据插入到指定位置
* @param index 要插入的位置
* @param s 要插入的数据
*/
public void insert(int index, E s){
//定义一个新数组长度是原数组长度+1
Object str [] = new Object [src.length+1];
//将新数据放到新数组的指定位置
str [index] = s;
//将下标小于index的拷贝到新数组对应的下标位置
System.arraycopy(src, 0, str, 0,index);
//将下标大于等于index的拷贝到新数组下标+1的位置
System.arraycopy(src, index, str, index+1, src.length-index);
//将src指向新数组
src = str;
}
/**
* 修改数据
* @param index 要修改的数据的下标
* @param s 修改后的数据
*/
public void update(int index, E s) {
src[index] = s;
}
/**
* 获得数据个数
*/
public int size() {
return src.length;
}
}
public class Main {
public static void main(String[] args) {
MyArray2<Integer> m = new MyArray2<Integer>();
//增加数据
m.add(100);
m.add(200);
m.add(300);
m.add(400);
m.add(500);
m.add(600);
//按下标删除数据
m.delete(0);
//按内容删除数据
m.delete(new Integer(200));
//按下标修改数据
m.update(3, 400);
//按下标插入内容
m.insert(2, 300);
for(int i=0; i<m.size();i++){
int t = m.get(i);
System.err.println(t);
//输出结果:
//300
//400
//300
//500
//400
}
}
}
链表的使用场景:
/**
* 链式实现栈
* 单项链表
*/
public class zhan <E>{
//定义一个空链表
private Node<E> hean= null;
//结点个数
private int num = 0;
/**
* 将数据压入栈
* @param e 要压入的数据
*/
public void put(E e){
// 根据数据创建一个结点类
Node<E> node = new Node<E> (e);
// 如果链表中没有结点
if(hean==null){
hean = node;
}else{
// 将新的结点作为链表的头结点
node.next = hean;
// 将head执行新的头结点
hean = node;
}
num++;
}
/**
* 弹出栈顶的数据
* @return 返回弹出的数据
*/
public E poll(){
if(hean!=null){
// 定义一个变量指向原来的头结点
Node<E> n =hean;
//将hean的指向下一个结点
hean = hean.next;
// 将原来头结点的next指向null
n.next = null;
num--;
return n.data;
}
return null;
}
/**
* 返回栈的长度
* @return 数据的个数
*/
public int size() {
return num;
}
/**
* 判断栈是不是一个空栈
* @return 如果没有数据,就返回true,否则false
*/
public boolean isEmpty() {
return num == 0;
}
//递归
public void printData(Node<E> node){
if(node!=null){
System.out.println(node.data);
node = node.next;
printData(node);
}
}
}
//单向链表结点类
class Node<E>{
//结点的数据
E data;
//对下一个结点的引用
Node<E> next;
//创建结点对象的时候必须指定数据
public Node(E e){
this.data = e;
}
}
/**
* 链式实现栈的主类
* @author Administrator
*
*/
public class ZhanMain {
public static void main(String[] args) {
// 创建栈对象
zhan<String> z = new zhan<String>();
// 将数据压入栈
z.put("AA");
z.put("BB");
z.put("CC");
// 从栈中弹出数据
while (!z.isEmpty()) {
String s = z.poll();
System.out.println(s);
//输出结果:
//CC
//BB
//AA
}
}
}