Java之美[從菜鳥到高手演變]之資料結構基礎、線性表、棧和佇列、陣列和字串
Java面試寶典之資料結構基礎 —— 線性表篇
作者:egg
這部分內容作為計算機專業最基礎的知識,幾乎被所有企業選中用來作考題,因此,本章我們從本章開始,我們將從基礎方面對資料結構進行講解,內容主要是線性表,包括棧、佇列、陣列、字串等,主要講解基礎知識,如概念及簡單的實現程式碼,非線性結構我們在後面的文章中給出。過程中有任
一、資料結構概念
用我的理解,資料結構包含資料和結構,通俗一點就是將資料按照一定的結構組合起來,不同的組合方式會有不同的效率,使用不同的場景,如此而已。比如我們最常用的陣列,就是一種資料結構,有獨特的承載資料的方式,按順序排列,其特點就是你可以根據下標快速查詢元素,但是因為在陣列中插入和刪除元素會有其它元素較大幅度的便宜,所以會帶來較多的消耗,所以因為這種特點,使得陣列適合:查詢比較頻繁,增、刪比較少的情況,這就是資料結構的概念。資料結構包括兩大類:線性結構和非線性結構,線性結構包括:陣列、連結串列、佇列、棧等,非線性結構包括樹、圖、表等及衍生類結構。本章我們先講解線性結構,主要從陣列、連結串列、佇列、棧方面進行討論,非線性資料結構在後面會繼續講解。
二、線性表
線性表是最基本、最簡單、也是最常用的一種資料結構。線性表中資料元素之間的關係是一對一的關係,即除了第一個和最後一個數據元素之外,其它資料元素都是首尾相接的。線性表的邏輯結構簡單,便於實現和操作。因此,線性表這種資料結構在實際應用中是廣泛採用的一種資料結構。其基本操作主要有:
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來簡單實現一下陣列。
陣列是一種引用型別的物件,我們可以像下面這樣的方式來宣告陣列:
int a[];
int[] b;
int []c;
a = new int[10];
總結起來,宣告一個數組有基本的三個因素:型別、名稱、下標,Java裡,陣列在格式上相對靈活,下標和名稱可以互換位置,前三種情況我們可以理解為宣告一個變數,後一種為其賦值。或者像下面這樣,在宣告的時候賦值:
int c[] = {2,3,6,10,99};
int []d = new int[10];
我稍微解釋一下,其實如果只執行:int[] b,只是在棧上建立一個引用變數,並未賦值,只有當執行d = new int[10]才會在堆上真正的分配空間。上述第一行為靜態初始化,就是說使用者指定陣列的內容,有系統計算陣列的大小,第二行恰恰相反,使用者指定陣列的大小,由系統分配初始值,我們列印一下陣列的初始值:
int []d = new int[10];
System.out.println(d[2]);
結果輸出0,對於int型別的陣列,預設的初始值為0.但是,絕對不可以像下面這樣:
int e[10] = new int[10];
無法通過編譯,至於為什麼,語法就是這樣,這是一種規範,不用去想它。我們可以通過下標來檢索陣列。下面我舉個簡單的例子,來說明下陣列的用法。
public static void main(String[] args) {
String name[];
name = new String[5];
name[0] = "egg";
name[1] = "erqing";
name[2] = "baby";
for (int i = 0; i < name.length; i++) {
System.out.println(name[i]);
}
}
這是最簡單的陣列宣告、建立、賦值、遍歷的例子,下面寫個增刪的例子。package com.xtfggef.algo.array;
public class Array {
public static void main(String[] args) {
int value[] = new int[10];
for (int i = 0; i < 10; i++) {
value[i] = i;
}
// traverse(value);
// insert(value, 666, 5);
delete(value, 3);
traverse(value);
}
public static int[] insert(int[] old, int value, int index) {
for (int k = old.length - 1; k > index; k--)
old[k] = old[k - 1];
old[index] = value;
return old;
}
public static void traverse(int data[]) {
for (int j = 0; j < data.length; j++)
System.out.print(data[j] + " ");
}
public static int[] delete(int[] old, int index) {
for (int h = index; h < old.length - 1; h++) {
old[h] = old[h + 1];
}
old[old.length - 1] = 0;
return old;
}
}
簡單寫一下,主要想說明陣列中刪除和增加元素的原理:增加元素,需要將index後面的依次向後移動,然後將值插入index位置,刪除則將後面的值依次向前移動,較簡單。要記住:陣列是表示相同型別的一類資料的集合,下標從0開始,就行了。
陣列實現的線下表可以參考ArrayList,在JDK中附有原始碼,感興趣的同學可以讀讀。下面我簡單介紹下單鏈表。
單鏈表是最簡單的連結串列,有節點之間首尾連線而成,簡單示意如下:
除了頭節點,每個節點包含一個數據域一個指標域,除了頭、尾節點,每個節點的指標指向下一個節點,下面我們寫個例子操作一下單鏈表。
package com.xtfggef.algo.linkedlist;
public class LinkedList<T> {
/**
* class node
* @author egg
* @param <T>
*/
private static class Node<T> {
T data;
Node<T> next;
Node(T data, Node<T> next) {
this.data = data;
this.next = next;
}
Node(T data) {
this(data, null);
}
}
// data
private Node<T> head, tail;
public LinkedList() {
head = tail = null;
}
/**
* judge the list is empty
*/
public boolean isEmpty() {
return head == null;
}
/**
* add head node
*/
public void addHead(T item) {
head = new Node<T>(item);
if (tail == null)
tail = head;
}
/**
* add the tail pointer
*/
public void addTail(T item) {
if (!isEmpty()) {
tail.next = new Node<T>(item);
tail = tail.next;
} else {
head = tail = new Node<T>(item);
}
}
/**
* print the list
*/
public void traverse() {
if (isEmpty()) {
System.out.println("null");
} else {
for (Node<T> p = head; p != null; p = p.next)
System.out.println(p.data);
}
}
/**
* insert node from head
*/
public void addFromHead(T item) {
Node<T> newNode = new Node<T>(item);
newNode.next = head;
head = newNode;
}
/**
* insert node from tail
*/
public void addFromTail(T item) {
Node<T> newNode = new Node<T>(item);
Node<T> p = head;
while (p.next != null)
p = p.next;
p.next = newNode;
newNode.next = null;
}
/**
* delete node from head
*/
public void removeFromHead() {
if (!isEmpty())
head = head.next;
else
System.out.println("The list have been emptied!");
}
/**
* delete frem tail, lower effect
*/
public void removeFromTail() {
Node<T> prev = null, curr = head;
while (curr.next != null) {
prev = curr;
curr = curr.next;
if (curr.next == null)
prev.next = null;
}
}
/**
* insert a new node
* @param appointedItem
* @param item
* @return
*/
public boolean insert(T appointedItem, T item) {
Node<T> prev = head, curr = head.next, newNode;
newNode = new Node<T>(item);
if (!isEmpty()) {
while ((curr != null) && (!appointedItem.equals(curr.data))) {
prev = curr;
curr = curr.next;
}
newNode.next = curr;
prev.next = newNode;
return true;
}
return false;
}
public void remove(T item) {
Node<T> curr = head, prev = null;
boolean found = false;
while (curr != null && !found) {
if (item.equals(curr.data)) {
if (prev == null)
removeFromHead();
else
prev.next = curr.next;
found = true;
} else {
prev = curr;
curr = curr.next;
}
}
}
public int indexOf(T item) {
int index = 0;
Node<T> p;
for (p = head; p != null; p = p.next) {
if (item.equals(p.data))
return index;
index++;
}
return -1;
}
/**
* judge the list contains one data
*/
public boolean contains(T item) {
return indexOf(item) != -1;
}
}
單鏈表最好玩兒的也就是增加和刪除節點,下面的兩個圖分別是用圖來表示單鏈表增、刪節點示意,看著圖學習,理解起來更加容易!
接下來的佇列和棧,我們分別用不同的結構來實現,佇列用陣列,棧用單列表,讀者朋友對此感興趣,可以分別再用不同的方法實現。
四、佇列
佇列是一個常用的資料結構,是一種先進先出(First In First Out, FIFO)的結構,也就是說只能在表頭進行刪除,在表尾進行新增,下面我們實現一個簡單的佇列。
package com.xtfggef.algo.queue;
import java.util.Arrays;
public class Queue<T> {
private int DEFAULT_SIZE = 10;
private int capacity;
private Object[] elementData;
private int front = 0;
private int rear = 0;
public Queue()
{
capacity = DEFAULT_SIZE;
elementData = new Object[capacity];
}
public Queue(T element)
{
this();
elementData[0] = element;
rear++;
}
public Queue(T element , int initSize)
{
this.capacity = initSize;
elementData = new Object[capacity];
elementData[0] = element;
rear++;
}
public int size()
{
return rear - front;
}
public void add(T element)
{
if (rear > capacity - 1)
{
throw new IndexOutOfBoundsException("the queue is full!");
}
elementData[rear++] = element;
}
public T remove()
{
if (empty())
{
throw new IndexOutOfBoundsException("queue is empty");
}
@SuppressWarnings("unchecked")
T oldValue = (T)elementData[front];
elementData[front++] = null;
return oldValue;
}
@SuppressWarnings("unchecked")
public T element()
{
if (empty())
{
throw new IndexOutOfBoundsException("queue is empty");
}
return (T)elementData[front];
}
public boolean empty()
{
return rear == front;
}
public void clear()
{
Arrays.fill(elementData , null);
front = 0;
rear = 0;
}
public String toString()
{
if (empty())
{
return "[]";
}
else
{
StringBuilder sb = new StringBuilder("[");
for (int i = front ; i < rear ; i++ )
{
sb.append(elementData[i].toString() + ", ");
}
int len = sb.length();
return sb.delete(len - 2 , len).append("]").toString();
}
}
public static void main(String[] args){
Queue<String> queue = new Queue<String>("ABC", 20);
queue.add("DEF");
queue.add("egg");
System.out.println(queue.empty());
System.out.println(queue.size());
System.out.println(queue.element());
queue.clear();
System.out.println(queue.empty());
System.out.println(queue.size());
}
}
佇列只能在表頭進行刪除,在表尾進行增加,這種結構的特點,適用於排隊系統。
五、棧
棧是一種後進先出(Last In First Out,LIFO)的資料結構,我們採用單鏈表實現一個棧。
package com.xtfggef.algo.stack;
import com.xtfggef.algo.linkedlist.LinkedList;
public class Stack<T> {
static class Node<T> {
T data;
Node<T> next;
Node(T data, Node<T> next) {
this.data = data;
this.next = next;
}
Node(T data) {
this(data, null);
}
}
@SuppressWarnings("rawtypes")
static LinkedList list = new LinkedList();
@SuppressWarnings("unchecked")
public T push(T item) {
list.addFromHead(item);
return item;
}
public void pop() {
list.removeFromHead();
}
public boolean empty() {
return list.isEmpty();
}
public int search(T t) {
return list.indexOf(t);
}
public static void main(String[] args) {
Stack<String> stack = new Stack<String>();
System.out.println(stack.empty());
stack.push("abc");
stack.push("def");
stack.push("egg");
stack.pop();
System.out.println(stack.search("def"));
}
}
本章的內容都是很基礎的,重在讓讀者朋友們理解資料結構的概念,下章開始,我們會介紹樹、二叉樹等Java中的實現,敬請讀者朋友們持續關注!
作者:egg
有問題,請依照上述聯絡方式聯絡作者,歡迎讀者及時提出建議,謝謝!相關推薦
Java之美[從菜鳥到高手演變]之字符串
tween gin new 有關 菜鳥 article user 再看 use 一、String 1、String簡介 初始化: 一般由String聲明的字符串,長度是不可變的,這也是它與StringBuffer和StringBuilder最直觀的一個區別。一般初始化方式:
Java之美[從菜鳥到高手演變]之集合類【吐血推薦!講得太好了!!!】
source: http://blog.csdn.net/zhangerqing/article/details/8122075 最近在找工作,目前還沒有定下來,拿到了一個公司的offer,不過被當白菜了,正在商量薪資方面的事情。隨著百度面試的失敗,夢想再次破滅
Java之美[從菜鳥到高手演變]之spring框架初識
初識輕量級Java開源框架 --- Spring作者:eggspring是一個輕量級Java框架,其核心思想就是DI(Dependency Injection,即依賴注入)和IoC(Inversion of Control,即控制反轉),因為其開源、低侵入性,現在已經席捲了很大一部分市場,其最大競爭對手乃是J
Java之美[從菜鳥到高手演變]之設計模式
轉自:http://blog.csdn.net/zhangerqing/article/details/8194653 設計模式(Design Patterns) ——可複
Java之美[從菜鳥到高手演變]之Java
轉載自:http://blog.csdn.net/zhangerqing/article/details/8731044 Java面試複習提綱 作者:egg 郵箱:[email protected] 微博:http://weibo.com/xtfggef 部落格:http
Java之美[從菜鳥到高手演變]之資料結構基礎、線性表、棧和佇列、陣列和字串
Java面試寶典之資料結構基礎 —— 線性表篇作者:egg郵箱:[email protected]這部分內容作為計算機專業最基礎的知識,幾乎被所有企業選中用來作考題,因此,本章我們從本章開始,我們將從基礎方面對資料結構進行講解,內容主要是線性表,包括棧、佇列、陣列、
Java之美[從菜鳥到高手演變]系列之博文閱讀導航
隨著博文越來越多,為部落格新增一個導航很有必要!本部落格將相繼開通Java、CloudFoundry、Linux、Ruby等專欄,都會設立目錄,希望讀者朋友們能更加方便的閱讀!在閱讀的過程中有任何問題,請聯絡:egg。QQ群:169480361(請在本博文下面留言,驗證資訊為
Java之美[從菜鳥到高手演變]之JVM記憶體管理及垃圾回收
很多Java面試的時候,都會問到有關Java垃圾回收的問題,提到垃圾回收肯定要涉及到JVM記憶體管理機制,Java語言的執行效率一直被C、C++程式設計師所嘲笑,其實,事實就是這樣,Java在執行效率方面確實很低,一方面,Java語言採用面向物件思想,這也決定了其必然是開發效
Java之美[從菜鳥到高手演練]之Linux篇——壓縮及解壓縮命令tar的使用
-z :是否同時具有 gzip 的屬性?亦即是否需要用 gzip 壓縮-j :是否同時具有 bzip2 的屬性?亦即是否需要用 bzip2 壓縮-v :壓縮的過程中顯示檔案!這個常用,但不建議用在背景執行過程-f :使用檔名,請留意,在 f 之後要立即接檔名喔!不要再加引數 例如使用『 tar -zcvf
Java之美[從菜鳥到高手演練]之ThreadLocal原理分析
作者:二青簡介早在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal為解決多執行緒程式的併發問題提供了一種新的思路。使用這個工具類可以很簡潔地編寫出優美的多執行緒程式。當使用ThreadLocal維護變數時,ThreadLocal為
Java之美[從菜鳥到高手演練]之初識Hadoop
初識Hadoop這是一篇轉載的文章,閱讀原文請點選:原文地址Hadoop一直是我想學習的技術,正巧最近專案組要做電子商城,我就開始研究Hadoop,雖然最後鑑定Hadoop不適用我們的專案,但是我會繼續研究下去,技多不壓身。《Hadoop基礎教程》是我讀的第一本Hadoop書
Python之美[從菜鳥到高手]--urllib原始碼分析
urllib提供了較好的封裝,可以很方便的讀取http,ftp,file等協議資料,本篇只關注http。urllib的底層還是使用httplib模組,相比於httplib,urllib介面更加好
Python之美[從菜鳥到高手]--讀"一道面試題看 HashMap 的儲存方式"的聯想
在 HashMap 中存放的一系列鍵值對,其中鍵為某個我們自定義的型別。放入 HashMap 後,我們在外部把某一個 key 的屬性進行更改,然後我們再用這個 key 從 HashMap 裡取出元素,這時候 HashMap 會返回什麼?如何面試者直接答“這要看自定義型別的ha
Python之美[從菜鳥到高手]--一步一步動手給Python寫擴充套件(愛之初體驗)
一直對Python擴充套件很感興趣,剛好看到了Extending and Embedding the Python Interpreter文件,看的是最低版本(由於工作中用的是2.x, ̄□ ̄),官方文件 我使用的IDE是Code::Blocks 12.11,
Python之美[從菜鳥到高手]--Python垃圾回收機制及gc模組詳解
Python中的垃圾回收是以引用計數為主,標記-清除和分代收集為輔。引用計數最大缺陷就是迴圈引用的問題,所以Python採用了輔助方法。本篇文章並不詳細探討Python的垃圾回收機制的內部實現,而是以gc模組為切入點學習Python的垃圾回收機制,如果想深入可以讀讀
演算法之美[從菜鳥到高手演練]之一些個小演算法
1、10000以內的完數/* * 問題描述:求10000以內的完數。 * 完數即:一個數等於它的不同因子的和 * 如6=1+2+3.8!=1+2+4 * xtfggef 2012/5/16 */ #include<iostream> #include<fst
資料結構基礎------1.線性表之單鏈表的建立與輸出方法(Java版)
基礎知識: 線性表(linear list),是其組成元素間具有線性關係的一種線性結構。 線性表有 ①順序儲存結構(sequential storage structure) 順序儲存結構可以簡單的理解利用為 陣列 的形式來進行儲存資料。 ②鏈式儲存結構(ch
資料結構與演算法——線性表之順序表(JAVA語言實現 )
資料結構與演算法——線性表之順序表(JAVA語言實現 ) 線性表是由n個數據元素組成的優先序列。 線性表中每個元素都必須有相同的結構,線性表是線性結構中最常用而又最簡單的一種資料結構。線性表由儲存結構是否連續可分為順序表和連結串列。順序表指線性表中每個元素按順序依次儲存,線性表中邏
資料結構學習筆記——線性表之順序表(c語言實現)
1.概念 順序表即線性表的順序儲存結構 ,指的是用一段地址連續的儲存單元依次儲存線性表資料元素。線上性表中,每個資料元素的型別都相同,一般可以用一維陣列來實現順序儲存結構。 2.實現 (1)建立順序表的結構 利用c語言結構體來建立順序表的結構,順序表結構體中
【資料結構專題】線性表之單鏈表
對比了好幾本書,比較少涉及單鏈表的賦值,為了親自跑出其他功能,花了不少時間,畢竟是打基礎嘛,相信以後會越來熟練(你為什麼那麼熟練,明明是我先~)話不多說,下面是程式碼及實驗結果。 #include <cstdio> #include