線性表——順序表——時間複雜度計算
資料結構的核心思想是通過資料結構的思維來優化程式碼的演算法,以此來提升程式的執行效能,縮短程式執行的時間。下面我來舉兩個例子,以此來說明資料結構的時間複雜度計算問題。
由於我這裡操作的是線性表——順序表,所以說先把線性表——順序表的原始碼貼出來
AbstractLineMethod.java
package com.mycompany;
import util.ObjectHolder;
/**
* Created by HP on 2017/9/6.
*/
public interface AbstractLineMethod {
/**
* 初始化線性表
* @param size
*/
void initList(int size);
/**
* 銷燬線性表
*/
void destroyList();
/**
* 清空線性表
*/
void clearList();
/**
* 線性表判空
* @return
*/
boolean listEmpty();
/**
* 獲取線性表的長度
* @return
*/
int listLength();
/**
* 獲取指定位置處的元素
* @param i
* @param ele
* @return
*/
public boolean getElem(int i, ObjectHolder ele);
/**
* 獲取該元素線上性表中第一次出現的位置
* @param ele
* @return
*/
public int locateElem(ObjectHolder ele);
/**
* 獲取指定元素的前驅
* @param currentElem
* @param preElem
* @return
*/
public boolean priorElem(ObjectHolder currentElem,ObjectHolder preElem);
/**
* 獲取指定元素的後繼
* @param currentElem
* @param nextElem
* @return
*/
public boolean nextElem(ObjectHolder currentElem,ObjectHolder nextElem);
/**
* 線上性表的指定位置處插入元素
* @param i
* @param ele
* @return
*/
public boolean listInsert(int i,Object ele);
/**
* 刪除線性表指定位置處的元素
* @param i
* @param ele
* @return
*/
public boolean listDelete(int i,ObjectHolder ele);
/**
* 迴圈遍歷線性表
*/
public void listTraverse();
}
LineMethod.java
package com.mycompany;
import util.ObjectHolder;
/**
* Created by HP on 2017/9/6.
*/
public class LineMethod implements AbstractLineMethod{
private int m_size = 0;
private Object[] m_pList = null;
private int m_iLength = 0;
/**
* 初始化線性表
* @param size
*/
public void initList(int size){
this.m_size = size;
this.m_pList = new Object[size];
this.m_iLength = 0;
}
/**
* 銷燬線性表
*/
public void destroyList(){
this.m_pList = null;
this.m_size = 0;
this.m_iLength = 0;
}
/**
* 將線性表指標歸零
*/
public void clearList(){
this.m_iLength = 0;
}
/**
* 判空操作
* 如果線性表為空,則返回true否則返回false
* @return
*/
public boolean listEmpty(){
if(this.m_iLength == 0){
return true;
}
return false;
}
/**
* 返回線性表的長度
* @return
*/
public int listLength(){
return m_iLength;
}
/**
* 獲取指定位置處的元素
* @param i
* @param ele
* @return
*/
public boolean getElem(int i, ObjectHolder ele){
if(i < 0 || i >= m_size){
return false;
}
ele.object = this.m_pList[i];
return true;
}
/**
* 尋找第一個滿足ele的資料元素的位序
* @param ele
* @return
*/
public int locateElem(ObjectHolder ele){
for(int i = 0;i < this.m_iLength; i++){
if(this.m_pList[i] == ele.object){
return i;
}
}
return -1;
}
/**
* 獲取指定元素的前驅,如果存在,則返回true,不存在則返回false
* @param currentElem
* @param preElem
* @return
*/
public boolean priorElem(ObjectHolder currentElem,ObjectHolder preElem){
//如果查詢元素不位於線性表,則返回false
int temp = locateElem(currentElem);
if(temp == -1){
return false;
}
//第一個元素沒有前驅,所以說應該加以排除
if(temp == 0){
return false;
}
preElem.object = this.m_pList[temp - 1];
return true;
}
/**
* 獲取指定元素的後繼,如果存在則返回true,如果不存在則返回false
* @param currentElem
* @param nextElem
* @return
*/
public boolean nextElem(ObjectHolder currentElem,ObjectHolder nextElem){
//如果所查詢元素不是位於線性表中,則返回false
int temp = locateElem(currentElem);
if(temp == -1){
return false;
}
//最後一個元素沒有後繼,應該加以排除
if(temp == this.m_iLength -1){
return false;
}
nextElem.object = this.m_pList[temp + 1];
return true;
}
/**
* 在指定位置處插入指定元素,如果插入成功則返回true,失敗則返回false
* @param i
* @param ele
* @return
*/
public boolean listInsert(int i,Object ele){
if(i < 0 || i > this.m_iLength){
return false;
}
for (int k = this.m_iLength - 1;k >= i;k --){
this.m_pList[k + 1] = this.m_pList[k];
}
this.m_pList[i] = ele;
this.m_iLength ++;
return true;
}
/**
* 線上性表中刪除指定的元素,如果刪除成功,則返回true,如果刪除失敗則返回false
* @param i
* @param ele
* @return
*/
public boolean listDelete(int i,ObjectHolder ele){
if(i < 0 || i >= this.m_iLength){
return false;
}
ele.object = this.m_pList[i];
for(int k = i +1;k < this.m_iLength;k ++){
this.m_pList[k - 1] = this.m_pList[k];
}
this.m_iLength --;
return true;
}
/**
* 迴圈遍歷線性表中的元素
*/
public void listTraverse(){
for(int i = 0;i < this.m_iLength;i ++){
System.out.println(this.m_pList[i]);
}
}
}
ObjectHolder.java
package util;
/**
* Created by HP on 2017/9/6.
*/
public class ObjectHolder {
public Object object;
}
下面是對於該線性表的時間複雜度的計算示例
示例1:
現有現有線性表LA,LB,LA中的陣列為:3,5,7,2,9,8,LB中的陣列為:4,,6,0,1現將LB中的數組合併到LA中,方法為:
TestUnion.java
package com.mycompany;
import org.apache.log4j.Logger;
import org.junit.Assert;
import org.junit.Test;
import util.ObjectHolder;
/**
* 現有線性表LA,LB
* LA中的陣列為:3,5,7,2,9,8
* LB中的陣列為:4,,6,0,1
* 現將LB中的數組合併到LA中
* Created by HP on 2017/9/12.
*/
public class TestUnion {
private static final Logger log = Logger.getLogger(TestUnion.class);
/**
* 建立線性表LA
* @return
*/
public AbstractLineMethod createListLA(){
Object e1 = 3;
Object e2 = 5;
Object e3 = 7;
Object e4 = 2;
Object e5 = 9;
Object e6 = 8;
AbstractLineMethod abstractLineMethod = new LineMethod();
abstractLineMethod.initList(10);
abstractLineMethod.listInsert(0,e1);
abstractLineMethod.listInsert(1,e2);
abstractLineMethod.listInsert(2,e3);
abstractLineMethod.listInsert(3,e4);
abstractLineMethod.listInsert(4,e5);
abstractLineMethod.listInsert(5,e6);
return abstractLineMethod;
}
/**
* 建立線性表LB
* @return
*/
public AbstractLineMethod createListLB(){
Object e1 = 4;
Object e2 = 6;
Object e3 = 0;
Object e4 = 1;
AbstractLineMethod abstractLineMethod = new LineMethod();
abstractLineMethod.initList(10);
abstractLineMethod.listInsert(0,e1);
abstractLineMethod.listInsert(1,e2);
abstractLineMethod.listInsert(2,e3);
abstractLineMethod.listInsert(3,e4);
return abstractLineMethod;
}
/**
* 合併線性表LA與LB
*/
@Test
public void testUnion(){
//集合A
AbstractLineMethod la = createListLA();
//線性表LA的順序:3,5,7,2,9,8
//集合B
AbstractLineMethod lb = createListLB();
//線性表LB的順序:4,6,0,1
//集合A的長度
int laLenth = la.listLength();
//集合B的長度
int lbLenth = lb.listLength();
ObjectHolder ele = new ObjectHolder();
for(int i = 0;i < lbLenth;i ++){
lb.getElem(i,ele);
if(la.locateElem(ele) == -1){
la.listInsert(laLenth ++,ele.object);
}
}
//迴圈遍歷新陣列
la.listTraverse();
//輸出結果:3,5,7,2,9,8,4,6,0,1
Assert.assertEquals(10,la.listLength());
log.info("合併後的線性表陣列長度為:" + la.listLength());
}
}
示例2:
現有非降序線性表LA,LB,其中線性表LA中的陣列為:3,5,8,11,線性表LB中的陣列元素為:2,6,8,9,11,15,20,現將LA與LB中的元素按照非降序順序插入到空線性表LC中,方法為:
TestMergeList.java
package com.mycompany;
import org.apache.log4j.Logger;
import org.junit.Assert;
import org.junit.Test;
import util.ObjectHolder;
/**
* 現有非降序線性表LA,LB
* 其中線性表LA中的陣列為:3,5,8,11
* 線性表LB中的陣列元素為:2,6,8,9,11,15,20
* 現將LA與LB中的元素按照非降序順序插入到空線性表LC中,方法如下:
* Created by HP on 2017/9/13.
*/
public class TestMergeList {
private static final Logger log = Logger.getLogger(TestMergeList.class);
/**
* 建立線性表LA
* @return
*/
public AbstractLineMethod createListLA(){
Object e1 = 3;
Object e2 = 5;
Object e3 = 8;
Object e4 = 11;
AbstractLineMethod abstractLineMethod = new LineMethod();
abstractLineMethod.initList(10);
abstractLineMethod.listInsert(0,e1);
abstractLineMethod.listInsert(1,e2);
abstractLineMethod.listInsert(2,e3);
abstractLineMethod.listInsert(3,e4);
return abstractLineMethod;
}
/**
* 建立線性表LB
* @return
*/
public AbstractLineMethod createListLB(){
Object e1 = 2;
Object e2 = 6;
Object e3 = 8;
Object e4 = 9;
Object e5 = 11;
Object e6 = 15;
Object e7 = 20;
AbstractLineMethod abstractLineMethod = new LineMethod();
abstractLineMethod.initList(10);
abstractLineMethod.listInsert(0,e1);
abstractLineMethod.listInsert(1,e2);
abstractLineMethod.listInsert(2,e3);
abstractLineMethod.listInsert(3,e4);
abstractLineMethod.listInsert(4,e5);
abstractLineMethod.listInsert(5,e6);
abstractLineMethod.listInsert(6,e7);
return abstractLineMethod;
}
/**
* 建立空的線性表LC
* @return
*/
public AbstractLineMethod createListLC(){
AbstractLineMethod abstractLineMethod = new LineMethod();
abstractLineMethod.initList(20);
return abstractLineMethod;
}
/**
* 合併到LC
*/
@Test
public void mergeToLC(){
//建立線性表LA
AbstractLineMethod la = createListLA();
//建立線性表LB
AbstractLineMethod lb = createListLB();
//建立空的線性表LC
AbstractLineMethod lc = createListLC();
//初始化下標i,j
int i = 0,j = 0;
//當兩個下標長度均在有效範圍內時
while((i < la.listLength()) && (j < lb.listLength())){
ObjectHolder laEle = new ObjectHolder();
ObjectHolder lbEle = new ObjectHolder();
//如果元素laEle與元素lbEle都獲取成功時
if(la.getElem(i,laEle) && lb.getElem(j,lbEle)){
//如果laEle元素的雜湊值小於等於lbEle元素的雜湊值,則將laEle元素插入到lc線性表中
if(laEle.object.hashCode() <= lbEle.object.hashCode()){
lc.listInsert(i + j,laEle.object);
//插入後,線性表la中的指標後移一位
i ++;
} else { //否則的話,此時laEle中的元素大於lbEle中的元素,則將lbEle元素插入到lc線性表中
lc.listInsert(i + j,lbEle.object);
//插入後,線性表lb中的指標後移一位
j ++;
}
}
}
//當其中的一個線性表迴圈遍歷結束,另一個還沒結束時,此時應該做的就是將沒有迴圈結束的線性表中剩餘的元素依次全部插入到lc中
//當線性表la剩餘時
while(i < la.listLength()){
ObjectHolder ele = new ObjectHolder();
//如果la中的元素獲取正確時,執行if語句中的程式碼
if(la.getElem(i,ele)){
//將該獲取的元素插入到lc中
lc.listInsert(i + j,ele.object);
//將la中的元素指標(下標)自增1
i ++;
}
}
//當線性表lb剩餘時
while(j < lb.listLength()){
ObjectHolder ele = new ObjectHolder();
//如果lb中的元素獲取正確時,執行if語句中的程式碼
if(lb.getElem(j,ele)){
//將該獲取的元素插入到lc中
lc.listInsert(i + j,ele.object);
//將lb中的元素指標(下標)自增1
j ++;
}
}
//迴圈結束之後,迴圈遍歷lc中的元素
lc.listTraverse();
log.info("合併後的陣列長度為:" + lc.listLength());
Assert.assertEquals(11,lc.listLength());
}
}
通過上述2個示例我們不難看出:
在示例1中,每次在LA中插入一個LB中的元素,該元素都要迴圈遍歷LA中的每一個元素,然後將其插入其中,其插入的耗時為:O(listLength(LA)*listLength(LB))
在示例2中,雖然整體的程式碼量比示例1中的程式碼量要長,但是LA中的元素已經找到,只要符合條件即可插入到LC中,而LB中的元素也是一樣的,這樣一來,插入到LC中的元素,LA只需要迴圈一次,LB也只需要迴圈一次,所以說整體的時間消耗為:
O(listLength(LA)+listLength(LB))
通過上述分析,我們可以發現,雖然示例2中的情況更復雜,程式碼量也更多,但是實際上在程式碼執行耗時操作時,示例2中的方法效能要明顯優於示例1中的方法。
下面是該專案的完整下載地址: