數據結構基礎、線性表、棧和隊列、數組和字符串

Java面試寶典之數據結構基礎 —— 線性表篇

作者:egg

郵箱:[email protected]

微博:http://weibo.com/xtfggef

博客:http://blog.csdn.net/zhangerqing(轉載請說明出處)

這部分內容作爲計算機專業最基礎的知識,幾乎被所有企業選中用來作考題,因此,本章我們從本章開始,我們將從基礎方面對數據結構進行講解,內容主要是線性表,包括棧、隊列、數組、字符串等,主要講解基礎知識,如概念及簡單的實現代碼,非線性結構我們在後面的文章中給出。過程中有任

何問題,請聯繫本人:http://weibo.com/xtfggef 


一、數據結構概念

用我的理解,數據結構包含數據和結構,通俗一點就是將數據按照一定的結構組合起來,不同的組合方式會有不同的效率,使用不同的場景,如此而已。比如我們最常用的數組,就是一種數據結構,有獨特的承載數據的方式,按順序排列,其特點就是你可以根據下標快速查找元素,但是因爲在數組中插入和刪除元素會有其它元素較大幅度的便宜,所以會帶來較多的消耗,所以因爲這種特點,使得數組適合:查詢比較頻繁,增、刪比較少的情況,這就是數據結構的概念。數據結構包括兩大類:線性結構和非線性結構,線性結構包括:數組、鏈表、隊列、棧等,非線性結構包括樹、圖、表等及衍生類結構。本章我們先講解線性結構,主要從數組、鏈表、隊列、棧方面進行討論,非線性數據結構在後面會繼續講解。


二、線性表

線性表是最基本、最簡單、也是最常用的一種數據結構。線性表中數據元素之間的關係是一對一的關係,即除了第一個和最後一個數據元素之外,其它數據元素都是首尾相接的。線性表的邏輯結構簡單,便於實現和操作。因此,線性表這種數據結構在實際應用中是廣泛採用的一種數據結構。其基本操作主要有:

   1)MakeEmpty(L) 這是一個將L變爲空表的方法
   2)Length(L) 返回表L的長度,即表中元素個數 
   3)Get(L,i) 這是一個函數,函數值爲L中位置i處的元素(1≤i≤n)
   4)Prev(L,i) 取i的前驅元素
   5)Next(L,i) 取i的後繼元素
   6)Locate(L,x) 這是一個函數,函數值爲元素x在L中的位置
   7)Insert(L,i,x)在表L的位置i處插入元素x,將原佔據位置i的元素及後面的元素都向後推一個位置
   8)Delete(L,p) 從表L中刪除位置p處的元素
   9)IsEmpty(L) 如果表L爲空表(長度爲0)則返回true,否則返回false
   10)Clear(L)清除所有元素
   11)Init(L)同第一個,初始化線性表爲空
   12)Traverse(L)遍歷輸出所有元素
   13)Find(L,x)查找並返回元素
   14)Update(L,x)修改元素
   15)Sort(L)對所有元素重新按給定的條件排序
   16) strstr(string1,string2)用於字符數組的求string1中出現string2的首地址

不管採用哪種方式實現線性表,至少都應該具有上述這些基本方法,下面我會將下數據結構的基本實現方式。


三、基礎數據結構

數據結構是一種抽象的數據類型(ADT),可以這麼說,我們可以採用任意的方式實現某種數據結構,只要符合將要實現的數據結構的特點,數據結構就是一種標準,我們可以採用不同的方式去實現,最常用的兩種就是數組和鏈表(包括單鏈表、雙向鏈表等)。數組是非常常見的數據類型,在任何一種語言裏都有它的實現,我們這裏採用Java來簡單實現一下數組。
數組是一種引用類型的對象,我們可以像下面這樣的方式來聲明數組:

[java]  view plain  copy
  1. int a[];  
  2. int[] b;  
  3. int []c;  

[java]  view plain  copy
  1. a = new int[10];  

總結起來,聲明一個數組有基本的三個因素:類型、名稱、下標,Java裏,數組在格式上相對靈活,下標和名稱可以互換位置,前三種情況我們可以理解爲聲明一個變量,後一種爲其賦值。或者像下面這樣,在聲明的時候賦值:

[java]  view plain  copy
  1. int c[] = {2,3,6,10,99};  
  2. int []d = new int[10];  

我稍微解釋一下,其實如果只執行:int[] b,只是在棧上創建一個引用變量,並未賦值,只有當執行d = new int[10]纔會在堆上真正的分配空間。上述第一行爲靜態初始化,就是說用戶指定數組的內容,有系統計算數組的大小,第二行恰恰相反,用戶指定數組的大小,由系統分配初始值,我們打印一下數組的初始值:

[java]  view plain  copy
  1. int []d = new int[10];  
  2. System.out.println(d[2]);  
結果輸出0,對於int類型的數組,默認的初始值爲0.

但是,絕對不可以像下面這樣:

[java]  view plain  copy
  1. int e[10] = new int[10];  
無法通過編譯,至於爲什麼,語法就是這樣,這是一種規範,不用去想它。
我們可以通過下標來檢索數組。下面我舉個簡單的例子,來說明下數組的用法。

[java]  view plain  copy
  1. public static void main(String[] args) {  
  2.   
  3.     String name[];  
  4.   
  5.     name = new String[5];  
  6.     name[0] = "egg";  
  7.     name[1] = "erqing";  
  8.     name[2] = "baby";  
  9.   
  10.     for (int i = 0; i < name.length; i++) {  
  11.         System.out.println(name[i]);  
  12.     }  
  13. }  
這是最簡單的數組聲明、創建、賦值、遍歷的例子,下面寫個增刪的例子。

[java]  view plain  copy
  1. package com.xtfggef.algo.array;  
  2.   
  3. public class Array {  
  4.   
  5.     public static void main(String[] args) {  
  6.   
  7.         int value[] = new int[10];  
  8.         for (int i = 0; i < 10; i++) {  
  9.             value[i] = i;  
  10.         }  
  11.   
  12.         // traverse(value);  
  13.         // insert(value, 666, 5);  
  14.         delete(value, 3);  
  15.         traverse(value);  
  16.     }  
  17.   
  18.     public static int[] insert(int[] old, int value, int index) {  
  19.         for (int k = old.length - 1; k > index; k--)  
  20.             old[k] = old[k - 1];  
  21.         old[index] = value;  
  22.         return old;  
  23.     }  
  24.   
  25.     public static void traverse(int data[]) {  
  26.         for (int j = 0; j < data.length; j++)  
  27.             System.out.print(data[j] + " ");  
  28.     }  
  29.   
  30.     public static int[] delete(int[] old, int index) {  
  31.         for (int h = index; h < old.length - 1; h++) {  
  32.             old[h] = old[h + 1];  
  33.         }  
  34.         old[old.length - 1] = 0;  
  35.         return old;  
  36.     }  
  37. }  
簡單寫一下,主要想說明數組中刪除和增加元素的原理:增加元素,需要將index後面的依次向後移動,然後將值插入index位置,刪除則將後面的值依次向前移動,較簡單。

要記住:數組是表示相同類型的一類數據的集合,下標從0開始,就行了。

數組實現的線下表可以參考ArrayList,在JDK中附有源碼,感興趣的同學可以讀讀。下面我簡單介紹下單鏈表。

單鏈表是最簡單的鏈表,有節點之間首尾連接而成,簡單示意如下:


除了頭節點,每個節點包含一個數據域一個指針域,除了頭、尾節點,每個節點的指針指向下一個節點,下面我們寫個例子操作一下單鏈表。

[java]  view plain  copy
  1. package com.xtfggef.algo.linkedlist;  
  2.   
  3. public class LinkedList<T> {  
  4.   
  5.     /** 
  6.      * class node 
  7.      * @author egg 
  8.      * @param <T> 
  9.      */  
  10.     private static class Node<T> {  
  11.         T data;  
  12.         Node<T> next;  
  13.   
  14.         Node(T data, Node<T> next) {  
  15.             this.data = data;  
  16.             this.next = next;  
  17.         }  
  18.   
  19.         Node(T data) {  
  20.             this(data, null);  
  21.         }  
  22.     }  
  23.   
  24.     // data  
  25.     private Node<T> head, tail;  
  26.   
  27.     public LinkedList() {  
  28.         head = tail = null;  
  29.     }  
  30.   
  31.     /** 
  32.      * judge the list is empty 
  33.      */  
  34.     public boolean isEmpty() {  
  35.         return head == null;  
  36.     }  
  37.   
  38.     /** 
  39.      * add head node 
  40.      */  
  41.     public void addHead(T item) {  
  42.         head = new Node<T>(item);  
  43.         if (tail == null)  
  44.             tail = head;  
  45.     }  
  46.   
  47.     /** 
  48.      * add the tail pointer 
  49.      */  
  50.     public void addTail(T item) {  
  51.         if (!isEmpty()) {   
  52.             tail.next = new Node<T>(item);  
  53.             tail = tail.next;  
  54.         } else {   
  55.             head = tail = new Node<T>(item);  
  56.         }  
  57.     }  
  58.   
  59.     /** 
  60.      * print the list 
  61.      */  
  62.     public void traverse() {  
  63.         if (isEmpty()) {  
  64.             System.out.println("null");  
  65.         } else {  
  66.             for (Node<T> p = head; p != null; p = p.next)  
  67.                 System.out.println(p.data);  
  68.         }  
  69.     }  
  70.   
  71.     /** 
  72.      * insert node from head 
  73.      */  
  74.     public void addFromHead(T item) {  
  75.         Node<T> newNode = new Node<T>(item);  
  76.         newNode.next = head;  
  77.         head = newNode;  
  78.     }  
  79.   
  80.     /** 
  81.      * insert node from tail 
  82.      */  
  83.     public void addFromTail(T item) {  
  84.         Node<T> newNode = new Node<T>(item);  
  85.         Node<T> p = head;  
  86.         while (p.next != null)  
  87.             p = p.next;  
  88.         p.next = newNode;  
  89.         newNode.next = null;  
  90.     }  
  91.   
  92.     /** 
  93.      * delete node from head 
  94.      */  
  95.     public void removeFromHead() {  
  96.         if (!isEmpty())  
  97.             head = head.next;  
  98.         else  
  99.             System.out.println("The list have been emptied!");  
  100.     }  
  101.   
  102.     /** 
  103.      * delete frem tail, lower effect 
  104.      */  
  105.     public void removeFromTail() {  
  106.         Node<T> prev = null, curr = head;  
  107.         while (curr.next != null) {  
  108.             prev = curr;  
  109.             curr = curr.next;  
  110.             if (curr.next == null)  
  111.                 prev.next = null;  
  112.         }  
  113.     }  
  114.   
  115.     /** 
  116.      * insert a new node 
  117.      * @param appointedItem 
  118.      * @param item 
  119.      * @return 
  120.      */  
  121.     public boolean insert(T appointedItem, T item) {  
  122.         Node<T> prev = head, curr = head.next, newNode;  
  123.         newNode = new Node<T>(item);  
  124.         if (!isEmpty()) {  
  125.             while ((curr != null) && (!appointedItem.equals(curr.data))) {  
  126.                 prev = curr;  
  127.                 curr = curr.next;  
  128.             }  
  129.             newNode.next = curr;   
  130.             prev.next = newNode;  
  131.             return true;  
  132.         }  
  133.         return false;   
  134.     }  
  135.   
  136.     public void remove(T item) {  
  137.         Node<T> curr = head, prev = null;  
  138.         boolean found = false;  
  139.         while (curr != null && !found) {  
  140.             if (item.equals(curr.data)) {  
  141.                 if (prev == null)  
  142.                     removeFromHead();  
  143.                 else  
  144.                     prev.next = curr.next;  
  145.                 found = true;  
  146.             } else {  
  147.                 prev = curr;  
  148.                 curr = curr.next;  
  149.             }  
  150.         }  
  151.     }  
  152.   
  153.   
  154.     public int indexOf(T item) {  
  155.         int index = 0;  
  156.         Node<T> p;  
  157.         for (p = head; p != null; p = p.next) {  
  158.             if (item.equals(p.data))  
  159.                 return index;  
  160.             index++;  
  161.   
  162.         }  
  163.         return -1;  
  164.     }  
  165.   
  166.     /** 
  167.      * judge the list contains one data 
  168.      */  
  169.     public boolean contains(T item) {  
  170.         return indexOf(item) != -1;  
  171.     }  
  172. }  

單鏈表最好玩兒的也就是增加和刪除節點,下面的兩個圖分別是用圖來表示單鏈表增、刪節點示意,看着圖學習,理解起來更加容易!


接下來的隊列和棧,我們分別用不同的結構來實現,隊列用數組,棧用單列表,讀者朋友對此感興趣,可以分別再用不同的方法實現。


四、隊列
隊列是一個常用的數據結構,是一種先進先出(First In First Out, FIFO)的結構,也就是說只能在表頭進行刪除,在表尾進行添加,下面我們實現一個簡單的隊列。

[java]  view plain  copy
  1. package com.xtfggef.algo.queue;  
  2.   
  3. import java.util.Arrays;  
  4.   
  5. public class Queue<T> {  
  6.   
  7.     private int DEFAULT_SIZE = 10;  
  8.       
  9.     private int capacity;  
  10.       
  11.     private Object[] elementData;  
  12.       
  13.     private int front = 0;  
  14.     private int rear = 0;  
  15. private int DEFAULT_SIZE = 10;  
  16.       
  17.     private int capacity;  
  18.       
  19.     private Object[] elementData;  
  20.       
  21.     private int front = 0;  
  22.     private int rear = 0;  
  23.       
  24.     public Queue()  
  25.     {  
  26.         capacity = DEFAULT_SIZE;  
  27.         elementData = new Object[capacity];  
  28.     }  
  29.       
  30.     public
相關文章
相關標籤/搜索