Java 數組和鏈表的區別以及使用場景
科技優家 2016-12-11 17:11
數組:是將元素在內存中連續存儲的;它的優點:因為數據是連續存儲的,內存地址連續,所以在查找數據的時候效率比較高;它的缺點:在存儲之前,我們需要申請一塊連續的內存空間,並且在編譯的時候就必須確定好它的空間的大小。在運行的時候空間的大小是無法隨着你的需要進行增加和減少而改變的,當數據兩比較大的時候,有可能會出現越界的情況,數據比較小的時候,又有可能會浪費掉內存空間。在改變數據個數時,增加、插入、刪除數據效率比較低。
鏈表:是動態申請內存空間,不需要像數組需要提前申請好內存的大小,鏈表只需在用的時候申請就可以,根據需要來動態申請或者刪除內存空間,對於數據增加和刪除以及插入比數組靈活。還有就是鏈表中數據在內存中可以在任意的位置,通過應用來關聯數據(就是通過存在元素的指針來聯系)。
數組和鏈表就拿增加數據來說,數組中增加一個元素,需要移動大量的元素,在內存中空出一個元素的空間,然后將增加的元素放到空出的空間中;而鏈表就是將鏈表中最后的一個元素的指針指向新增的元素,在指出新增元素是尾元素就好了。
數組應用場景:
1、數據比較少;
2、經常做的運算是按序號訪問數據元素;
3、數組更容易實現,任何高級語言都支持;
4、構建的線性表較穩定。
/**
* 自定義長度可變的數組[存放字符串]
* @author Administrator
*/
public class my {
// 定義一個長度為0的初始數組
private String src = new String[0];
/**
* 存放數據
* @param s 要存放的數據
*/
public void add(String s) {
// 定義一個新數組長度是源數組長度+1
String dest = new String[src.length + 1];
// 將原數組的數據拷貝到新數組中
System.arraycopy(src, 0, dest, 0, src.length);
// 將新數據放到新數組的最后一個位置
dest[dest.length - 1] = s;
// 將原數組指向新數組
src = dest;
}
/**
* 取出數據
* @param index 要取出的數據的下標
*/
public String get(int index) {
String s = src[index];
return s;
}
/**
* 根據下標刪除數據
* @param index要刪除的數據的下標
*/
public void delete(int index) {
String dest=new String[src.length-1];
//將下標小於index的拷貝到新數組對應的下標
System.arraycopy(src,0,dest,0,index);
//將下標大於index的拷貝到新數組下標的位置為原數組的下標位置-1
System.arraycopy(src,index+1,dest,index,src.length-index-1);
//將src指向新數組
src=dest;
}
/**
* 刪除指定的數據
* @param s要刪除的數據,如果有重復的數據,就刪除下標最小的
*/
public void delete(String s) {
int t=-1;
for(int i=0;i<src.length;i++){
if(s.equals(src[i])){
t=i;
break;
}
}
//如果s在數組中出現過,t一定是大於等於0的
if(t>=0){
delete(t);
}
}
/**
* 將數據插入到指定位置
* @param index 要插入的位置
* @param s 要插入的數據
*/
public void insert(int index,String s){
String dest = new String[src.length+1];
//將新數據放到新數組指定的位置
dest[index]=s;
//將下標小於index的數據拷貝到新數組對應的下標位置
System.arraycopy(src,0,dest,0,index);
//將下標大於等於index的數據拷貝到 新數組下標+1的位置
System.arraycopy(src, index, dest,index+1, src.length-index);
src=dest;
}
/**
* 修改數據
* @param index要修改的數據的下標
* @param s修改后的數據
*/
public void update(int index, String s) {
src[index] = s;
}
/**
* 獲得數據個數
*/
public int size {
return src.length;
}
}
/**
* 自定義長度可變數組的測試類
*
* @author Administrator
*
*/
public static void main(String[] args) {
// 創建數組對象
my arr = new my;
// 增加數據
arr.add("AA");
arr.add("BB");
arr.add("CC");
arr.add("DD");
arr.add("EE");
arr.add("FF");
//根據下標刪除數據
arr.delete(3);
//刪除指定的數據
arr.delete("BB");
//將數據插入到指定位置
arr.insert(0,"on");
//修改數據
arr.update(2, "up");
//獲得數據個數
arr.size;
// 取出數據
for (int i = 0; i < arr.size; i++) {
String s = arr.get(i);
System.out.println(s);
}
}
}
//結果
// on
// AA
// up
// EE
// FF
鏈表應用場景:
1、對線性表的長度或者規模難以估計;
2、可以頻繁做插入刪除操作;
3、構建動態性比較強的線性表。
/**
* 自定義鏈表類【雙向鏈表】
*
* @author Administrator
*
*/
public class MyLinkList<E> {
// 初始狀態下,鏈表沒有任何結點,頭結點為null,尾結點為null
private Node<E> head = null;
private Node<E> last = null;
private int num = 0;// 數據個數
// 增加數據
public void add(E e) {
// 根據數據創建結點對象
Node<E> node = new Node<E>(e);
// 如果鏈表中已經有結點,就將node作為last的下一個結點
if (last != null) {
last.next = node;
node.front = last;
last = node;
} else {
// 如果鏈表中還沒有結點,node就是第一個結點
// 既是頭結點,又是尾結點
head = node;
last = node;
}
num++;
}
//插入數據
public void insert(int index, E e) {
// 創建新結點
Node<E> node = new Node<E>(e);
// 找到index位置的結點
Node<E> n1 = getNode(index);
// 找到n1的前一個結點
Node<E> n2 = n1.front;
n2.next = node;
node.front = n2;
node.next = n1;
n1.front = node;
num++;
}
public void delete(int index) {
}
public void delete(E e) {
}
public void update(int index, E e) {
Node<E> n1 = getNode(index);
n1.data = e;
}
public E get(int index) {
Node<E> node = getNode(index);
return node.data;
}
//根據內容確定下標
private int getIndex(E e){
int index=-1;
Node<E> n = head;
while(n!=null){
index++;
if(n.data.equals(e)){
break;
}
n=n.next;
}
return index;
}
public int getIndex2(E e){
for(int i=0;i<num;i++){
E e2 = get(i);
if(e2.equals(e)){
return i;
}
}
return -1;
}
//根據下標確定結點
private Node<E> getNode(int index) {
int t = -1;
if (index >= 0 && index < num) {
Node<E> n = head;
while (n != null) {
t++;
if (t == index) {
break;
}
n = n.next;
}
return n;
} else {
// 拋出異常
throw new IndexOutOfBoundsException("下標超出邊界!index:" + index
+ ",size:" + num);
}
}
public int size {
return num;
}
}
// 內部的結點類,主要為MyLinkList類服務
class Node<E> {
// 結點的數據
E data;
// 對下一個結點的引用
Node<E> next;
// 對前一個結點的引用
Node<E> front;
// 創建結點對象的時候必須指定數據
public Node(E e) {
data = e;
}
}
public class Main {
public static void main(String[] args){
myLinkList<String> mm=new myLinkList<String>;
mm.add("AA");
mm.add("BB");
mm.add("CC");
mm.add("DD");
mm.add("EE");
mm.insert(2,"鏈");
mm.update(3, "表");
for(int i=0;i<mm.size;i++){
String s=mm.get(i);
System.out.println(s);
}
}
}
//結果
// AA
// BB
// 鏈
// 表
// DD
// EE
