我是野豬。
想在開始介紹之前,說下自己一步步開始自學數據結構與算法的思想,首先爲啥要學?通常情況下,精心選擇合適的數據結構可以帶來更高的運行或存儲效率;其次如何去學?我認爲剛開始學習數據結構(或者說算法)類似於射箭,“射藝無其他竅門兒,手熟是第一祕訣,你多練幾次,自然能領悟其中道理”,又或者說像是學騎自行車,剛開始都比較吃力,只要堅持不懈的學、多多練習自然能像一個常人那樣騎車子,至於以後的進階纔有的人騎得花樣百出、有的人造詣更深。
數據結構是計算機存儲、組織數據的方式,也就是說數據結構不單單是數據存儲的容器,還要有對數據的基本操作,如檢索、插入、刪除、展示等。通常情況下,精心選擇合適的數據結構可以帶來更高的運行或存儲效率。數據結構通常與高效的檢索算法和索引技術有關。
以數組爲例,是爲了處理方便,把具有相同類型的若干變量按有序的形式組織起來,這些按順序排列的同類型數據的結合稱爲數組,並且還有對其中數據的基本操作。
代碼如下:
/**
* 有序數組
*/
public class OrderArray {
//創建int類型的數組
private final int[] intArray;
//創建的數組默認的長度
private int aLength = 0;
public OrderArray(int max) {
intArray = new int[max];
}
/**
* 插入元素
*
* @param elem
*/
public void insertElem(int elem) {
int location = 0;
//1. 插入新的元素時 要先找到元素所在的位置 因爲是有序數組 遍歷只要找到座標所在的元素大於插入元素則停止
for (; location < aLength; location++) {
if (intArray[location] > elem) {
break;
}
}
//2. 所在位置之後的元素全部後移一位
for (int i = aLength; location < i; i--) {
intArray[i] = intArray[i - 1];
}
//3. 插入元素
intArray[location] = elem;
//4. 長度加1
aLength++;
}
/**
* 遍歷查看所有元素
*/
public void showAllElem() {
for (int i = 0; i < aLength; i++) {
System.out.println(intArray[i] + "\t");
}
}
/**
* 二分法查找某元素是否在有序數組中,有則返回所在的下標,否則返回-1
*
* @param val
* @return
*/
public int searchElem(int val) {
int low = 0;
int high = aLength - 1;
while (true) {
int mid = (low + high) / 2;
if (intArray[mid] == val) {
return mid;
} else if (low == mid) {
//只有當切割完之後的數組中的元素個數是1或2時 纔會滿足
if (val == intArray[high]) {
return high;
} else {
return -1;
}
} else {
if (intArray[mid] < val) {
//說明查詢的值val在下標mid和high之間 因此low = mid
low = mid;
} else if (intArray[mid] > val) {
high = mid;
}
}
}
}
/**
* 刪除數據
*
* @param val
* @return
*/
public boolean deleteElem(int val) {
int index = -1;
//1. 先檢索val值所在的下標
int tempLocation = searchElem(val);
//2.確定下標後其後的元素全部前移一位
if (tempLocation != -1) {
for (int i = tempLocation; i < aLength-1; i++) {
intArray[i] = intArray[i + 1];
}
//3.數組長度減一
aLength--;
return true;
} else {
System.out.println("要刪除的元素不存在,請重新輸入");
return false;
}
}
}
/**
* 測試
*/
public class Test {
public static void main(String[] args) {
OrderArray orderArray = new OrderArray(5);
orderArray.insertElem(1);
orderArray.insertElem(4);
orderArray.insertElem(3);
orderArray.insertElem(5);
orderArray.insertElem(10);
orderArray.showAllElem();
int i = orderArray.searchElem(0);
System.out.println("所查元素的下標是"+i);
boolean deleteElem = orderArray.deleteElem(5);
if (deleteElem) {
orderArray.showAllElem();
}
}
}
對數據的處理有插入數據、展示全部數據、檢索數據、刪除數據等。
插入數據:首先遍歷整個數據集,當插入的元素大於某下標對應的值則break跳出循環,拿到當前的location,其後的元素全部後移一位。
展示數據:遍歷整個數據集即可。
檢索數據:用的是典型針對有序數據集的二分查找(又叫折半查找)法,使得查詢效率大大提高(文章末尾有詳細分析並引入一些基本的數據結構概念)。
刪除數據:刪除數據是在檢索數據的基礎上,找到指定元素的位置下標,下標之後的元素全部前移一位。
二分查找:可以看出循環中的每一步將查找的範圍縮小一半,最終這個範圍會縮小到無法再分割。基本圖示如下:
通過二分查找我們可以體會這樣一件事即當我們查找一個有序數組的時候可以先切割一半比較一直找到對應的元素,假設數據量是100,查詢過程體現在數字上就是下面這張圖:
這就是時間複雜度的概念:淺顯地理解就是當你數據範圍很大時,花費的時間變化如何。
假設我們在上述數組例子中查找具體值然後返回下標的過程中不是採用二分查找而是整個數據集循環遍歷,那麼最多花費的次數是數據集的長度,比如100個數,花費的時間最長就是100,而二分只是7;範圍擴大到1000時,花費的時間是1000,而二分只是10,所以說整個查詢效率有很大的區別尤其是數據量很大時。
下圖是常見的增長數量級的總計:接下來我們會一直用到。
比如對數基本的二分查找的時間複雜度就稱爲O(log N)。
通過以上以數組爲例我們簡單的說了一些數據結構的基本概念,方便我們入門。
最後補充一些上述沒有提到的最基本的概念:
數據的邏輯結構:指反映數據元素之間的的邏輯關係。
1.線性結構:數據元素之間是一對一的關係。
2.樹形結構:數據元素之間是一對多的關係。
3.圖形結構:數據元素之間是多對多的關係。
常見的數據結構有:
數組 :爲了處理方便,把具有相同類型的若干變量按有序的形式組織起來。這些按順序排列的同類型數據的結合稱爲數組。
棧 :只能在一端插入和刪除的特殊線性表。按照先進後出的原則存儲數據。
隊列 :一種特殊的線性表,原則是隻允許在表的前端進行刪除操作,而在表的後端進行插入操作。顯然隊列是按照先進先出的原則組織數據。
鏈表 :鏈表是一種物理存儲單元上非連續、非順序的存儲結構,數據元素的邏輯結構是通過鏈表中的指針鏈接次序實現的。鏈表由一系列的結點(鏈表中的每一個元素稱爲結點)組成,每個結點都分爲兩部分:一個是存儲數據元素的數據域;另一個是存儲下一個結點地址的指針域。
樹 :暫時理解不好,稍後補充,哈哈。
圖 :暫時理解不好,稍後補充,哈哈。
堆 :堆是一種特殊的樹形結構,每個結點都有一個值。通常我們所說的堆的數據結構,是指二叉堆。堆的特點是根結點的值最大(或最小),且根結點的兩個子樹也是一個堆。