2023年3月

=== 注释:此人博客对很多个数据结构类都有讲解-并加以实例

Java API —— ArrayList类 & Vector类 & LinkList类
Java API —— BigDecimal类
Java API —— BigInteger类
Java API —— Calendar类
Java API —— DateFormat类
Java API —— Date类
Java API —— HashMap类 & LinkedHashMap类
Java API —— JDK5新特性
Java API —— List接口&ListIterator接口
Java API —— Map接口
Java API —— Math类
Java API —— Pattern类
Java API —— Random类
Java API —— Set接口 & HashSet类 & LinkedHashSet类
Java API —— System类
Java API —— TreeMap类
Java API —— TreeSet类
Java API —— 泛型
Java API ——Collection集合类 & Iterator接口
List应用举例

==========================

转:面试常考的数据结构Java实现 - 我是一名老菜鸟 - 博客园--其实是讲二叉树和排序--如果原文还在请调整到原文看

http://www.cnblogs.com/yangyquin/p/4921664.html

=========以下是文字复制,很长 请耐心看

1、线性表

2、线性链表

3、栈

4、队列

5、串

6、数组

7、广义表

8、树和二叉树

二叉树:
每个结点至多只有两棵子树(即二叉树中不存在度大于2的结点),并且,二叉树的子树
有左右之分
,其
次序不能任意颠倒

二叉树的性质:

性质1

在二叉树的

i


至多有
2
i-1

结点。

性质2
:深度为
k
的二叉树
至多有
2
k-1个结点(k>=1)。

性质3

对任何一颗二叉树T,如果其
终端结点数为
n
0

度为2的结点数为n2


n
0=n2
+1。

设n1为二叉树T中度为1的节点数,因为二叉树中所有结点的度均小于或等于2,所以其结点总数为:n=n0+n1+n2;再看二叉树中的分支数,除了根节点外,其余结点都有一个分支进入,设B为分支数,则n=B+1;由于这些分支是由度为1或2的结点射出的,所以有B=n1+2*n2,于是得n=n1+2n2+1,所以n0=n2+1

满二叉树:
一棵
深度为k且有2
k
-1
个结点
的二叉树。
每一层上的结点数都是最大结点数

完全二叉树:
如果对满二叉树的结点进行
连续编号
,约定编号从根结点起,自上而下,自左至右。深度为k的,有n个结点的二叉树,
当且仅当其每一个结点都与深度为
k的满二叉树中编号从1至n的结点一一对应。

特点:(1)
叶子结点只可能在层次最大的两层上出现;
(2)对任一结点,若其右分支下的子孙的最大层次为h,则其左分支下的子孙的最大层次必为lh+1。

性质4

具有n个结点的完全二叉树的深度为log2n+1(2为下标,取log2n最小整数)。

性质5

如果对一棵有n个结点的完全二叉树(其深度为log2n+1)(取log2n最小整数)的结点按层序编号(从第1层到第log2n+1层,每层从左到右),则对任一结点i(1<=i<=n),有:

(1)如果i=1,则结点i是二叉树的根,无双亲;如果i>1,则其双亲PARENT(i)是结点i/2(取最小整数)。

(2)如果2i>n,则结点i无左孩子(结点i为叶子结点);否则其左孩子LCHILD(i)是结点2i。

(3)如果2i+1>n,则结点i无右孩子;否则其右孩子RCHILD(i)是结点2i+1。

最优二叉树(赫夫曼树)
:从树中一个结点到另一个结点之间的分支构成这两个结点之间的路径,路径上的分支数目称为路径长度。树的路径长度是从树根到每一个结点的路径长度之和。结点的带权路径长度为从该结点到树根之间的路径长度与结点上权的乘积。树的带权路径长度为树中所有叶子结点的带权路径长度之和。

二叉排序树:
或者是一棵空树;或者是具有下列性质的二叉树:(1)若它的左子树不空,则左子树上所有结点的值均小于它的根节点的值;(2)若它的右子树上所有结点的值均大于它的根节点的值;(3)它的左、右子树也分别为二叉排序树。

平衡二叉树:又称AVL
树。
它或者是一棵空树,或者是具有下列性质的二叉树。它的左子树和右子树都是平衡二叉树,
且左子树和右子树的深度只差的绝对值不超过
1
。若将二叉树上结点的平衡因子BF定义为该结点的左子树的深度减去它的右子树的深度,则平衡二叉树上所有结点的平衡因子只可能是-1、0和1。

红黑树:
红黑树是一种
自平衡排序二叉树
,树中每个节点的值,都大于或等于在它的左子树中的所有节点的值,并且小于或等于在它的右子树中的所有节点的值,这确保红黑树运行时可以快速地在树中查找和定位的所需节点。

  • 性质 1:每个节点要么是红色,要么是黑色。
  • 性质 2:根节点永远是黑色的。
  • 性质 3:所有的叶节点都是空节点(即 null),并且是黑色的。
  • 性质 4:每个红色节点的两个子节点都是黑色。(从每个叶子到根的路径上不会有两个连续的红色节点)
  • 性质 5:从任一节点到其子树中每个叶子节点的路径都包含相同数量的黑色节点。

Java 中实现的红黑树可能有如图所示结构:

备注:本文中所有关于红黑树中的示意图采用白色代表红色。黑色节点还是采用了黑色表示。

根据性质 5:红黑树从根节点到每个叶子节点的路径都包含相同数量的黑色节点,因此从根节点到叶子节点的路径中包含的黑色节点数被称为树的“黑色高度(black-height)”。

性质 4 则保证了从根节点到叶子节点的最长路径的长度不会超过任何其他路径的两倍。假如有一棵黑色高度为 3 的红黑树:从根节点到叶节点的最短路径长度是 2,该路径上全是黑色节点(黑节点 - 黑节点 - 黑节点)。最长路径也只可能为 4,在每个黑色节点之间插入一个红色节点(黑节点 - 红节点 - 黑节点 - 红节点 - 黑节点),性质 4 保证绝不可能插入更多的红色节点。由此可见,红黑树中最长路径就是一条红黑交替的路径。

B-树:
B-数是一种平衡的多路查找树,一棵m阶B-树,或为空树,或为满足下列特性的m叉树:
(m≥3)

(1)根结点只有1个,关键字字数的范围[1,m-1],分支数量范围[2,m];

(2)除根以外的非叶结点,每个结点包含分支数范围[[m/2],m],即关键字字数的范围是[[m/2]-1,m-1],其中[m/2]表示取大于m/2的最小整数;

(3)非叶结点是由叶结点分裂而来的,所以叶结点关键字个数也满足[[m/2]-1,m-1];

(4)所有的非终端结点包含信息:(n,P
0
,K
1
,P
1
,K
2
,P
2
,……,K
n
,P
n
),

其中K
i
为关键字,P
i
为指向子树根结点的指针,并且P
i-1
所指子树中的关键字均小于K
i
,而P
i
所指的关键字均大于K
i
(i=1,2,……,n),n+1表示B-树的阶,n表示关键字个数,即[ceil(m / 2)-1]<= n <= m-1;

(5)所有叶子结点都在同一层,并且指针域为空,具有如下性质:

根据B-树定义,第一层为根有一个结点,至少两个分支,第二层至少2个结点,i≥3时,每一层至少有2乘以([m/2])的i-2次方个结点([m/2]表示取大于m/2的最小整数)。若m阶树中共有N个结点,那么可以推导出N必然满足N≥2*(([m/2])的h-1次方)-1 (h≥1),因此若查找成功,则高度h≤1+log[m/2](N+1)/2,h也是磁盘访问次数(h≥1),保证了查找算法的高效率。

B+树:
B+树是B-树的变体,也是一种多路搜索树,其定义基本与B-树同,除了:

1)非叶子结点的子树指针与关键字个数相同;

2)非叶子结点的子树指针P[i],指向关键字值属于[K[i], K[i+1])的子树(B-树是开区间);

3)为所有叶子结点增加一个链指针;

4)所有关键字都在叶子结点出现;

9、图

各种排序算法的比较:

一、插入排序

1、直接插入

稳定,平均和最坏都是O(n2)

它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

2、Shell排序

不稳定,平均O(n3/2),最坏O(n2)。
它的基本思想是先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为dl的倍数的记录放在同一个组中。先在各组内进行直接插人排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。该方法实质上是一种分组插入方法。

代码实现:

package com.yyq;

import java.util.Arrays;

/**
 * Created by Administrator on 2015/9/9.
 */
public class InsertSort { public static void insertDirectlySort(int a[]) { if (a == null) return; int len = a.length; try { for (int i = 0; i < len; i++) { for (int j = i + 1; j < len && j > 0; j--) { if (a[j] < a[j - 1]) { int temp = a[j]; a[j] = a[j - 1]; a[j - 1] = temp; } } } } catch (Exception e) { e.printStackTrace(); } } public static void shellSort(int data[]) { if (data == null) return; int j = 0; int temp = 0; int len = data.length / 2; for (int increment = len; increment > 0; increment /= 2) { for (int i = increment; i < data.length; i++) { temp = data[i]; for (j = i; j >= increment; j -= increment) { if(temp < data[j - increment]){ data[j] = data[j - increment]; }else{ break; } } data[j] = temp; } } } public static void Test(int a[],int b[]) { System.out.println("The Source Secquence:"); if (a == null) return; System.out.println(Arrays.toString(a)); insertDirectlySort(a); System.out.println("InsertDirectlySort Result: "); System.out.println(Arrays.toString(a)); shellSort(b); System.out.println("ShellSort Result:"); System.out.println(Arrays.toString(b)); System.out.println(); } public static void main(String[] args){ int a1[] = null; int a2[] = {1}; int a3[] = {3, 6, 1, 8, 2, 9, 4}; int a4[] = {1, 3, 5, 7, 9}; int a5[] = {6, 9, 4, 8, -1}; int a6[] = {9, 5, 4, 2, 1}; int b1[] = null; int b2[] = {1}; int b3[] = {3, 6, 1, 8, 2, 9, 4}; int b4[] = {1, 3, 5, 7, 9}; int b5[] = {6, 9, 4, 8, -1}; int b6[] = {9, 5, 4, 2, 1}; Test(a1,b1); Test(a2,b2); Test(a3,b3); Test(a4,b4); Test(a5,b5); Test(a6,b6); } }
复制代码

输出结果:

The Source Secquence:

The Source Secquence:

[1]

InsertDirectlySort Result:

[1]

ShellSort Result:

[1]

The Source Secquence:

[3, 6, 1, 8, 2, 9, 4]

InsertDirectlySort Result:

[1, 2, 3, 4, 6, 8, 9]

ShellSort Result:

[1, 2, 3, 4, 6, 8, 9]

The Source Secquence:

[1, 3, 5, 7, 9]

InsertDirectlySort Result:

[1, 3, 5, 7, 9]

ShellSort Result:

[1, 3, 5, 7, 9]

The Source Secquence:

[6, 9, 4, 8, -1]

InsertDirectlySort Result:

[-1, 4, 6, 8, 9]

ShellSort Result:

[-1, 4, 6, 8, 9]

The Source Secquence:

[9, 5, 4, 2, 1]

InsertDirectlySort Result:

[1, 2, 4, 5, 9]

ShellSort Result:

[1, 2, 4, 5, 9]

二、选择排序

1、直接选择

不稳定,平均和最坏都是O(n2)。
是一种简单直观的排序算法。它的工作原理如下。首先在未排序序列中找到最小元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小元素,然后放到排序序列末尾(目前已被排序的序列)。以此类推,直到所有元素均排序完毕。

2、堆排序

不稳定,平均和最坏都是O(nlogn),辅助存储O(1)。
利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

复制代码
package com.yyq;

import java.util.Arrays;

/**
 * Created by Administrator on 2015/9/9.
 */
public class SelectSort {
    public static void selectDirectlySort(int[] a) {
        if (a == null) return;
        int min = 0;
        int i = 0;
        int j = 0;
        int index = 0;
        int len = a.length;
        for (i = 0; i < len - 1; i++) {
            min = a[i];
            index = i;
            for (j = i + 1; j < len; j++) {
                if (a[j] < min) {
                    min = a[j];
                    index = j;
                }
            }
            a[index] = a[i];
            a[i] = min;
        }
    }

    public static void heapSort(int[] array) {
        if (array == null) return;
        buildHeap(array);//构建堆
        int n = array.length;
        int i = 0;
        for (i = n - 1; i >= 1; i--) {
            swap(array, 0, i);
            heapify(array, 0, i);
        }
    }
    //构建
    public static void buildHeap(int[] array) {
        int n = array.length;//数组中元素的个数
        for (int i = n / 2 - 1; i >= 0; i--)
            heapify(array, i, n);
    }
    public static void heapify(int[] A, int idx, int max) {
        int left = 2 * idx + 1;// 左孩子的下标(如果存在的话)
        int right = 2 * idx + 2;// 左孩子的下标(如果存在的话)
        int largest = 0;//寻找3个节点中最大值节点的下标
        if (left < max && A[left] > A[idx])
            largest = left;
        else
            largest = idx;
        if (right < max && A[right] > A[largest])
            largest = right;
        if (largest != idx) {
            swap(A, largest, idx);
            heapify(A, largest, max);
        }
    }
    public static void swap(int[] array, int i, int j) {
        int temp = 0;
        temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }

    public static void Test(int a[], int b[]) {
        System.out.println("The Source Secquence:");
        if (a == null) return;
        System.out.println(Arrays.toString(a));

        selectDirectlySort(a);
        System.out.println("BubbleSort Result: ");
        System.out.println(Arrays.toString(a));

        heapSort(b);
        System.out.println("QuickSort Result:");
        System.out.println(Arrays.toString(b));
        System.out.println();
    }

    public static void main(String[] args) {
        int a1[] = null;
        int a2[] = {1};
        int a3[] = {3, 6, 1, 8, 2, 9, 4};
        int a4[] = {1, 3, 5, 7, 9};
        int a5[] = {6, 9, 4, 8, -1};
        int a6[] = {9, 5, 4, 2, 1};
        int b1[] = null;
        int b2[] = {1};
        int b3[] = {3, 6, 1, 8, 2, 9, 4};
        int b4[] = {1, 3, 5, 7, 9};
        int b5[] = {6, 9, 4, 8, -1};
        int b6[] = {9, 5, 4, 2, 1};
        Test(a1, b1);
        Test(a2, b2);
        Test(a3, b3);
        Test(a4, b4);
        Test(a5, b5);
        Test(a6, b6);
    }
}
复制代码

输出结果:

The Source Secquence:

The Source Secquence:

[1]

BubbleSort Result:

[1]

QuickSort Result:

[1]

The Source Secquence:

[3, 6, 1, 8, 2, 9, 4]

BubbleSort Result:

[1, 2, 3, 4, 6, 8, 9]

QuickSort Result:

[1, 2, 3, 4, 6, 8, 9]

The Source Secquence:

[1, 3, 5, 7, 9]

BubbleSort Result:

[1, 3, 5, 7, 9]

QuickSort Result:

[1, 3, 5, 7, 9]

The Source Secquence:

[6, 9, 4, 8, -1]

BubbleSort Result:

[-1, 4, 6, 8, 9]

QuickSort Result:

[-1, 4, 6, 8, 9]

The Source Secquence:

[9, 5, 4, 2, 1]

BubbleSort Result:

[1, 2, 4, 5, 9]

QuickSort Result:

[1, 2, 4, 5, 9]

三、交换排序

1、冒泡排序

稳定,平均和最坏都是O(n2)。
是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

2、快速排序

不稳定,平均
O(nlogn),最坏O(n
2
),辅助存储O(logn)。

基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

复制代码
package com.yyq;

import java.util.Arrays;

/**
 * Created by Administrator on 2015/9/10.
 */
public class ChangeSort {
    public static void swap(int[] array, int i, int j){
        int temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
    public static void bubbleSort(int[] array){
        if (array == null) return;
        int len = array.length;;
        for(int i = 0; i < len-1; i++){
            for (int j = len-1; j > i; j--){
                if (array[j] < array[j-1] ){
                    swap(array,j,j-1);
                }
            }
        }
    }
    public static void quickSort(int[] array, int low, int high){
        if (array == null || low < 0 || high < 0 || low >= array.length) return;
        int pivotloc = partition(array, low, high);
        if(low < high){
            quickSort(array, low, pivotloc-1);
            quickSort(array,pivotloc+1,high);
        }
    }
    public static int partition(int[] array, int low, int high){
        int pivokey = array[low];
        while(low < high){
            while(low < high && array[high] >= pivokey)
            {
                high--;
            }
            array[low] = array[high];
            while(low < high && array[low] <= pivokey)
            {
                low++;
            }
            array[high] = array[low];
        }
        array[low] = pivokey;
        return low;
    }
    public static void Test(int a[],int b[]) {
        System.out.println("The Source Secquence:");
        if (a == null) return;
        System.out.println(Arrays.toString(a));

        bubbleSort(a);
        System.out.println("BubbleSort Result: ");
        System.out.println(Arrays.toString(a));

        quickSort(b, 0, b.length-1);
        System.out.println("QuickSort Result:");
        System.out.println(Arrays.toString(b));
        System.out.println();
    }
    public static void main(String[] args){
        int a1[] = null;
        int a2[] = {1};
        int a3[] = {3, 6, 1, 8, 2, 9, 4};
        int a4[] = {1, 3, 5, 7, 9};
        int a5[] = {6, 9, 4, 8, -1};
        int a6[] = {9, 5, 4, 2, 1};
        int b1[] = null;
        int b2[] = {1};
        int b3[] = {3, 6, 1, 8, 2, 9, 4};
        int b4[] = {1, 3, 5, 7, 9};
        int b5[] = {6, 9, 4, 8, -1};
        int b6[] = {9, 5, 4, 2, 1};
        Test(a1,b1);
        Test(a2,b2);
        Test(a3,b3);
        Test(a4,b4);
        Test(a5,b5);
        Test(a6,b6);
    }
}
复制代码

输出结果:

The Source Secquence:

The Source Secquence:

[1]

BubbleSort Result:

[1]

QuickSort Result:

[1]

The Source Secquence:

[3, 6, 1, 8, 2, 9, 4]

BubbleSort Result:

[1, 2, 3, 4, 6, 8, 9]

QuickSort Result:

[1, 2, 3, 4, 6, 8, 9]

The Source Secquence:

[1, 3, 5, 7, 9]

BubbleSort Result:

[1, 3, 5, 7, 9]

QuickSort Result:

[1, 3, 5, 7, 9]

The Source Secquence:

[6, 9, 4, 8, -1]

BubbleSort Result:

[-1, 4, 6, 8, 9]

QuickSort Result:

[-1, 4, 6, 8, 9]

The Source Secquence:

[9, 5, 4, 2, 1]

BubbleSort Result:

[1, 2, 4, 5, 9]

QuickSort Result:

[1, 2, 4, 5, 9]

四、归并排序(
台湾译作:合并排序):

稳定,平均和最坏都是
O(nlogn),辅助存储O(n)。
是建立在归并操作上的一种有效的排序算法。将两个(或两个以上)有序表合并成一个新的有序表 即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。

复制代码
package com.yyq;

import java.util.Arrays;

/**
 * Created by Administrator on 2015/9/10.
 */
public class MergingSort {

    public static void Test(int a[]) {
        System.out.println("The Source Secquence:");
        if (a == null) return;
        System.out.println(Arrays.toString(a));

        mergeSort(a,0,a.length-1);
        System.out.println("MergeSort Result: ");
        System.out.println(Arrays.toString(a));
        System.out.println();
    }
    public static void main(String[] args){
        int a1[] = null;
        int a2[] = {1};
        int a3[] = {3, 6, 1, 8, 2, 9, 4};
        int a4[] = {1, 3, 5, 7, 9};
        int a5[] = {6, 9, 4, 8, -1};
        int a6[] = {9, 5, 4, 2, 1};
        Test(a1);
        Test(a2);
        Test(a3);
        Test(a4);
        Test(a5);
        Test(a6);
    }
    public static int[] mergeSort(int[] nums, int low, int high) {
        if (nums == null || low < 0 || low > nums.length-1 || high < 0) return nums;
        int mid = (low + high) / 2;
        if (low < high) {
            // 左边
            mergeSort(nums, low, mid);
            // 右边
            mergeSort(nums, mid + 1, high);
            // 左右归并
            merge(nums, low, mid, high);
        }
        return nums;
    }
    public static void merge(int[] nums, int low, int mid, int high) {
        int[] temp = new int[high - low + 1];
        int i = low;// 左指针
        int j = mid + 1;// 右指针
        int k = 0;
        // 把较小的数先移到新数组中
        while (i <= mid && j <= high) {
            if (nums[i] < nums[j]) {
                temp[k++] = nums[i++];
            } else {
                temp[k++] = nums[j++];
            }
        }
        // 把左边剩余的数移入数组
        while (i <= mid) {
            temp[k++] = nums[i++];
        }
        // 把右边边剩余的数移入数组
        while (j <= high) {
            temp[k++] = nums[j++];
        }
        // 把新数组中的数覆盖nums数组
        for (int k2 = 0; k2 < temp.length; k2++) {
            nums[k2 + low] = temp[k2];
        }
    }
}
复制代码

输出结果:

The Source Secquence:

The Source Secquence:

[1]

MergeSort Result:

[1]

The Source Secquence:

[3, 6, 1, 8, 2, 9, 4]

MergeSort Result:

[1, 2, 3, 4, 6, 8, 9]

The Source Secquence:

[1, 3, 5, 7, 9]

MergeSort Result:

[1, 3, 5, 7, 9]

The Source Secquence:

[6, 9, 4, 8, -1]

MergeSort Result:

[-1, 4, 6, 8, 9]

The Source Secquence:

[9, 5, 4, 2, 1]

MergeSort Result:

[1, 2, 4, 5, 9]

五、基数排序又称“桶子法”:

稳定,平均和最坏都是O(d(n+rd)),对于n个记录,每个记录含d个关键字(即位数),每个关键字的取值范围为rd个值。
它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用。

复制代码
package com.yyq;

import java.util.Arrays;

/**
 * Created by Administrator on 2015/9/10.
 */
public class RadixSort {
    public static void radixSort(int[] array, int num, int radix) {
        if (array == null) return;
        int k = 0;
        int n = 1;
        int index = 1;
        int len = array.length;
        //分成nums.length个桶
        int[][] radixArray = new int[radix][radix];
        //每个桶放的个数组成的数组
        int[] tempArray = new int[radix];
        for (int i = 0; i < tempArray.length; i++){
            tempArray[i] = 0;
        }
        //还在位数内
        while (index <= num) {
            for (int i = 0; i < len; i++) {
                //个,十,百,千...
                int temp = (array[i] / n) % 10;
                //存入特定桶的特定位置
                radixArray[temp][tempArray[temp]] = array[i];
                tempArray[temp] = tempArray[temp] + 1;
            }
            for (int i = 0; i < radix; i++) {
                if (tempArray[i] != 0) {
                    for (int j = 0; j < tempArray[i]; j++) {
                        //数组重组
                        array[k] = radixArray[i][j];
                        k++;
                    }
                    //重置,以防下次循环时数据出错
                    tempArray[i] = 0;
                }
            }
            //重置,以防下次循环时数据出错
            k = 0;
            //进位
            n *= 10;
            index++;
        }
    }

    // 基数排序的实现
    public static void Test(int a[]) {
        System.out.println("The Source Secquence:");
        if (a == null) return;
        System.out.println(Arrays.toString(a));
        int num = 0;
        int max_num = num;
        for (int i = 0; i < a.length; i++){
            int temp = a[i];
            while(temp != 0){
                num++;
                temp = temp / 10;
            }
            if (num > max_num){
                max_num = num;
            }
            num = 0;
        }
        System.out.println("The largest number'length is:"+max_num);
        radixSort(a, max_num,10);
        System.out.println("RadixSort Result: ");
        System.out.println(Arrays.toString(a));
        System.out.println();
    }

    public static void main(String[] args) {
        int a1[] = null;
        int a2[] = {1};
        int a3[] = {3, 6, 1, 8, 2, 9, 4};
       int a4[] = {110, 35, 4855, 2726,562599};
        int a5[] = {278, 109, 930, 184, 505, 269, 800, 831};
        int a6[] = {9, 35, 4, 2, 1};
        Test(a1);
        Test(a2);
        Test(a3);
        Test(a4);
        Test(a5);
        Test(a6);
    }
}
复制代码

输出结果:

The Source Secquence:

The Source Secquence:

[1]

The largest number'length is:1

RadixSort Result:

[1]

The Source Secquence:

[3, 6, 1, 8, 2, 9, 4]

The largest number'length is:1

RadixSort Result:

[1, 2, 3, 4, 6, 8, 9]

The Source Secquence:

[110, 35, 4855, 2726, 562599]

The largest number'length is:6

RadixSort Result:

[35, 110, 2726, 4855, 562599]

The Source Secquence:

[278, 109, 930, 184, 505, 269, 800, 831]

The largest number'length is:3

RadixSort Result:

[109, 184, 269, 278, 505, 800, 831, 930]

The Source Secquence:

[9, 35, 4, 2, 1]

The largest number'length is:2

RadixSort Result:

[1, 2, 4, 9, 35]

java中的数据结构 - 南风顾 - 博客园
http://www.cnblogs.com/tingxuelou/p/6686143.html

线性表,链表,哈希表是常用的数据结构,在进行Java开发时,JDK已经为我们提供了一系列相应的类来实现基本的数据结构。

Java工具包提供了强大的数据结构。在Java中的数据结构主要包括以下几种接口和类:

1.枚举
(Enumeration):枚举(The Enumeration)接口定义了一种从数据结构中取回连续元素的方式。它还是使用在诸如Vector和Properties这些传统类所定义的方法中

2.位集合(BitSet)3.向量(Vector)4.栈(Stack)

5.字典(Dictionary)

6.哈希表(Hashtable)

7.属性(Properties)

以上这些都是传统的集合框架,虽然这些类都非常有用,但是它们缺少一个核心的,统一的主题。由于这个原因,使用Vector类的方式和使用Properties类的方式有着很大不同。

集合框架被设计成要满足以下几个目标。

  • 该框架必须是高性能的。基本集合(动态数组,链表,树,哈希表)的实现也必须是高效的。
  • 该框架允许不同类型的集合,以类似的方式工作,具有高度的互操作性。
  • 对一个集合的扩展和适应必须是简单的。

为此,整个集合框架就围绕一组标准接口而设计。你可以直接使用这些接口的标准实现,诸如: LinkedList, HashSet, 和 TreeSet等,除此之外你也可以通过这些接口实现自己的集合。

集合框架是一个用来代表和操纵集合的统一架构。所有的集合框架都包含如下内

1.list是存储有序的集合,Set是存储无序的集合,存储不重复的数据。

2.sortedset继承于set接口,用来存储有序的集合。

3.map将唯一的键映射到值。

4.map.entry描述在一个map中的一个元素

Set和List的区别:set是无序的集合,list是有序的集合,使用此接口能够精确的控制被个元素插入的位置,能够偶通过索引的位置来精确地访问元素

Set检索效率低下,删除和插入效率高,插入和删除不会引起元素位置改变

List和数组类似,可以动态增长,根据实际存储的数据的长度自动增长List的长度。查找元素效率高,插入删除效率低,因为会引起其他元素位置改变

Java集合类及其数据结构归纳 - s小小的我 - 博客园
http://www.cnblogs.com/shidejia/p/6433788.html

---------大图可以 在新标签中打开图片 看到大图

上面这张图总结了java集合类的继承结构,下面是对集合类的一些总结和特性描述:

Collection

Collection是一个接口,是高度抽象出来的集合,它包含了集合的基本操作:添加、删除、清空、遍历、是否为空、获取大小、是否保护某元素等等。

Collection接口的所有子类
(直接子类和间接子类
)都必须实现
2种构造函数:不带参数的构造函数和参数为
Collection的构造函数。带参数的构造函数,可以用来转换
Collection的类型。

AbstractCollection

AbstractCollection是一个抽象类,它实现了
Collection中除
iterator()和
size()之外的函数。由于它实现了
Collection接口中的大部分函数,从而方便其它类实现
Collection,比如
ArrayList、
LinkedList等,它们这些类想要实现
Collection接口,通过继承
AbstractCollection就已经实现了大部分的接口了。

List

List是一个继承于
Collection的接口。

List是有序的队列,
List中的每一个元素都有一个索引。第一个元素的索引值是
0,往后的元素的索引值依次
+1。


Set不同,
List中允许有重复的元素。

既然
List是继承于
Collection接口,它包含了
Collection中的全部函数接口;由于
List是有序队列,它也额外的有自己的
API接口。主要有
“添加、删除、获取、修改指定位置的元素
”、
“获取
List中的子队列
”等。

List中有
listIterator()方法,
List的实现类都要实现
listIterator()方法,返回一个
ListIterator对象。

ListIterator是一个继承于
Iterator的接口,它是队列迭代器。专门用于便利
List,能提供向前
/向后遍历。相比于
Iterator,它新增了添加、是否存在上一个元素、获取上一个元素等等
API接口。

AbstractList

AbstractList是一个继承于AbstractCollection,并且实现List接口的抽象类。

它实现了List中除size()、get(int
location)之外的函数。由于它实现了List接口中的大部分函数,从而方便其它类继承List。AbstractList和AbstractCollection相比,AbstractList抽象类中实现了iterator()接口。

ArrayList

ArrayList继承了AbstractList抽象类,实现了List接口。

它是一个数组队列,相当于动态数组。与Java中的数组相比,它的容量能动态增长。

ArrayList还实现了RandomAccess(提供了随机访问功能:即可以通过元素的序号快速获取元素对象),
Cloneable(能被克隆), java.io.Serializable(支持序列化,能通过序列化去传输)这些接口。

ArrayList中是非线程安全的,所以在单线程中才使用ArrayList,而在多线程中可以选择Vector或者CopyOnWriteArrayList。

LinkedList

LinkedList
是一个继承于AbstractSequentialList的双向链表,可以被当作堆栈、队列或双端队列进行操作。

LinkedList同时还实现了List、Deque(双端队列)、Cloneable(能克隆)、java.io.Serializable(支持序列化,能通过序列化去传输)等接口。LinkedList是非同步的。

Vector

Vector
是矢量队列,它是JDK1.0版本添加的类。继承于AbstractList,实现了List(支持相关的添加、删除、修改、遍历等),
RandomAccess(随机访问功能), Cloneable(能被克隆)这些接口。

Vector实际上是通过一个数组去保存数据的。当我们构造Vecotr时;若使用默认构造函数,则Vector的默认容量大小是10。

当Vector容量不足以容纳全部元素时,Vector的容量会增加。若容量增加系数
>0,则将容量的值增加“容量增加系数”;否则,将容量大小增加一倍。

Vector的克隆函数,即是将全部元素克隆到一个数组中。和ArrayList不同,Vector中的操作是线程安全的。

Stack

Stack是栈。它的特性是:先进后出(FILO, First In Last Out)。

Stack继承于Vector(矢量队列)的,由于Vector是通过数组实现的,这就意味着,Stack也是通过数组实现的,而非链表。

Set

Set是一个继承于Collection的接口。Set是没有重复元素的集合。

AbstractSet

AbstractSet是一个继承于AbstractCollection,并且实现Set接口的抽象类。它实现了Set接口中的大部分函数,从而方便其它类实现Set接口。

HashSet

HashSet
是一个没有重复元素的集合,继承于AbstractSet,并且实现了Set接口。

它是由HashMap实现的,HashSet中含有一个HashMap类型的成员变量map,HashSet的操作函数,实际上都是通过map实现的。HashMap不保证元素的顺序,而且HashSet允许使用
null 元素。HashSet是非同步的。

TreeSet

TreeSet是一个有序的集合,它是通过TreeMap实现的,TreeSet中含有一个NavigableMap类型的成员变量m,而m实际上是TreeMap的实例。

TreeMap继承于AbstractSet(具有Set的属性和方法)抽象类,实现了NavigableSet(支持一系列的导航方法,比如查找与指定目标最匹配项),
Cloneable(能被克隆),
java.io.Serializable(支持序列化,能通过序列化去传输。当写入到输出流时,依次写入“比较器、容量、全部元素”;当读出输入流时,再依次读取。)接口。

TreeSet是基于TreeMap实现的。TreeSet中的元素支持2种排序方式:自然排序或者根据创建TreeSet时提供的Comparator进行排序。这取决于使用的构造方法。

TreeSet为基本操作(add、remove 和 contains)提供受保证的 log(n)
时间开销。

TreeSet是非同步的,即非线程安全的。 它的iterator
方法返回的迭代器是fail-fast的。

Map

Map是一个键值对(key-value)映射接口。Map映射中不能包含重复的键;每个键最多只能映射到一个值。

Map提供接口分别用于返回键集、值集或键-值映射关系集:

entrySet()用于返回键-值集的Set集合;

keySet()用于返回键集的Set集合;

values()用户返回值集的Collection集合。

因为Map中不能包含重复的键;每个键最多只能映射到一个值。所以,键-值集、键集都是Set,值集时Collection。

Map提供了“键-值对”、“根据键获取值”、“删除键”、“获取容量大小”等方法。

AbstractMap

AbstractMap类提供Map接口的骨干实现,以最大限度地减少实现此接口所需的工作。

SortedMap

SortedMap是一个继承于Map接口的接口。它是一个有序的SortedMap键值映射。

SortedMap的排序方式有两种:自然排序或者用户指定比较器。插入有序
SortedMap的所有元素都必须实现Comparable接口(或者被指定的比较器所接受)。

NavigableMap

NavigableMap是继承于SortedMap的接口。它是一个可导航的键-值对集合,具有了为给定搜索目标报告最接近匹配项的导航方法。

NavigableMap分别提供了获取“键”、“键-值对”、“键集”、“键-值对集”的相关方法。

HashMap

HashMap是一个散列表,它存储的内容是键值对(key-value)映射。

HashMap继承于AbstractMap,实现了Map、Cloneable、java.io.Serializable接口。

HashMap的实现不是同步的,这意味着它不是线程安全的。它的key、value都可以为null。此外,HashMap中的映射不是有序的。

TreeMap

TreeMap实现SortedMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用Iterator
遍历TreeMap时,得到的记录是排过序的。

TreeMap基于红黑树(Red-Black
tree)实现。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。

Hashtable

Hashtable与HashMap类似,Hashtable继承自Dictionary类,实现了Map接口,不同的是它不允许记录的键或者值为空;和HashMap相比,Hashtable是线程同步的,即任一时刻只有一个线程能写Hashtable,因此也导致了
Hashtable在写入时会比较慢。而且Hashtable可以通过Enumeration去遍历。

LinkedHashMap

LinkedHashMap保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的。也可以在构造时用带参数,按照应用次数排序。在遍历的时候会比HashMap慢,不过有种情况例外,当HashMap容量很大,实际数据较少时,遍历起来可能会比LinkedHashMap慢,因为LinkedHashMap的遍历速度只和实际数据有关,和容量无关,而HashMap的遍历速度和他的容量有关。

Enumeration和Iterator比较:

(01) 函数接口不同

Enumeration只有2个函数接口。通过Enumeration,我们只能读取集合的数据,而不能对数据进行修改。

Iterator只有3个函数接口。Iterator除了能读取集合的数据之外,也能数据进行删除操作。

(02) Iterator支持fail-fast机制,而Enumeration不支持。

Enumeration 是JDK
1.0添加的接口。使用到它的函数包括Vector、Hashtable等类,这些类都是JDK
1.0中加入的,Enumeration存在的目的就是为它们提供遍历接口。Enumeration本身并没有支持同步,而在Vector、Hashtable实现Enumeration时,添加了同步。

而Iterator 是JDK
1.2才添加的接口,它也是为了HashMap、ArrayList等集合提供遍历接口。Iterator是支持fail-fast机制的:当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。

java 中几种常用数据结构 - u010947402的博客 - CSDN博客
http://blog.csdn.net/u010947402/article/details/51878166

JAVA中常用的数据结构(java.util. 中)

java中有几种常用的数据结构,主要分为Collection和map两个主要接口(接口只提供方法,并不提供实现),而程序中最终使用的数据结构是继承自这些接口的数据结构类。其主要的关系(继承关系)有:  (----详细参见java api文档!)

Collection---->Collections                                                                                                          Map----->SortedMap------>TreeMap

Collection---->List----->(Vector \ ArryList \ LinkedList)                                                          Map------>HashMap

Collection---->Set------>(HashSet \ LinkedHashSet \ SortedSet)

--------------Collection----------------

1、Collections

API----This class consists exclusively of static methods that operate on or return collections. It contains polymorphic algorithms that operate on collections, "wrappers", which return a new collection backed by a specified collection, and a few other odds and ends.

The methods of this class all throw a
NullPointerException
if the collections or class objects provided to them are null.

2、List

API----This class consists exclusively of static methods that operate on or return collections. It contains polymorphic algorithms that operate on collections, "wrappers", which return a new collection backed by a specified collection, and a few other odds and ends.

The methods of this class all throw a
NullPointerException
if the collections or class objects provided to them are null.

List是有序的Collection,使用此接口能够精确的控制每个元素插入的位置。用户能够使用索引(元素在List中的位置,类似于数组下 >标)来访问List中的元素,这类似于Java的数组。

3、Vector

API----The
Vector
class implements a growable array of objects. Like an array, it contains components that can be accessed using an integer index. However, the size of a
Vector
can grow or shrink as needed to accommodate adding and removing items after the
Vector
has been created.

基于数组(Array)的List,其实就是封装了数组所不具备的一些功能方便我们使用,所以它难易避免数组的限制,同时性能也不可能超越数组。所以,在可能的情况下,我们要多运用数组。另外很重要的一点就是Vector是线程同步的(sychronized)的,这也是Vector和ArrayList 的一个的重要区别。

4、ArrayList

API----Resizable-array implementation of the
List
interface. Implements all optional list operations, and permits all elements, including
null
. In addition to implementing the
List
interface, this class provides methods to manipulate the size of the array that is used internally to store the list. (This class is roughly equivalent to
Vector
, except that it is unsynchronized.)

同Vector一样是一个基于数组上的链表,但是不同的是ArrayList不是同步的。所以在性能上要比Vector好一些,但是当运行到多线程环境中时,可需要自己在管理线程的同步问题。

5、LinkedList

API----Linked list implementation of the
List
interface. Implements all optional list operations, and permits all elements (including
null
). In addition to implementing the
List
interface, the
LinkedList
class provides uniformly named methods to
get
,
remove
and
insert
an element at the beginning and end of the list. These operations allow linked lists to be used as a stack,
queue
, or
double-ended queue
.

LinkedList不同于前面两种List,它不是基于数组的,所以不受数组性能的限制。
它每一个节点(Node)都包含两方面的内容:
1.节点本身的数据(data);
2.下一个节点的信息(nextNode)。
所以当对LinkedList做添加,删除动作的时候就不用像基于数组的ArrayList一样,必须进行大量的数据移动。只要更改nextNode的相关信息就可以实现了,这是LinkedList的优势。

List总结:

  • 所有的List中只能容纳单个不同类型的对象组成的表,而不是Key-Value键值对。例如:[
    tom,1,c ]
  • 所有的List中可以有相同的元素,例如Vector中可以有
    [ tom,koo,too,koo ]
  • 所有的List中可以有null元素,例如[
    tom,null,1 ]

基于Array的List(Vector,ArrayList)适合查询,而LinkedList 适合添加,删除操作

6、Set(接口)

API-----A collection that contains no duplicate elements. More
formally, sets contain no pair of elements
e1
and
e2
such that
e1.equals(e2)
, and at most one null element. As implied
by its name, this interface models the mathematical

set

abstraction.

Set是不包含重复元素的Collection

7、HashSet

API-----This class implements the
Set
interface, backed by a hash table (actually a
HashMap
instance). It
makes no guarantees as to the iteration order of the set; in particular, it does
not guarantee that the order will remain constant over time. This class permits
the
null
element.

虽然Set同List都实现了Collection接口,但是他们的实现方式却大不一样。List基本上都是以Array为基础。但是Set则是在
HashMap的基础上来实现的,这个就是Set和List的根本区别。HashSet的存储方式是把HashMap中的Key作为Set的对应存储项。看看
HashSet的add(Object obj)方法的实现就可以一目了然了。

8、LinkedHashSet

API----Linked list implementation of the

List

interface. Implements all optional list operations, and permits
all elements (including

null

). In addition to implementing
the

List

interface, the

LinkedList

class provides uniformly
named methods to

get

,

remove

and

insert

an element at
the beginning and end of the list. These operations allow linked lists to be
used as a stack,
queue
, or
double-ended queue
.

HashSet的一个子类,一个链表。

9、SortedSet

API---A
Set
that further provides
a
total ordering
on its elements. The elements are ordered using their
natural ordering
, or by a
Comparator
typically provided at sorted set creation
time. The set's iterator will traverse the set in ascending element order.
Several additional operations are provided to take advantage of the ordering.
(This interface is the set analogue of
SortedMap
.)

有序的Set,通过SortedMap来实现的。

Set总结:

(1)Set实现的基础是Map(HashMap)(2)Set中的元素是不能重复的,如果使用add(Object
obj)方法添加已经存在的对象,则会覆盖前面的对象

-------------Map-----------------

Map
是一种把键对象和值对象进行关联的容器,而一个值对象又可以是一个Map,依次类推,这样就可形成一个多级映射。对于键对象来说,像Set一样,一个
Map容器中的键对象不允许重复,这是为了保持查找结果的一致性;如果有两个键对象一样,那你想得到那个键对象所对应的值对象时就有问题了,可能你得到的并不是你想的那个值对象,结果会造成混乱,所以键的唯一性很重要,也是符合集合的性质的。当然在使用过程中,某个键所对应的值对象可能会发生变化,这时会按照最后一次修改的值对象与键对应。对于值对象则没有唯一性的要求,你可以将任意多个键都映射到一个值对象上,这不会发生任何问题(不过对你的使用却可能会造成不便,你不知道你得到的到底是那一个键所对应的值对象)。

1、HashMap

API----Hash table based implementation of the

Map

interface. This
implementation provides all of the optional map operations, and
permits

null

values and the

null

key. (The

HashMap

class is roughly equivalent to

Hashtable

, except that it is
unsynchronized and permits nulls.) This class makes no guarantees as to the
order of the map; in particular, it does not guarantee that the order will
remain constant over time.

2、TreeMap

API----A Red-Black tree based
NavigableMap
implementation. The map is sorted
according to the
natural ordering
of its keys, or by
a
Comparator
provided at map creation
time, depending on which constructor is used.
TreeMap则是对键按序存放,因此它便有一些扩展的方法,比如firstKey(),lastKey()等,你还可以从TreeMap中指定一个范围以取得其子Map。
键和值的关联很简单,用put(Object
key,Object value)方法即可将一个键与一个值对象相关联。用get(Object
key)可得到与此key对象所对应的值对象。
------------说明-----------

一、几个常用类的区别

1.ArrayList:
元素单个,效率高,多用于查询
2.Vector:
元素单个,线程安全,多用于查询
3.LinkedList:元素单个,多用于插入和删除
4.HashMap:
元素成对,元素可为空
5.HashTable:
元素成对,线程安全,元素不可为空


二、Vector、ArrayList和LinkedList

大多数情况下,从性能上来说ArrayList最好,但是当集合内的元素需要频繁插入、删除时LinkedList会有比较好的表现,但是它们三个性能都比不上数组,另外Vector是线程同步的。所以:
如果能用数组的时候(元素类型固定,数组长度固定),请尽量使用数组来代替List;
如果没有频繁的删除插入操作,又不用考虑多线程问题,优先选择ArrayList;
如果在多线程条件下使用,可以考虑Vector;
如果需要频繁地删除插入,LinkedList就有了用武之地;
如果你什么都不知道,用ArrayList没错。


三、Collections和Arrays


Java集合类框架里有两个类叫做Collections(注意,不是Collection!)和Arrays,这是JCF里面功能强大的工具,但初学者往往会忽视。按JCF文档的说法,这两个类提供了封装器实现(Wrapper
Implementations)、数据结构算法和数组相关的应用。
想必大家不会忘记上面谈到的“折半查找”、“排序”等经典算法吧,Collections类提供了丰富的静态方法帮助我们轻松完成这些在数据结构课上烦人的工作:
binarySearch:折半查找。
sort:排序,这里是一种类似于快速排序的方法,效率仍然是O(n
* log n),但却是一种稳定的排序方法。
reverse:将线性表进行逆序操作,这个可是从前数据结构的经典考题哦!
rotate:以某个元素为轴心将线性表“旋转”。
swap:交换一个线性表中两个元素的位置。
……
Collections还有一个重要功能就是“封装器”(Wrapper),它提供了一些方法可以把一个集合转换成一个特殊的集合,如下:
unmodifiableXXX:转换成只读集合,这里XXX代表六种基本集合接口:Collection、List、Map、Set、SortedMap和SortedSet。如果你对只读集合进行插入删除操作,将会抛出UnsupportedOperationException异常。
synchronizedXXX:转换成同步集合。
singleton:创建一个仅有一个元素的集合,这里singleton生成的是单元素Set,
singletonList和singletonMap分别生成单元素的List和Map。
空集:由Collections的静态属性EMPTY_SET、EMPTY_LIST和EMPTY_MAP表示。

JAVA常用数据结构及原理分析  http://www.2cto.com/kf/201506/412305.html

前不久面试官让我说一下怎么理解java数据结构框架,之前也看过部分
源码
,balabala讲了一堆,现在总结一下。

java.util包中三个重要的接口及特点:
List(列表)、Set(保证集合中元素唯一)、Map(维护多个key-value键值对,保证key唯一)。

其不同子类的实现各有差异,如是否同步(线程安全)、是否有序。
常用类继承树:
这里写图片描述

以下结合源码讲解常用类实现原理及相互之间的差异。

Collection (所有集合类的接口)
List、Set都继承自Collection接口,查看JDK
API,操作集合常用的方法大部分在该接口中定义了。
这里写图片描述

Collections
(操作集合的工具类)
对于集合类的操作不得不提到工具类
Collections
,它提供了许多方便的方法,如求两个集合的差集、并集、拷贝、排序等等。
由于大部分的集合接口实现类都是不同步的,可以使用Collections.synchronized*方法创建同步的集合类对象。
如创建一个同步的List:
List synList = Collections.synchronizedList(new ArrayList());
其实现原理就是重新封装new出来的对象,操作对象时用关键字synchronized同步。看源码很容易理解。
Collections部分源码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19
<code
class
=
"language-java hljs "
>
//Collections.synchronizedList返回的是静态类SynchronizedCollection的实例,最终将new出来的ArrayList对象赋值给了Collection<e> c。
static
class
SynchronizedCollection<e>
implements
Collection<e>, Serializable {

final
Collection<e> c;
// Backing Collection

final
Object mutex;
// Object on which to synchronize

SynchronizedCollection(Collection<e> c) {

if
(c==
null
)

throw
new
NullPointerException();

this
.c = c;

mutex =
this
;

}

//...

public
boolean
add(E e) {

//操作集合时简单调用原本的ArrayList对象,只是做了同步

synchronized
(mutex) {
return
c.add(e);}

}

//...
}</e></e></e></e></e></code>

List (列表)

ArrayList、Vector是线性表,使用Object数组作为容器去存储数据的,添加了很多方法维护这个数组,使其容量可以动态增长,极大地提升了开发效率。它们明显的区别是ArrayList是非同步的,Vector是同步的。不用考虑多线程时应使用ArrayList来提升效率。
ArrayList、Vector
部分源码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31
<code
class
=
"language-java hljs "
>
//ArrayList.add
public
boolean
add(E e) {

ensureCapacityInternal(size +
1
);
// Increments modCount!!

//可以看出添加的对象放到elementData数组中去了

elementData[size++] = e;

return
true
;
}
//ArrayList.remove
public
E remove(
int
index) {

rangeCheck(index);

modCount++;

E oldValue = elementData(index);

int
numMoved = size - index -
1
;

if
(numMoved >
0
)

//移除元素时数组产生的空位由System.arraycopy方法将其后的所有元素往前移一位,System.arraycopy调用虚拟机提供的本地方法来提升效率

System.arraycopy(elementData, index+
1
, elementData, index,

numMoved);

elementData[--size] =
null
;
// Let gc do its work

return
oldValue;
}
//Vector add方法上多了synchronized关键字
public
synchronized
boolean
add(E e) {

modCount++;

ensureCapacityHelper(elementCount +
1
);

elementData[elementCount++] = e;

return
true
;
}</code>

LinkedList是链表,略懂数据结构就知道其实现原理了。链表随机位置插入、删除数据时比线性表快,遍历比线性表慢。
双向链表原理图:
这里写图片描述
LinkedList部分源码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21
<code
class
=
"language-java hljs "
>
//源码很清晰地表达了原理图
public
class
LinkedList<e>
extends
AbstractSequentialList<e>
implements
List<e>, Deque<e>, Cloneable, java.io.Serializable
{

//头尾节点

transient
Node<e> first;

transient
Node<e> last;
}
//节点类

private
static
class
Node<e> {

//节点存储的数据

E item;

Node<e> next;

Node<e> prev;

Node(Node<e> prev, E element, Node<e> next) {

this
.item = element;

this
.next = next;

this
.prev = prev;

}
}</e></e></e></e></e></e></e></e></e></e></e></code>

由此可根据实际情况来选择使用ArrayList(非同步、非频繁删除时选择)、Vector(需同步时选择)、LinkedList(频繁在任意位置插入、删除时选择)。

Map(存储键值对,key唯一)

HashMap结构的实现原理是将put进来的key-value封装成一个Entry对象存储到一个Entry数组中,位置(数组下标)由key的哈希值与数组长度计算而来。如果数组当前下标已有值,则将数组当前下标的值指向新添加的Entry对象。
有点晕,看图吧:
这里写图片描述
看完图再看源码,非常清晰,都不需要注释。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30
<code
class
=
"language-java hljs "
>
public
class
HashMap<k,v>
extends
AbstractMap<k,v>
implements
Map<k,v>, Cloneable, Serializable
{

transient
Entry<k,v>[] table;

public
V put(K key, V value) {

if
(key ==
null
)

return
putForNullKey(value);

int
hash = hash(key);

int
i = indexFor(hash, table.length);

//遍历当前下标的Entry对象链,如果key已存在则替换

for
(Entry<k,v> e = table[i]; e !=
null
; e = e.next) {

Object k;

if
(e.hash == hash && ((k = e.key) == key || key.equals(k))) {

V oldValue = e.value;

e.value = value;

e.recordAccess(
this
);

return
oldValue;

}

}

addEntry(hash, key, value, i);

return
null
;

}
}
static
class
Entry<k,v>
implements
Map.Entry<k,v> {

final
K key;

V value;

Entry<k,v> next;

int
hash;
}</k,v></k,v></k,v></k,v></k,v></k,v></k,v></k,v></code>

TreeMap是由Entry对象为节点组成的一颗
红黑树
,put到TreeMap的数据默认按key的自然顺序排序,new
TreeMap时传入Comparator自定义排序。红黑树网上很多资料,我讲不清,这里就不介绍了。

Set(保证容器内元素唯一性)
之所以先讲Map是因为
Set结构其实就是维护一个Map来存储数据的,利用Map结构key值唯一性

HashSet部分源码:

1

2

3

4

5

6

7

8

9

10

11
<code
class
=
"language-java hljs "
>
public
class
HashSet<e>
extends
AbstractSet<e>
implements
Set<e>, Cloneable, java.io.Serializable
{

//无意义对象来作为Map的value

private
static
final
Object PRESENT =
new
Object();

public
boolean
add(E e) {

return
map.put(e, PRESENT)==
null
;

}
}</e></e></e></code>

HashSet、TreeSet分别默认维护一个HashMap、TreeMap。