线性表包括:顺序表和单链表;顺序表是一串连着的内存空间,因此用数组来实现;单链表是分散的内存空间块,用对象来实现,一个结点是一个对象,对象里面有两个域,一个是data域,一个是nextNode域。
由于顺序表和单链表都涉及到迭代器模式,自己实现迭代器去迭代里面的数据,这里提供一个接口。
迭代器:
MyIterator类:
package cn.test.ArrayList;
public interface MyIterator<T> {
//是否有下一个
public boolean hasNext();
public T next();
public T remove();
}
顺序表:
MyArray类:
package cn.test.ArrayList;
public class MyArray<T> {
private T[] elementDatas;
private int length = 0;
public int getLength() {
return length;
}
//注意length和size是不同的
public int size(){
return elementDatas.length;
}
public MyArray() {
elementDatas = (T[]) new Object[16];
}
public MyArray(int initSize){
elementDatas = (T[]) new Object[initSize];
}
//插入数据
public boolean insert(T data){
//判断elementDatas的长度
if(length >= size()){ //拓展长度
T[] elementDatas_temp = (T[])new Object[size() * 2 + 1];
migrate(elementDatas, elementDatas_temp);
elementDatas = elementDatas_temp;
}
elementDatas[length++] = data;
return true;
}
//指定位置插入数据
public boolean insert(int index, T data){
//判断插入位置的合法性
if(index < 0 || index > length){
return false;
}
if(length >= size()){ //拓展长度
T[] elementDatas_temp = (T[])new Object[size() * 2 + 1];
migrate(elementDatas, elementDatas_temp);
elementDatas = elementDatas_temp;
}
if(index == length){
return insert(data);
}else{
for(int i = length-1; i >= index; i--){
elementDatas[i+1] = elementDatas[i];
}
elementDatas[index] = data;
length++;
return true;
}
}
//在第一个位置插入数据
public boolean insertFirst(T data){
return insert(0, data);
}
//删除指定下标数据
public T delete(int index){
T data = null;
//判断位置合法性
if(index < 0 || index >= length){
return null;
}
data = elementDatas[index];
//删除
for(int i = index; i <= length-1; i++){
elementDatas[i] = elementDatas[i+1];
}
length --;
return data;
}
//删除第一个数据
public T deleteFirst(){
return delete(0);
}
//删除最后一个数据
public T deleteLast(){
return delete(length-1);
}
//删除指定数据
public T delete(T data){
for(int i = 0; i < elementDatas.length; i++){
if(data.equals(elementDatas[i])){
return delete(i);
}
}
return null;
}
//得到指定下面的值
public T get(int index){
return elementDatas[index];
}
//得到第一个值
public T getFirst(){
return get(0);
}
//得到最后一个值
public T getLast(){
return get(length-1);
}
public MyIterator<T> iterator(){
return new MyArrayIterator();
}
private void migrate(T[] from, T[] to){
for(int i = 0; i < from.length; i++){
to[i] = from[i];
}
}
private class MyArrayIterator implements MyIterator<T>{
private int index = 0; //未来的下标
@Override
public boolean hasNext() {
if(index <= length-1){
return true;
}
return false;
}
@Override
public T next() {
return get(index++);
}
@Override
public T remove() {
return delete(index);
}
}
}
以上代码需要注意private class MyArrayIterator这个内部类,为什么设置为private,目的是不让外部访问。内部类可以访问外部类的方法,但外部类不可以直接访问内部类的方法,需要通过创建内部对象去访问。引申:(参考Thinking in java的内部类部分)
另外,如何创建泛型数组呢?我们知道private T[] ddTs = new T[12];
是不行的;有一个办法就是先创建Object数组,然后强制转换为T,如:private T[] elementDatas = (T[]) new Object[12];
测试方法如下:
TestMyArray类:
package cn.test.ArrayList;
import org.junit.Test;
public class TestMyArray {
/**
* 测试size、length
*/
@Test
public void test01(){
MyArray<Integer> myArray = new MyArray<Integer>();
myArray.insert(2);
myArray.insert(3);
System.out.println("size:" + myArray.size() + ", length" + myArray.getLength());
MyArray<Integer> myArray2 = new MyArray<Integer>(12);
System.out.println("size:" + myArray2.size());
}
/**
* 测试insert、delete、get
*/
@Test
public void test02(){
MyArray<Integer> myArray = new MyArray<Integer>(2);
System.out.println("size:"+myArray.size());
myArray.insert(1);
myArray.insert(2);
myArray.insert(3);
myArray.insert(4);
myArray.insert(2, 100);
myArray.insertFirst(200);
System.out.println("size:"+myArray.size()+" length:"+myArray.getLength());
myArray.delete((Integer)100);
System.out.println(myArray.getLength());
MyIterator<Integer> it = myArray.iterator();
while(it.hasNext()){
System.out.print(it.next()+" ");
}
}
}
以上测试方法均能得到正确的输出。
单链表:
MyOneWayLinkedList类:
package cn.test.LinkedList.OneWay;
import cn.test.ArrayList.MyIterator;
public class MyOneWayLinkedList<T> {
private Node<T> firstNode;
private int length;
public int getLength() {
return length;
}
//在第一个位置插入元素
public boolean insertFirst(T data){
Node<T> tmpNode = new Node<T>();
tmpNode.setData(data);
if(null == firstNode){
firstNode = tmpNode;
length++;
}
tmpNode.setNext(firstNode);
firstNode = tmpNode;
length++;
return true;
}
//在最后的位置添加元素
public boolean insertLast(T data){
//创建一个结点
Node<T> tmp = new Node<T>();
tmp.setData(data);
if(null == firstNode){
firstNode = tmp;
firstNode.setNext(null);
}else{
Node<T> node = firstNode;
for(int i = 0; i < length-1; i++){ //for循环中,要找到哪个位置
//就要小于哪个值
node = node.getNext();
}
//插入
node.setNext(tmp);
}
length++;
return true;
}
//根据index插入元素
public boolean insert(int index, T data){
//判断index的合法性
if(index < 0 || index > length){
return false;
}
//创建结点
Node<T> node = new Node<T>();
node.setData(data);
if(0 == index){
node.setNext(firstNode);
firstNode = node;
length++;
}else{
int tmp = 0;
Node<T> tmpNode = firstNode;
while(tmp < index - 1){
tmpNode = tmpNode.getNext();
tmp++;
}
node.setNext(tmpNode.getNext());
tmpNode.setNext(node);
length++;
}
return true;
}
//删除指定位置的结点
public T delete(int index){
if(index < 0 || index > length){
return null;
}
Node<T> tmpNode = firstNode;
Node<T> returnNode = null;
if(0 == index){
returnNode = tmpNode;
firstNode = firstNode.getNext();
}else{
int tmp = 0;
while(tmp < index - 1){ //找到删除位置
tmpNode = tmpNode.getNext();
tmp++;
}
returnNode = tmpNode.getNext();
tmpNode.setNext(tmpNode.getNext().getNext());
}
length--;
return returnNode.getData();
}
//删除第一个元素
public T deleteFirst(){
if(0 == length){
return null;
}
Node<T> retNode = firstNode;
firstNode = firstNode.getNext();
length--;
return retNode.getData();
}
//删除最后一个元素
public T deleteLast(){
if(0 == length){
return null;
}
int tmp = 0;
Node<T> tmpNode = firstNode;
while(tmp < length - 2){
tmpNode = tmpNode.getNext();
tmp++;
}
Node<T> retNode = tmpNode.getNext();
tmpNode.setNext(retNode.getNext());
length--;
return retNode.getData();
}
//删除指定元素
public boolean delete(T data){
if(0 == length){
return false;
}
if(1 == length){
if(data.equals(firstNode.getData())){
firstNode = null;
length--;
return true;
}else{
return false;
}
}
int index = 0;
Node<T> tmpNode = firstNode;
while(index < length - 1){
if(data.equals(tmpNode.getNext().getData())){
tmpNode.setNext(tmpNode.getNext().getNext());
length--;
return true;
}
}
return false;
}
//得到指定下标的值
public T get(int index){
//判断下标合法
if(index < 0 || index > length){
return null;
}
int tmp = 0;
Node<T> tmpNode = firstNode;
while(tmp < index){
tmpNode = tmpNode.getNext();
tmp++;
}
return tmpNode.getData();
}
//清空链表
public void clear(){
firstNode = null;
length = 0;
}
//获取迭代器
public MyIterator<T> iterator(){
return new MyOneWayLinkedListIterator();
}
private class MyOneWayLinkedListIterator implements MyIterator<T>{
int index = 0; //未来的下标
@Override
public boolean hasNext() {
if(index <= length - 1){ //未来的下标在合法的范围内
return true;
}
return false;
}
@Override
public T next() {
return get(index++);
}
@Override
public T remove() {
return delete(index);
}
}
}
测试方法:
TestLinkedList类:
package cn.test.LinkedList.OneWay;
import org.junit.Test;
import cn.test.ArrayList.MyIterator;
public class TestLinkedList {
@Test
public void test01(){
MyOneWayLinkedList<String> myList = new MyOneWayLinkedList<String>();
myList.insertLast("1212");
myList.insertFirst("11");
myList.insertFirst("00");
myList.insert(0, "66");
MyIterator<String> it = myList.iterator();
System.out.println(myList.getLength());
while(it.hasNext()){
System.out.print(it.next()+" ");
}
}
@Test
public void test02(){
MyOneWayLinkedList<String> myList = new MyOneWayLinkedList<String>();
System.out.println("---"+myList.getLength());
myList.insertLast("1");
myList.insertLast("2");
myList.insertLast("3");
myList.insertLast("4");
myList.insertLast("5");
myList.delete(4);
myList.clear();
System.out.println("---"+myList.getLength());
MyIterator<String> it = myList.iterator();
while(it.hasNext()){
System.out.print(it.next()+" ");
}
}
}
以上测试方法均能得到正确输出
============================
顺序表和单链表的对比:
存储分配方式:
(1)顺序表:采用一段连续的存储单元一次存储数据元素
(2)单链表:采用链式存储结构,用一组任意的存储单元存储数据元素,每个存储单元都存有下一个存储单元的地址
时间性能:
1、查找:
(1)顺序表:时间复杂度为O(1)
(2)单链表:时间复杂度为O(n)
2、插入和删除:
(1)顺序表:时间复杂度为O(n),并且需要移动大量的数据元素
(2)单链表:时间复杂度为O(1),但在找到位置的过程中也需要循环,时间复杂度为O(n)
3、空间性能
(1)顺序表:创建前需要分配好多大的存储空间,这就会导致分配空间少出现内存溢出,分配空间多内存浪费
(2)单链表:创建前不需要分配空间,个数不受限制,空间利用率高
总结:经常插入删除用单链表,经常查询用顺序表