日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

Java基础学习系列--(五)【迭代器,数据结构,List,Set ,TreeSet集合,Collections工具类】

發(fā)布時(shí)間:2024/3/26 java 60 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java基础学习系列--(五)【迭代器,数据结构,List,Set ,TreeSet集合,Collections工具类】 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

第一章 Iterator迭代器

1.1 Iterator接口

在程序開發(fā)中,經(jīng)常需要遍歷集合中的所有元素。針對這種需求,JDK專門提供了一個(gè)接口java.util.Iterator。

想要遍歷Collection集合,那么就要獲取該集合迭代器完成迭代操作,下面介紹一下獲取迭代器的方法:

  • public Iterator iterator(): 獲取集合對應(yīng)的迭代器,用來遍歷集合中的元素的。

下面介紹一下迭代的概念:

  • 迭代:即Collection集合元素的通用獲取方式。在取元素之前先要判斷集合中有沒有元素,如果有,就把這個(gè)元素取出來,繼續(xù)在判斷,如果還有就再取出出來。一直把集合中的所有元素全部取出。這種取出方式專業(yè)術(shù)語稱為迭代。

Iterator接口的常用方法如下:

  • public E next():返回迭代的下一個(gè)元素。
  • public boolean hasNext():如果仍有元素可以迭代,則返回 true。

接下來我們通過案例學(xué)習(xí)如何使用Iterator迭代集合中元素:

public class IteratorDemo {public static void main(String[] args) {// 使用多態(tài)方式 創(chuàng)建對象Collection<String> coll = new ArrayList<String>();// 添加元素到集合coll.add("串串星人");coll.add("吐槽星人");coll.add("汪星人");//遍歷//使用迭代器 遍歷 每個(gè)集合對象都有自己的迭代器Iterator<String> it = coll.iterator();// 泛型指的是 迭代出 元素的數(shù)據(jù)類型while(it.hasNext()){ //判斷是否有迭代元素String s = it.next();//獲取迭代出的元素System.out.println(s);}} }

tips:

  • 在進(jìn)行集合元素獲取時(shí),如果集合中已經(jīng)沒有元素了,還繼續(xù)使用迭代器的next方法,將會(huì)拋出java.util.NoSuchElementException沒有集合元素異常。
  • 在進(jìn)行集合元素獲取時(shí),如果添加或移除集合中的元素 , 將無法繼續(xù)迭代 , 將會(huì)拋出ConcurrentModificationException并發(fā)修改異常.
  • 1.2 迭代器的實(shí)現(xiàn)原理

    我們在之前案例已經(jīng)完成了Iterator遍歷集合的整個(gè)過程。當(dāng)遍歷集合時(shí),首先通過調(diào)用t集合的iterator()方法獲得迭代器對象,然后使用hashNext()方法判斷集合中是否存在下一個(gè)元素,如果存在,則調(diào)用next()方法將元素取出,否則說明已到達(dá)了集合末尾,停止遍歷元素。

    Iterator迭代器對象在遍歷集合時(shí),內(nèi)部采用指針的方式來跟蹤集合中的元素,為了讓初學(xué)者能更好地理解迭代器的工作原理,接下來通過一個(gè)圖例來演示Iterator對象迭代元素的過程:

    在調(diào)用Iterator的next方法之前,迭代器的索引位于第一個(gè)元素之前,不指向任何元素,當(dāng)?shù)谝淮握{(diào)用迭代器的next方法后,迭代器的索引會(huì)向后移動(dòng)一位,指向第一個(gè)元素并將該元素返回,當(dāng)再次調(diào)用next方法時(shí),迭代器的索引會(huì)指向第二個(gè)元素并將該元素返回,依此類推,直到hasNext方法返回false,表示到達(dá)了集合的末尾,終止對元素的遍歷。

    第二章 數(shù)據(jù)結(jié)構(gòu)

    2.1 數(shù)據(jù)結(jié)構(gòu)介紹

    數(shù)據(jù)結(jié)構(gòu) : 數(shù)據(jù)用什么樣的方式組合在一起。

    2.2 常見數(shù)據(jù)結(jié)構(gòu)

    數(shù)據(jù)存儲(chǔ)的常用結(jié)構(gòu)有:棧、隊(duì)列、數(shù)組、鏈表和紅黑樹。我們分別來了解一下:

    • stack,又稱堆棧,它是運(yùn)算受限的線性表,其限制是僅允許在標(biāo)的一端進(jìn)行插入和刪除操作,不允許在其他任何位置進(jìn)行添加、查找、刪除等操作。

    簡單的說:采用該結(jié)構(gòu)的集合,對元素的存取有如下的特點(diǎn)

    • 先進(jìn)后出(即,存進(jìn)去的元素,要在后它后面的元素依次取出后,才能取出該元素)。例如,子彈壓進(jìn)彈夾,先壓進(jìn)去的子彈在下面,后壓進(jìn)去的子彈在上面,當(dāng)開槍時(shí),先彈出上面的子彈,然后才能彈出下面的子彈。
    • 棧的入口、出口的都是棧的頂端位置。

    這里兩個(gè)名詞需要注意:

    • 壓棧:就是存元素。即,把元素存儲(chǔ)到棧的頂端位置,棧中已有元素依次向棧底方向移動(dòng)一個(gè)位置。
    • 彈棧:就是取元素。即,把棧的頂端位置元素取出,棧中已有元素依次向棧頂方向移動(dòng)一個(gè)位置。

    隊(duì)列

    • 隊(duì)列queue,簡稱隊(duì),它同堆棧一樣,也是一種運(yùn)算受限的線性表,其限制是僅允許在表的一端進(jìn)行插入,而在表的另一端進(jìn)行刪除。

    簡單的說,采用該結(jié)構(gòu)的集合,對元素的存取有如下的特點(diǎn):

    • 先進(jìn)先出(即,存進(jìn)去的元素,要在后它前面的元素依次取出后,才能取出該元素)。例如,小火車過山洞,車頭先進(jìn)去,車尾后進(jìn)去;車頭先出來,車尾后出來。
    • 隊(duì)列的入口、出口各占一側(cè)。例如,下圖中的左側(cè)為入口,右側(cè)為出口。

    數(shù)組

    • 數(shù)組:Array,是有序的元素序列,數(shù)組是在內(nèi)存中開辟一段連續(xù)的空間,并在此空間存放元素。就像是一排出租屋,有100個(gè)房間,從001到100每個(gè)房間都有固定編號,通過編號就可以快速找到租房子的人。

    簡單的說,采用該結(jié)構(gòu)的集合,對元素的存取有如下的特點(diǎn):

    • 查找元素快:通過索引,可以快速訪問指定位置的元素

    • 增刪元素慢

    • 指定索引位置增加元素:需要?jiǎng)?chuàng)建一個(gè)新數(shù)組,將指定新元素存儲(chǔ)在指定索引位置,再把原數(shù)組元素根據(jù)索引,復(fù)制到新數(shù)組對應(yīng)索引的位置。如下圖

    • **指定索引位置刪除元素:**需要?jiǎng)?chuàng)建一個(gè)新數(shù)組,把原數(shù)組元素根據(jù)索引,復(fù)制到新數(shù)組對應(yīng)索引的位置,原數(shù)組中指定索引位置元素不復(fù)制到新數(shù)組中。如下圖

    鏈表

    • 鏈表:linked list,由一系列結(jié)點(diǎn)node(鏈表中每一個(gè)元素稱為結(jié)點(diǎn))組成,結(jié)點(diǎn)可以在運(yùn)行時(shí)i動(dòng)態(tài)生成。每個(gè)結(jié)點(diǎn)包括兩個(gè)部分:一個(gè)是存儲(chǔ)數(shù)據(jù)元素的數(shù)據(jù)域,另一個(gè)是存儲(chǔ)下一個(gè)結(jié)點(diǎn)地址的指針域。我們常說的鏈表結(jié)構(gòu)有單向鏈表與雙向鏈表,那么這里給大家介紹的是單向鏈表

    簡單的說,采用該結(jié)構(gòu)的集合,對元素的存取有如下的特點(diǎn):

    • 多個(gè)結(jié)點(diǎn)之間,通過地址進(jìn)行連接。例如,多個(gè)人手拉手,每個(gè)人使用自己的右手拉住下個(gè)人的左手,依次類推,這樣多個(gè)人就連在一起了。

    • 查找元素慢:想查找某個(gè)元素,需要通過連接的節(jié)點(diǎn),依次向后查找指定元素

    • 增刪元素快:

      樹是有很多節(jié)點(diǎn)組成的

    2.3. 樹基本結(jié)構(gòu)介紹

    樹具有的特點(diǎn):

  • 每一個(gè)節(jié)點(diǎn)有零個(gè)或者多個(gè)子節(jié)點(diǎn)
  • 沒有父節(jié)點(diǎn)的節(jié)點(diǎn)稱之為根節(jié)點(diǎn),一個(gè)樹最多有一個(gè)根節(jié)點(diǎn)。
  • 每一個(gè)非根節(jié)點(diǎn)有且只有一個(gè)父節(jié)點(diǎn)
  • 名詞含義
    節(jié)點(diǎn)指樹中的一個(gè)元素
    節(jié)點(diǎn)的度節(jié)點(diǎn)擁有的子樹的個(gè)數(shù),二叉樹的度不大于2
    葉子節(jié)點(diǎn)度為0的節(jié)點(diǎn),也稱之為終端結(jié)點(diǎn)
    高度葉子結(jié)點(diǎn)的高度為1,葉子結(jié)點(diǎn)的父節(jié)點(diǎn)高度為2,以此類推,根節(jié)點(diǎn)的高度最高
    根節(jié)點(diǎn)在第一層,以此類推
    父節(jié)點(diǎn)若一個(gè)節(jié)點(diǎn)含有子節(jié)點(diǎn),則這個(gè)節(jié)點(diǎn)稱之為其子節(jié)點(diǎn)的父節(jié)點(diǎn)
    子節(jié)點(diǎn)子節(jié)點(diǎn)是父節(jié)點(diǎn)的下一層節(jié)點(diǎn)
    兄弟節(jié)點(diǎn)擁有共同父節(jié)點(diǎn)的節(jié)點(diǎn)互稱為兄弟節(jié)點(diǎn)

    二叉樹

    如果樹中的每個(gè)節(jié)點(diǎn)的子節(jié)點(diǎn)的個(gè)數(shù)不超過2,那么該樹就是一個(gè)二叉樹。

    二叉查找樹/二叉排序樹

    二叉查找樹的特點(diǎn):

  • 左子樹上所有的節(jié)點(diǎn)的值均小于等于他的根節(jié)點(diǎn)的值
  • 右子樹上所有的節(jié)點(diǎn)值均大于或者等于他的根節(jié)點(diǎn)的值
  • 每一個(gè)子節(jié)點(diǎn)最多有兩個(gè)子樹
  • 案例演示(20,18,23,22,17,24,19)數(shù)據(jù)的存儲(chǔ)過程;

    增刪改查的性能都很高!!!

    遍歷獲取元素的時(shí)候可以按照"左中右"的順序進(jìn)行遍歷;

    注意:二叉查找樹存在的問題:會(huì)出現(xiàn)"瘸子"的現(xiàn)象,影響查詢效率。

    平衡二叉樹

    (基于查找二叉樹,但是讓樹不要太高,盡量讓樹的元素均衡分布。這樣綜合性能就高了)

    概述

    為了避免出現(xiàn)"瘸子"的現(xiàn)象,減少樹的高度,提高我們的搜素效率,又存在一種樹的結(jié)構(gòu):“平衡二叉樹”

    規(guī)則:它的左右兩個(gè)子樹的高度差的絕對值不超過1,并且左右兩個(gè)子樹都是一棵平衡二叉樹

    如下圖所示:

    如下圖所示,左圖是一棵平衡二叉樹,根節(jié)點(diǎn)10,左右兩子樹的高度差是1,而右圖,雖然根節(jié)點(diǎn)左右兩子樹高度差是0,但是右子樹15的左右子樹高度差為2,不符合定義,

    所以右圖不是一棵平衡二叉樹。

    旋轉(zhuǎn)

    在構(gòu)建一棵平衡二叉樹的過程中,當(dāng)有新的節(jié)點(diǎn)要插入時(shí),檢查是否因插入后而破壞了樹的平衡,如果是,則需要做旋轉(zhuǎn)去改變樹的結(jié)構(gòu)。

    左旋:

    左旋就是將節(jié)點(diǎn)的右支往左拉,右子節(jié)點(diǎn)變成父節(jié)點(diǎn),并把晉升之后多余的左子節(jié)點(diǎn)出讓給降級節(jié)點(diǎn)的右子節(jié)點(diǎn);


    右旋:

    將節(jié)點(diǎn)的左支往右拉,左子節(jié)點(diǎn)變成了父節(jié)點(diǎn),并把晉升之后多余的右子節(jié)點(diǎn)出讓給降級節(jié)點(diǎn)的左子節(jié)點(diǎn)

    舉個(gè)例子,像上圖是否平衡二叉樹的圖里面,左圖在沒插入前"19"節(jié)點(diǎn)前,該樹還是平衡二叉樹,但是在插入"19"后,導(dǎo)致了"15"的左右子樹失去了"平衡",

    所以此時(shí)可以將"15"節(jié)點(diǎn)進(jìn)行左旋,讓"15"自身把節(jié)點(diǎn)出讓給"17"作為"17"的左樹,使得"17"節(jié)點(diǎn)左右子樹平衡,而"15"節(jié)點(diǎn)沒有子樹,左右也平衡了。如下圖,

    由于在構(gòu)建平衡二叉樹的時(shí)候,當(dāng)有新節(jié)點(diǎn)插入時(shí),都會(huì)判斷插入后時(shí)候平衡,這說明了插入新節(jié)點(diǎn)前,都是平衡的,也即高度差絕對值不會(huì)超過1。當(dāng)新節(jié)點(diǎn)插入后,

    有可能會(huì)有導(dǎo)致樹不平衡,這時(shí)候就需要進(jìn)行調(diào)整,而可能出現(xiàn)的情況就有4種,分別稱作左左,左右,右左,右右

    左左

    左左即為在原來平衡的二叉樹上,在節(jié)點(diǎn)的左子樹的左子樹下,有新節(jié)點(diǎn)插入,導(dǎo)致節(jié)點(diǎn)的左右子樹的高度差為2,如下即為"10"節(jié)點(diǎn)的左子樹"7",的左子樹"4",插入了節(jié)點(diǎn)"5"或"3"導(dǎo)致失衡。

    左左調(diào)整其實(shí)比較簡單,只需要對節(jié)點(diǎn)進(jìn)行右旋即可,如下圖,對節(jié)點(diǎn)"10"進(jìn)行右旋,

    左右

    左右即為在原來平衡的二叉樹上,在節(jié)點(diǎn)的左子樹的右子樹下,有新節(jié)點(diǎn)插入,導(dǎo)致節(jié)點(diǎn)的左右子樹的高度差為2,如上即為"11"節(jié)點(diǎn)的左子樹"7",的右子樹"9",

    插入了節(jié)點(diǎn)"10"或"8"導(dǎo)致失衡。

    左右的調(diào)整就不能像左左一樣,進(jìn)行一次旋轉(zhuǎn)就完成調(diào)整。我們不妨先試著讓左右像左左一樣對"11"節(jié)點(diǎn)進(jìn)行右旋,結(jié)果圖如下,右圖的二叉樹依然不平衡,而右圖就是接下來要

    講的右左,即左右跟右左互為鏡像,左左跟右右也互為鏡像。


    左右這種情況,進(jìn)行一次旋轉(zhuǎn)是不能滿足我們的條件的,正確的調(diào)整方式是,將左右進(jìn)行第一次旋轉(zhuǎn),將左右先調(diào)整成左左,然后再對左左進(jìn)行調(diào)整,從而使得二叉樹平衡。

    即先對上圖的節(jié)點(diǎn)"7"進(jìn)行左旋,使得二叉樹變成了左左,之后再對"11"節(jié)點(diǎn)進(jìn)行右旋,此時(shí)二叉樹就調(diào)整完成,如下圖:

    右左

    右左即為在原來平衡的二叉樹上,在節(jié)點(diǎn)的右子樹的左子樹下,有新節(jié)點(diǎn)插入,導(dǎo)致節(jié)點(diǎn)的左右子樹的高度差為2,如上即為"11"節(jié)點(diǎn)的右子樹"15",的左子樹"13",

    插入了節(jié)點(diǎn)"12"或"14"導(dǎo)致失衡。

    前面也說了,右左跟左右其實(shí)互為鏡像,所以調(diào)整過程就反過來,先對節(jié)點(diǎn)"15"進(jìn)行右旋,使得二叉樹變成右右,之后再對"11"節(jié)點(diǎn)進(jìn)行左旋,此時(shí)二叉樹就調(diào)整完成,如下圖:

    右右

    右右即為在原來平衡的二叉樹上,在節(jié)點(diǎn)的右子樹的右子樹下,有新節(jié)點(diǎn)插入,導(dǎo)致節(jié)點(diǎn)的左右子樹的高度差為2,如下即為"11"節(jié)點(diǎn)的右子樹"13",的左子樹"15",插入了節(jié)點(diǎn)

    "14"或"19"導(dǎo)致失衡。

    右右只需對節(jié)點(diǎn)進(jìn)行一次左旋即可調(diào)整平衡,如下圖,對"11"節(jié)點(diǎn)進(jìn)行左旋。

    紅黑樹

    就是平衡的二叉查找樹!!

    概述

    紅黑樹是一種自平衡的二叉查找樹,是計(jì)算機(jī)科學(xué)中用到的一種數(shù)據(jù)結(jié)構(gòu),它是在1972年由Rudolf Bayer發(fā)明的,當(dāng)時(shí)被稱之為平衡二叉B樹,后來,在1978年被

    Leoj.Guibas和Robert Sedgewick修改為如今的"紅黑樹"。它是一種特殊的二叉查找樹,紅黑樹的每一個(gè)節(jié)點(diǎn)上都有存儲(chǔ)位表示節(jié)點(diǎn)的顏色,可以是紅或者黑;

    紅黑樹不是高度平衡的,它的平衡是通過"紅黑樹的特性"進(jìn)行實(shí)現(xiàn)的;

    紅黑樹的特性:

  • 每一個(gè)節(jié)點(diǎn)或是紅色的,或者是黑色的。
  • 根節(jié)點(diǎn)必須是黑色
  • 每個(gè)葉節(jié)點(diǎn)(Nil)是黑色的;(如果一個(gè)節(jié)點(diǎn)沒有子節(jié)點(diǎn)或者父節(jié)點(diǎn),則該節(jié)點(diǎn)相應(yīng)的指針屬性值為Nil,這些Nil視為葉節(jié)點(diǎn))
  • 如果某一個(gè)節(jié)點(diǎn)是紅色,那么它的子節(jié)點(diǎn)必須是黑色(不能出現(xiàn)兩個(gè)紅色節(jié)點(diǎn)相連的情況)
  • 對每一個(gè)節(jié)點(diǎn),從該節(jié)點(diǎn)到其所有后代葉節(jié)點(diǎn)的簡單路徑上,均包含相同數(shù)目的黑色節(jié)點(diǎn);
  • 如下圖所示就是一個(gè)

    在進(jìn)行元素插入的時(shí)候,和之前一樣; 每一次插入完畢以后,使用黑色規(guī)則進(jìn)行校驗(yàn),如果不滿足紅黑規(guī)則,就需要通過變色,左旋和右旋來調(diào)整樹,使其滿足紅黑規(guī)則;

    第三章 List接口

    我們掌握了Collection接口的使用后,再來看看Collection接口中的子類,他們都具備那些特性呢?

    接下來,我們一起學(xué)習(xí)Collection中的常用幾個(gè)子類(java.util.List集合、java.util.Set集合)。

    3.1 List接口介紹

    java.util.List接口繼承自Collection接口,是單列集合的一個(gè)重要分支,習(xí)慣性地會(huì)將實(shí)現(xiàn)了List接口的對象稱為List集合。在List集合中允許出現(xiàn)重復(fù)的元素,所有的元素是以一種線性方式進(jìn)行存儲(chǔ)的,在程序中可以通過索引來訪問集合中的指定元素。另外,List集合還有一個(gè)特點(diǎn)就是元素有序,即元素的存入順序和取出順序一致。

    看完API,我們總結(jié)一下:

    List接口特點(diǎn):

  • 它是一個(gè)元素存取有序的集合。例如,存元素的順序是11、22、33。那么集合中,元素的存儲(chǔ)就是按照11、22、33的順序完成的)。
  • 它是一個(gè)帶有索引的集合,通過索引就可以精確的操作集合中的元素(與數(shù)組的索引是一個(gè)道理)。
  • 集合中可以有重復(fù)的元素,通過元素的equals方法,來比較是否為重復(fù)的元素。
  • tips:我們在基礎(chǔ)班的時(shí)候已經(jīng)學(xué)習(xí)過List接口的子類java.util.ArrayList類,該類中的方法都是來自List中定義。

    3.2 List接口中常用方法

    List作為Collection集合的子接口,不但繼承了Collection接口中的全部方法,而且還增加了一些根據(jù)元素索引來操作集合的特有方法,如下:

    • public void add(int index, E element): 將指定的元素,添加到該集合中的指定位置上。
    • public E get(int index):返回集合中指定位置的元素。
    • public E remove(int index): 移除列表中指定位置的元素, 返回的是被移除的元素。
    • public E set(int index, E element):用指定元素替換集合中指定位置的元素,返回值的更新前的元素。

    List集合特有的方法都是跟索引相關(guān),我們在基礎(chǔ)班都學(xué)習(xí)過。

    tips:我們之前學(xué)習(xí)Colletion體系的時(shí)候,發(fā)現(xiàn)List集合下有很多集合,它們的存儲(chǔ)結(jié)構(gòu)不同,這樣就導(dǎo)致了這些集合它們有各自的特點(diǎn),供我們在不同的環(huán)境下使用,那么常見的數(shù)據(jù)結(jié)構(gòu)有哪些呢?在下一章我們來介紹:

    3.3 ArrayList集合

    java.util.ArrayList集合數(shù)據(jù)存儲(chǔ)的結(jié)構(gòu)是數(shù)組結(jié)構(gòu)。元素增刪慢,查找快,由于日常開發(fā)中使用最多的功能為查詢數(shù)據(jù)、遍歷數(shù)據(jù),所以ArrayList是最常用的集合。

    許多程序員開發(fā)時(shí)非常隨意地使用ArrayList完成任何需求,并不嚴(yán)謹(jǐn),這種用法是不提倡的。

    3.4 LinkedList集合

    java.util.LinkedList集合數(shù)據(jù)存儲(chǔ)的結(jié)構(gòu)是鏈表結(jié)構(gòu)。方便元素添加、刪除的集合。

    LinkedList是一個(gè)雙向鏈表,那么雙向鏈表是什么樣子的呢,我們用個(gè)圖了解下

    實(shí)際開發(fā)中對一個(gè)集合元素的添加與刪除經(jīng)常涉及到首尾操作,而LinkedList提供了大量首尾操作的方法。這些方法我們作為了解即可

    • public void addFirst(E e):將指定元素插入此列表的開頭。
    • public void addLast(E e):將指定元素添加到此列表的結(jié)尾。
    • public E getFirst():返回此列表的第一個(gè)元素。
    • public E getLast():返回此列表的最后一個(gè)元素。
    • public E removeFirst():移除并返回此列表的第一個(gè)元素。
    • public E removeLast():移除并返回此列表的最后一個(gè)元素。
    • public E pop():從此列表所表示的堆棧處彈出一個(gè)元素。
    • public void push(E e):將元素推入此列表所表示的堆棧。
    • public boolean isEmpty():如果列表不包含元素,則返回true。

    LinkedList是List的子類,List中的方法LinkedList都是可以使用,這里就不做詳細(xì)介紹,我們只需要了解LinkedList的特有方法即可。在開發(fā)時(shí),LinkedList集合也可以作為堆棧,隊(duì)列的結(jié)構(gòu)使用。

    public class Demo04LinkedList {public static void main(String[] args) {method4();}/** void push(E e): 壓入。把元素添加到集合的第一個(gè)位置。* E pop(): 彈出。把第一個(gè)元素刪除,然后返回這個(gè)元素。*/public static void method4() {//創(chuàng)建LinkedList對象LinkedList<String> list = new LinkedList<>();//添加元素list.add("達(dá)爾文");list.add("達(dá)芬奇");list.add("達(dá)爾優(yōu)");System.out.println("list:" + list);//調(diào)用push在集合的第一個(gè)位置添加元素//list.push("愛迪生");//System.out.println("list:" + list);//[愛迪生, 達(dá)爾文, 達(dá)芬奇, 達(dá)爾優(yōu)]//E pop(): 彈出。把第一個(gè)元素刪除,然后返回這個(gè)元素。String value = list.pop();System.out.println("value:" + value);//達(dá)爾文System.out.println("list:" + list);//[達(dá)芬奇,達(dá)爾優(yōu)]}/** E removeFirst():刪除第一個(gè)元素* E removeLast():刪除最后一個(gè)元素。*/public static void method3() {//創(chuàng)建LinkedList對象LinkedList<String> list = new LinkedList<>();//添加元素list.add("達(dá)爾文");list.add("達(dá)芬奇");list.add("達(dá)爾優(yōu)");//刪除集合的第一個(gè)元素 // String value = list.removeFirst(); // System.out.println("value:" + value);//達(dá)爾文 // System.out.println("list:" + list);//[達(dá)芬奇,達(dá)爾優(yōu)]//刪除最后一個(gè)元素String value = list.removeLast();System.out.println("value:" + value);//達(dá)爾優(yōu)System.out.println("list:" + list);//[達(dá)爾文, 達(dá)芬奇]}/** E getFirst(): 獲取集合中的第一個(gè)元素* E getLast(): 獲取集合中的最后一個(gè)元素*/public static void method2() {//創(chuàng)建LinkedList對象LinkedList<String> list = new LinkedList<>();//添加元素list.add("達(dá)爾文");list.add("達(dá)芬奇");list.add("達(dá)爾優(yōu)");System.out.println("list:" + list);//獲取集合中的第一個(gè)元素System.out.println("第一個(gè)元素是:" + list.getFirst());//獲取集合中的最后一個(gè)元素怒System.out.println("最后一個(gè)元素是:" + list.getLast());} /** void addFirst(E e): 在集合的開頭位置添加元素。* void addLast(E e): 在集合的尾部添加元素。*/public static void method1() {//創(chuàng)建LinkedList對象LinkedList<String> list = new LinkedList<>();//添加元素list.add("達(dá)爾文");list.add("達(dá)芬奇");list.add("達(dá)爾優(yōu)");//打印這個(gè)集合System.out.println("list:" + list);//[達(dá)爾文, 達(dá)芬奇, 達(dá)爾優(yōu)]//調(diào)用addFirst添加元素list.addFirst("曹操");System.out.println("list:" + list);//[曹操, 達(dá)爾文, 達(dá)芬奇, 達(dá)爾優(yōu)]//調(diào)用addLast方法添加元素list.addLast("大喬");System.out.println("list:" + list);//[曹操, 達(dá)爾文, 達(dá)芬奇, 達(dá)爾優(yōu), 大喬]} }

    第四章 Set接口

    java.util.Set接口和java.util.List接口一樣,同樣繼承自Collection接口,它與Collection接口中的方法基本一致,并沒有對Collection接口進(jìn)行功能上的擴(kuò)充,只是比Collection接口更加嚴(yán)格了。與List接口不同的是,Set接口都會(huì)以某種規(guī)則保證存入的元素不出現(xiàn)重復(fù)。

    Set集合有多個(gè)子類,這里我們介紹其中的java.util.HashSet、java.util.LinkedHashSet、java.util.TreeSet這兩個(gè)集合。

    tips:Set集合取出元素的方式可以采用:迭代器、增強(qiáng)for。

    4.1 HashSet集合介紹

    java.util.HashSet是Set接口的一個(gè)實(shí)現(xiàn)類,它所存儲(chǔ)的元素是不可重復(fù)的,并且元素都是無序的(即存取順序不能保證不一致)。java.util.HashSet底層的實(shí)現(xiàn)其實(shí)是一個(gè)java.util.HashMap支持,由于我們暫時(shí)還未學(xué)習(xí),先做了解。

    HashSet是根據(jù)對象的哈希值來確定元素在集合中的存儲(chǔ)位置,因此具有良好的存儲(chǔ)和查找性能。保證元素唯一性的方式依賴于:hashCode與equals方法。

    我們先來使用一下Set集合存儲(chǔ),看下現(xiàn)象,再進(jìn)行原理的講解:

    public class HashSetDemo {public static void main(String[] args) {//創(chuàng)建 Set集合HashSet<String> set = new HashSet<String>();//添加元素set.add(new String("cba"));set.add("abc");set.add("bac"); set.add("cba"); //遍歷for (String name : set) {System.out.println(name);}} }

    輸出結(jié)果如下,說明集合中不能存儲(chǔ)重復(fù)元素:

    cba abc bac

    tips:根據(jù)結(jié)果我們發(fā)現(xiàn)字符串"cba"只存儲(chǔ)了一個(gè),也就是說重復(fù)的元素set集合不存儲(chǔ)。

    4.2 HashSet集合存儲(chǔ)數(shù)據(jù)的結(jié)構(gòu)(哈希表)

    什么是哈希表呢?

    JDK1.8之前,哈希表底層采用數(shù)組+鏈表實(shí)現(xiàn),即使用數(shù)組處理沖突,同一hash值的鏈表都存儲(chǔ)在一個(gè)數(shù)組里。但是當(dāng)位于一個(gè)桶中的元素較多,即hash值相等的元素較多時(shí),通過key值依次查找的效率較低。而JDK1.8中,哈希表存儲(chǔ)采用數(shù)組+鏈表+紅黑樹實(shí)現(xiàn),當(dāng)鏈表長度超過閾值(8)時(shí),將鏈表轉(zhuǎn)換為紅黑樹,這樣大大減少了查找時(shí)間。

    簡單的來說,哈希表是由數(shù)組+鏈表+紅黑樹(JDK1.8增加了紅黑樹部分)實(shí)現(xiàn)的,如下圖所示。

    看到這張圖就有人要問了,這個(gè)是怎么存儲(chǔ)的呢?

    為了方便大家的理解我們結(jié)合一個(gè)存儲(chǔ)流程圖來說明一下:

    總而言之,JDK1.8引入紅黑樹大程度優(yōu)化了HashMap的性能,那么對于我們來講保證HashSet集合元素的唯一,其實(shí)就是根據(jù)對象的hashCode和equals方法來決定的。如果我們往集合中存放自定義的對象,那么保證其唯一,就必須復(fù)寫hashCode和equals方法建立屬于當(dāng)前對象的比較方式。

    4.3 HashSet存儲(chǔ)自定義類型元素

    給HashSet中存放自定義類型元素時(shí),需要重寫對象中的hashCode和equals方法,建立自己的比較方式,才能保證HashSet集合中的對象唯一.

    創(chuàng)建自定義Student類:

    public class Student {private String name;private int age;//get/set@Overridepublic boolean equals(Object o) {if (this == o)return true;if (o == null || getClass() != o.getClass())return false;Student student = (Student) o;return age == student.age &&Objects.equals(name, student.name);}@Overridepublic int hashCode() {return Objects.hash(name, age);} }

    創(chuàng)建測試類:

    public class HashSetDemo2 {public static void main(String[] args) {//創(chuàng)建集合對象 該集合中存儲(chǔ) Student類型對象HashSet<Student> stuSet = new HashSet<Student>();//存儲(chǔ) Student stu = new Student("于謙", 43);stuSet.add(stu);stuSet.add(new Student("郭德綱", 44));stuSet.add(new Student("于謙", 43));stuSet.add(new Student("郭麒麟", 23));stuSet.add(stu);for (Student stu2 : stuSet) {System.out.println(stu2);}} } 執(zhí)行結(jié)果: Student [name=郭德綱, age=44] Student [name=于謙, age=43] Student [name=郭麒麟, age=23]

    4.4 LinkedHashSet

    我們知道HashSet保證元素唯一,可是元素存放進(jìn)去是沒有順序的,那么我們要保證有序,怎么辦呢?

    在HashSet下面有一個(gè)子類java.util.LinkedHashSet,它是鏈表和哈希表組合的一個(gè)數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)。

    演示代碼如下:

    public class LinkedHashSetDemo {public static void main(String[] args) {Set<String> set = new LinkedHashSet<String>();set.add("bbb");set.add("aaa");set.add("abc");set.add("bbc");Iterator<String> it = set.iterator();while (it.hasNext()) {System.out.println(it.next());}} } 結(jié)果:bbbaaaabcbbc

    4.5 TreeSet集合

    1. 特點(diǎn)

    TreeSet集合是Set接口的一個(gè)實(shí)現(xiàn)類,底層依賴于TreeMap,是一種基于紅黑樹的實(shí)現(xiàn),其特點(diǎn)為:

  • 元素唯一
  • 元素沒有索引
  • 使用元素的自然順序?qū)υ剡M(jìn)行排序,或者根據(jù)創(chuàng)建 TreeSet 時(shí)提供的 Comparator 比較器
    進(jìn)行排序,具體取決于使用的構(gòu)造方法:
  • public TreeSet(): 根據(jù)其元素的自然排序進(jìn)行排序 public TreeSet(Comparator<E> comparator): 根據(jù)指定的比較器進(jìn)行排序

    2. 演示

    案例演示自然排序(20,18,23,22,17,24,19):

    public static void main(String[] args) {//無參構(gòu)造,默認(rèn)使用元素的自然順序進(jìn)行排序TreeSet<Integer> set = new TreeSet<Integer>();set.add(20);set.add(18);set.add(23);set.add(22);set.add(17);set.add(24);set.add(19);System.out.println(set); }控制臺(tái)的輸出結(jié)果為: [17, 18, 19, 20, 22, 23, 24]

    案例演示比較器排序(20,18,23,22,17,24,19):

    public static void main(String[] args) {//有參構(gòu)造,傳入比較器,使用比較器對元素進(jìn)行排序TreeSet<Integer> set = new TreeSet<Integer>(new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {//元素前 - 元素后 : 升序//元素后 - 元素前 : 降序return o2 - o1;}});set.add(20);set.add(18);set.add(23);set.add(22);set.add(17);set.add(24);set.add(19);System.out.println(set); }控制臺(tái)的輸出結(jié)果為: [24, 23, 22, 20, 19, 18, 17]

    第五章 Collections類

    5.1 Collections常用功能

    • java.utils.Collections是集合工具類,用來對集合進(jìn)行操作。

      常用方法如下:

    • public static void shuffle(List<?> list):打亂集合順序。

    • public static <T> void sort(List<T> list):將集合中元素按照默認(rèn)規(guī)則排序。

    • public static <T> void sort(List<T> list,Comparator<? super T> ):將集合中元素按照指定規(guī)則排序。

    代碼演示:

    public class CollectionsDemo {public static void main(String[] args) {ArrayList<Integer> list = new ArrayList<Integer>();list.add(100);list.add(300);list.add(200);list.add(50);//排序方法 Collections.sort(list);System.out.println(list);} } 結(jié)果: [50,100, 200, 300]

    我們的集合按照默認(rèn)的自然順序進(jìn)行了排列,如果想要指定順序那該怎么辦呢?

    5.2 Comparator比較器

    創(chuàng)建一個(gè)學(xué)生類,存儲(chǔ)到ArrayList集合中完成指定排序操作。

    Student 類

    public class Student{private String name;private int age;//構(gòu)造方法//get/set//toString }

    測試類:

    public class Demo {public static void main(String[] args) {// 創(chuàng)建四個(gè)學(xué)生對象 存儲(chǔ)到集合中ArrayList<Student> list = new ArrayList<Student>();list.add(new Student("rose",18));list.add(new Student("jack",16));list.add(new Student("abc",20));Collections.sort(list, new Comparator<Student>() {@Overridepublic int compare(Student o1, Student o2) {return o1.getAge()-o2.getAge();//以學(xué)生的年齡升序}});for (Student student : list) {System.out.println(student);}} } Student{name='jack', age=16} Student{name='rose', age=18} Student{name='abc', age=20}

    5.3 可變參數(shù)

    JDK1.5之后,如果我們定義一個(gè)方法需要接受多個(gè)參數(shù),并且多個(gè)參數(shù)類型一致,我們可以對其簡化.

    格式:

    修飾符 返回值類型 方法名(參數(shù)類型... 形參名){ }

    代碼演示:

    public class ChangeArgs {public static void main(String[] args) {int sum = getSum(6, 7, 2, 12, 2121);System.out.println(sum);}public static int getSum(int... arr) {int sum = 0;for (int a : arr) {sum += a;}return sum;} }

    注意:

    ? 1.一個(gè)方法只能有一個(gè)可變參數(shù)

    ? 2.如果方法中有多個(gè)參數(shù),可變參數(shù)要放到最后。

    應(yīng)用場景: Collections

    ? 在Collections中也提供了添加一些元素方法:

    ? public static <T> boolean addAll(Collection<T> c, T... elements):往集合中添加一些元素。

    代碼演示:

    public class CollectionsDemo {public static void main(String[] args) {ArrayList<Integer> list = new ArrayList<Integer>();//原來寫法//list.add(12);//list.add(14);//list.add(15);//list.add(1000);//采用工具類 完成 往集合中添加元素 Collections.addAll(list, 5, 222, 12);System.out.println(list); }

    第六章 集合綜合案例

    6.1 案例介紹

    按照斗地主的規(guī)則,完成洗牌發(fā)牌的動(dòng)作。
    具體規(guī)則:

    使用54張牌打亂順序,三個(gè)玩家參與游戲,三人交替摸牌,每人17張牌,最后三張留作底牌。

    6.2 案例分析

    • 準(zhǔn)備牌:

      牌可以設(shè)計(jì)為一個(gè)ArrayList,每個(gè)字符串為一張牌。
      每張牌由花色數(shù)字兩部分組成,我們可以使用花色集合與數(shù)字集合嵌套迭代完成每張牌的組裝。
      牌由Collections類的shuffle方法進(jìn)行隨機(jī)排序。

    • 發(fā)牌

      將每個(gè)人以及底牌設(shè)計(jì)為ArrayList,將最后3張牌直接存放于底牌,剩余牌通過對3取模依次發(fā)牌。

    • 看牌

      直接打印每個(gè)集合。

    6.3 代碼實(shí)現(xiàn)

  • Poker.java
  • public class Poker {private String name;public Poker() {}public Poker(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "{" + name + "}";} }

    2 測試類

    public class Demo12 {public static void main(String[] args) {// 創(chuàng)建一個(gè)ArrayList用于存放一副牌ArrayList<Poker> pokers = new ArrayList<>();pokers.add(new Poker("大王", ""));pokers.add(new Poker("小王", ""));String[] colors = new String[] {"?", "?", "?", "?"};String[] numbers = new String[] {"2", "A", "K", "Q", "J", "10", "9", "8", "7", "6", "5", "4", "3"};// 組合牌, 嵌套循環(huán)的流程:外循環(huán)一次,內(nèi)循環(huán)所有次// 2.使用嵌套循環(huán)生成一副牌for (String n : numbers) {// "2", "A"for (String c : colors) {// "?", "?", "?", "?"Poker p = new Poker(c, n);// 3.將54張牌放到集合pokers.add(p);}}// 打印 // System.out.println(pokers);// 洗牌: Collections,集合工具類// static void shuffle?(List<?> list) 將集合中元素的順序打亂Collections.shuffle(pokers);System.out.println("洗牌后:" + pokers);// 發(fā)牌// 1.創(chuàng)建3個(gè)玩家集合,創(chuàng)建底牌集合ArrayList<Poker> player01 = new ArrayList<>();ArrayList<Poker> player02 = new ArrayList<>();ArrayList<Poker> player03 = new ArrayList<>();ArrayList<Poker> diPai = new ArrayList<>();// 2.遍歷牌的集合// 0 1 2 3 4 5 6 7 8 9 10 ...51 52 53// pokers = [?5], [?4], [?8], [?A], [?7], [?2], [?6], [?J], [?A], [?7], [?6], [?5], [?7], [?10]// 玩家1: 索引0,3,6 索引 % 3 == 0// 玩家2: 索引1,4,7 索引 % 3 == 1// 玩家3: 索引2,5,8 索引 % 3 == 2// 3.根據(jù)索引將牌發(fā)給不同的玩家for (int i = 0; i < pokers.size(); i++) {// i表示索引,poker就是i索引對應(yīng)的pokerPoker poker = pokers.get(i);if (i >= 51) { // 最后3張給底牌diPai.add(poker);} else if (i % 3 == 0) { // 玩家1player01.add(poker);} else if (i % 3 == 1) { // 玩家2player02.add(poker);} else if (i % 3 == 2) { // 玩家3player03.add(poker);}}// 看牌System.out.println("玩家1: " + player01);System.out.println("玩家2: " + player02);System.out.println("玩家3: " + player03);System.out.println("底牌: " + diPai);// 還要?jiǎng)?chuàng)建一副牌// 創(chuàng)建一個(gè)ArrayList用于存放一副牌} }

    總結(jié)

    以上是生活随笔為你收集整理的Java基础学习系列--(五)【迭代器,数据结构,List,Set ,TreeSet集合,Collections工具类】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。