java常用的数组、字符串、集合操作以及数据结构与算法基本知识

时间:2023-01-03 18:07:11

        java中常用封装的数组 、字符串、 集合来操作对象,但数据结构中常用的有栈和队列   数与图以及他们之间的排序,查找。

        数组声明没有分配内存空间  只有创建或者是初始化时才分配,创建时把数组中的数据类型数据所在的内存空间首地址赋值给数组名,在创建每个对象时,都会给该对象分配地址和它存储的数据 。如变量    int arr[]; int arr[]={1,2,3};  arr=new int[10] ,int arr[][]={{1,9,7},{1,2,3}}  int arr[][]=new int[7][10]

        默认值

                   整型: 0  

                  实型:        0.0f或者0.0d

              字符型:‘\0'或者'\U0000'

              字符串:null

             常用操作:length数组求长度  toCharArray()字符串转为字符数组  valueof(char[])字符数组转为字符串 与new  String=new String(char[])一样

        字符串

 new String("str") 字符串可以在创建时同时创建两个对象,一个是字符串常量池,一个是字符串对象。字符串常量池里有就不再创建,

length()字符串大小  parseInt(String s)字符串转为Int型   valueof(int i)Int 型转字符串         intValue()是把Integer转为int    new Integer(int value)或者valueof(int value)把int变为integer对象

        new String(char[])

      new String(String s)

      new String(StringBuffer sb)

      new String(byte b[])

       new String(byte b[],offset,int count)

      net String(str.getBytes(String utf-8),String GBK);

      方法

      equals(String s)

     equlsIgnoreCase(String s)

      startsWith(String s)

     endsWith(String s)

       compareTo(String s)

    indexOf(String s)

    lastIndexOf(String s)

   charAt(int index)

   concat(String str)

    toCharArray()

   toString()

   toUpperCase()

   toLowerCase()

  trim()

 split(String regex)//正则表达式

 isEmpty()

 subString(int start)指定起始位置到结尾

 subString(int start,int end)

 replace(char old,char  new)//匹配全部

 replaceAll(String regex,char new)//正则表达式  全部匹配

 replaceFirst(String regex,char new)//正则表达式  第一个

 getBytes(String utf-8)

 str.intern()//从字符串池里面找与str相等(用equals(比较)的字符串,如果找到就返回该字符串,如果没有就把该字符串放到字符串池中,再返回它引用,这样可以节省内存

 String处理的是字符串常量,不可以修改、删除、替换字符串常量中的某个字符,而StringBuffer处理的是字符串变量,它的值和长度可以修改。

 new StringBuffer()默认长度是16个字节

 new  StringBuffer(int length)设置对象初始容量是length字节

new StringBuffer(String str)长度是str长度+16字节

  方法

append(String s)

charAt(int n)

setCharAt(int n,Char ch)

insert(int index,String str)

reverse()

delete(int start,int end)

replace(int start,int end,String str)

java.lang.StringBuilder一个可变的字符序列是5.0新增的。此类提供一个与 StringBuffer 兼容的 API,多个线程操作字符串缓冲区时,使用stringBuffer可以选择提供同步,但StringBuilder不保证同步(线程不安全)。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。两者的方法基本相同。

每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM 的 GC 就会开始工作,那速度是一定会相当慢的。

一般 速度:StringBuilder>StringBuffer>string

但String str = “This"+"is"+"test">StringBuffer Sb = new StringBuilder("This").append("is").append("test");
但String str1= "This";
String str2= "is";
String str3= "test";
String S1 = str1+str2+str3;<StringBuffer Sb = new StringBuilder("This").append("is").append("test");

还有其他常用的类system. math random date

        集合

判断各种集合类型不同主要是从线程安全,有序,重复

List、set都是继承了collection接口  List是有序、可重复的。collections是一个类,里面有各种对集合进行操作的静态方法。

map是键值类:采用键值对形式存储,key是唯一的,但value可以重复。

list常用的子类:Vector、ArrayList区别是Vector是同步的,linkedList链表添加或者删除数据不用大量移动数据。

map常用的子类:hashTable、hashMap区别是hashTable是线程安全、同步的  但不允许key或者value为null  用Enumeration er=new HashTable.keys();er.hasMoreElements(); .get(er.nextElement(),而hashMap用迭代器 。

set常用的子类:treeSet二叉树 是有序的 hashSet采用散列存储,是无序的,也就是输入数据与输出数据顺序不一致。

线程安全:只有一个线程使用一个内存空间,如果多个线程共用内存就不安全了。


Hashtable类实现原理:

hashcode()  这个方法外定义一个key(类型是Object)或者ID字段作为x,在内部使用哈希函数f(x)计算获得哈希码,返回哈希码值,作为对象在内存(数组)中的位置,当两个对象的哈希码一样时,一个hashcode数值就是一个对象,由于HashMap、HashSet HashTable不能有重复的对象,所以两个重复的对象要想当做同一个对象,就需要重写equals方法,执行判断(object instanceof 类名 、abject==this,或者把object强制转换为这个类对象,再this.getX()与类对象.getX()是否相等。)equals相当于桶的作用,把多个对象存在里面,比较某一个对象是否相等就相当于在这个桶里是否有这个对象。hashcode就相当于在找桶的位置。

重写equals需要注意是同类型比较和类型不能为null,再根据不同条件比较,如String是根据内容,HashTatble是根据key(x),它是无序的,因为hashcode()方法得到数组(内存)位置的。所以执行 put(Oject key,Object value)时,会调用hashcode()方法计算内存的位置,如果内存中这个位置被占用了,就调用Equals判断是否是同一个对象,如果不是,就重新计算哈希码值,为新对象分配一个数组下标,如果是就不抛出异常,就用这个新的覆盖那个旧的。

在java中,equals和hashcode是有设计要求的,equals相等,则hashcode一定相等,反之则不然。

在Java中,哈希码代表了对象的一种特征,例如我们判断某两个字符串是否==,如果其哈希码相等,则这两个字符串是相等的。其次,哈希码是一种数据结构的算法。常见的哈希码的算法有:


1:Object类的hashCode.返回对象的内存地址经过处理后的结构,由于每个对象的内存地址都不一样,所以哈希码也不一样。
2:String类的hashCode.根据String类包含的字符串的内容,根据一种特殊算法返回哈希码,只要字符串内容相同,返回的哈希码也相同。
3:Integer类,返回的哈希码就是Integer对象里所包含的那个整数的数值,例如Integer i1=new Integer(100),i1.hashCode的值就是100 。由此可见,2个一样大小的Integer对象,返回的哈希码也一样

  方法:

remove(Object obj)

add(Object obj)

addAll(Collection c)

iterator()

contains(Object obj)

containsAll(Collection c)

clear()

hashCode()

equals(Object obj)

isEmpty()

size()

 Map接口方法

  put(key,value)

  get(Object key)

remove(Object key)

containsKey(Object key)

containsValue(Object value)

注意:==与equals(Object obj)的区别,==在基本数据类型中是值比较,其他是地址比较。equals在String Integer Date重写了equals方法时比较是内容,其他比较内存地址。

   

   数据结构

数据:对象(结点)有什么属性,用构造函数把属性传进去,或者setxx方法传进去设置,用getXX方法取出属性。

关系:对象之间有什么关系。

操作:创建,增、删、改、查、排。

   c语言中的指针就相当于java中的对象引用,引用可以调用它的属性即变量,以及函数。第一个new得到的对象实例就是头结点。

链表:

  线性链表:结点由一个数据域与指针域组成,其中指针域存储的是下一个对象的引用。

   创建类或者接口(把具有同一类特性的对象封装成类)

    Interface class LinkNode{

              Object  obj;//数据对象

               LinkNode next;//指针

           public LinkNode()

             {

                      this.LinkNode(null,null);

             }

           public LinkNode(Object obj,LinkNode next){

                       this.obj=obj;

                       this.next=next;

              }

           private setNext(LinkNode next){
                        this.next=next;}

            private getNext(){

                return next;

                   }

             private setObj(Object obj){

                 this.obj=obj;

                          }

            private getObj(){

              return obj;

              } 

}

   插入方法:

            问题:要在线性表的两个数据元素(结点)a、b之间,插入一个数据元素(结点)x,

            功能:在某个位置插入元素

             参数:数据元素、位置

            返回值:无

             逻辑:先找到i位置(即b结点)的前驱结点的指针域,也就是b的引用,a的属性中的next,把它赋值给新的结点,然后new出来新的结点的引用,赋值给a

             作者:

             修改时间:

             创建时间:

       void  insert(Object obj,int i)throws Exception{

                if(i>size||i<0)

                throw new Exception("输入的位置不合理");

             try{

                    LinkNode head;//头指针或者头结点(数据域为链表长度)

                   LinkNode p=head;//遍历指针

                   while(p!=null)

                    {             if(p.data==b)

                                     //return p

                                   //赋值操作

                                 {

                                      LinNode q=new LinkNode(obj,p.getNext())//把前驱结点的指针域值赋值给新的结点

                                    p.setNext(q);

                                  else

                                  p=p.next;//遍历

                    }

               return;

   }


                       

 循环链表:

对象  其他与线性链表一样,不同的是最后一个结点指向头结点,所以判断是否到最后一个结点,可以用是否指向头结点。

关系

操作

双向链表:与线性链表不同,每个对象中增加后前驱指针域


     栈   

规则   先进后出   当遍历指针遍历到栈底的时候指针域为null  对象只有后驱指针域与数据域   没有头结点用头指针就可以 顺序存储有上 溢出 下溢出

存储结构   链表与数组

逻辑结构   线性

应用 语法词法分析   表达式求值  数值转换

    队列

规则  先进先出   有队头Front 允许插入  队尾rear允许删除   当头指针与尾指针指向同一个位置时队列 为空    不管进队还是出队头尾指针都是向高地址移动  出队移动头指针  进队移动尾指针 为了假上溢出 采用循环队列  当头尾指针指向最高地址时,再进队就上溢出了 但低地址还有空间 用循环队列  再进队列就回到低地址。

存储结构  链表与数组

存储结构

应用  cpu分时系统  模拟打印机缓冲区  银行排队

    树与二叉树

     大量的输入数据,线性表的访问时间太慢,不宜使用。

 树基本概念

(1)树(Tree)的概念:树是一种递归定义的数据结构,是一种重要的非线性数据结构。树可以是一棵空树,它没有任何的结点;也可以是一棵非空树,至少含有一个结点。
(2)根(Root):有且仅有一个结点的非空树,那个结点就是根。
(3)子树(Subtree):在一棵非空树中,除根外,其余所有结点可以分为m(m≥0)个互不相交的集合。每个集合本身又是一棵树,称为根的子树。
(4)结点(Node):表示树中的元素及若干指向其子树的分支。
(5)结点的度(Degree):一个结点拥有的子树数目称为该结点的度。
(6)叶子结点(Leaf):度为0的结点。
(7)孩子(Child):结点子树的根称为该结点的孩子。
(8)双亲(Parents):孩子结点的上层结点叫该结点的双亲。
(9)兄弟(Sibling):同一双亲的孩子。
(10)树的度:一棵树中最大的结点度数。
(11)结点的层次(Level):从根结点开始定义根为第一层,它的孩子为第二层,依此类推。
(12)深度(Depth):树中结点最大层次的值。根节点算一层,叶子结点算一层
(13)有序树:树中的各子树自左向右有序的称为有序树。
(14)无序树:树中的各子树自左向右无序的称为无序树。
(15)森林(Forest):是m(m≥0)棵互不相交的树的集合。
(16)祖先:是指从根结点到该结点之间所有的结点。

满二叉树:除最后一层无任何子节点外,每一层上的所有结点都有两个子结点二叉树。共有2^k-1个结点

完全二叉树:最后一批没有孩子结点,倒数第二排可以有0、1、2个孩子结点,其他节点都有两个孩子结点,就相当于从满二叉树从最后一排从右到左依次剪掉叶子结点。

存储结构

二叉树遍历

(1)先序遍历(先根遍历)
        1. 访问根结点
        2. 先序遍历左子树
        3.  先序遍历右子树
(2)中序遍历(中根遍历)
        1. 中序遍历左子树
        2. 访问根结点
        3.  中序遍历右子树
(3)后序遍历(后根遍历)
        1. 后序遍历左子树
        2. 后序遍历右子树
        3.  访问根结点

 线索二叉树  

最优二叉树(哈夫曼树):结点带权路径长度为从该结点到树根之间的路径长度与结点上权的乘积,树的带权路径长度为树中所有叶子结点的带权路径长度之和。假设有N个权值,试构造n个叶子结点的二叉树,每个叶子带权为对应的权值,则带权路径长度最小的二叉树为最优二叉树或哈夫曼树

 构造哈夫曼树过程

(1)根据给定的n个权值的关键字,构成一个集合,在集合中找两个权值最小的构成新的权值,直到与最后一个权值构成新的权值。(新的权值对应新的结点 没有关键字的)

应用 哈弗曼编码

      图

  任意两个顶点都有可能有关系

图的基本概念

无向图:图中每条边都没有方向;
有向图:图中每条边都有方向;
无向边:边是没有方向的,写为(a,b)
有向边:边是有方向的,写为<a,b>
有向边也成为弧;开始顶点称为弧尾,结束顶点称为弧头;
简单图:不存在指向自己的边、不存在两条重复的边的图;
无向完全图:每个顶点之间都有一条边的无向图有1/2n(n-1)条边;
有向完全图:每个顶点之间都有两条互为相反的边的无向图 有n(n-1)条边;
稀疏图:边相对于顶点来说很少的图;
稠密图:边很多的图;
权重:图中的边可能会带有一个权重,为了区分边的长短;
网:带有权重的图;
度:与特定顶点相连接的边数;
出度、入度:对于有向图的概念,出度表示此顶点为起点的边的数目,入度表示此顶点为终点的边的数目;
路径:路径的长度是路径上的边或弧的数目,序列中顶点不重复的路径称为简单路径
环:第一个顶点和最后一个顶点相同的路径;
简单环:除去第一个顶点和最后一个顶点后没有重复顶点的环;
连通图:任意两个顶点都相互连通的图;
极大连通子图:包含竟可能多的顶点(必须是连通的),即找不到另外一个顶点,使得此顶点能够连接到此极大连通子图的任意一个顶点;
连通分量:极大连通子图的数量;
强连通图:此为有向图的概念,表示任意两个顶点a,b,使得a能够连接到b,b也能连接到a 的图;
生成树:n个顶点,n-1条边,并且保证n个顶点相互连通(不存在环);
最小生成树:此生成树的边的权重之和是所有生成树中最小的;
AOV网:结点表示活动的网,不应该出现有环;
AOE网:边表示活动的持续时间的网;


图的存储结构

邻接矩阵

邻接表

十字链表

边集数组

邻接多重表


图的遍历

深度优先搜索:从图中某个顶点出发,访问此顶点,然后依次从该顶点未被访问的邻接点出发深度优先遍历图,直到图中所有和该顶点有路径相通的顶点都被访问到;若此时图中尚有顶点未被访问,则另选图中一个未被访问的顶点作为始点,重复上述过程,直至图中所有顶点都被访问到为止。

广度优先搜索:从图中某个顶点出发,访问此顶点,然后依次从该顶点未被访问的邻接点出发广度优先遍历图,直到图中所有和该顶点有路径相通的顶点都被访问到;若此时图中尚有顶点未被访问,则另选图中一个未被访问的顶点作为始点,重复上述过程,直至图中所有顶点都被访问到为止。注意同一层的即同为顶层的邻接点的下一层都是要轮流访问的,如左结点的下一层邻接点访问完就该到右结点的下一层访问邻接点。

最小生成树:在n个顶点中,图中最多的边有n(n-1),而连通n个顶点最少需要n-1条边,假设边上有权值,则需要根据普利姆算法或者克鲁斯卡尔算法从n(n-1)条边中选择代价最小的n-1条边,构成生成树。

拓扑排序:可判断网中是否出现有向环,在有向图中选一个没有前驱的顶点且输出它,从图中删除该顶点和所有以它为尾的弧,重复上述两步,直到把所有顶点已输出,则说明为无环有向图。

关键路径:从源点到终点路径长度最长的路径叫关键路径,顶点叫事件,边叫活动。事件开始的最早时间,事件开始的最晚事件

最短路径:源点到某一点路径的长度最小为最短路径。

          堆(动态存储管理)

       排序

   可查看http://blog.jobbole.com/11745/


归并排序:把一个长度为n的数组相邻的长度为1子序列归并,得到n/2个长度为2或者为2的子序列,再将相邻的子序列两两合并,反复执行,直到只有一个序列为止

选择排序:选择从一个数组中选最大的,依次与前面的交换(不用定义一个新数组,就用flag标志最小的),需交换n次

堆排序:把无序数组建成一个堆,数组第一个元素开始做根节点,接下来两个元素做左右孩子结点,两个孩子结点再从接下来的4个元素作为孩子结点,直到数组元素用完;之                  后输出堆顶(堆顶为最大的为大顶堆,排序为大到小,为最小的是小顶堆,小到大排序),之后堆顶元素与最后一个元素交换( 完全二叉树中最下层,从右开始那边结                 点),之后堆被破坏,重新建立堆,再输出堆顶,再重建。。。

插入排序:从一个数组中第一个开始认为有序的,依次需后面的元素插入到这个有序的合适位置中arr[j+1]=arr[j];(所以要移动元素)

希尔排序:

快速排序:从一个数组中第一个元素作为关键字,从最后一个元素开始与它比较,比它小就交换,一交换完,接着就用第二元素与它比较,比它小就接着用第三个元素与它比                         较。第一趟结束后分为以关键字位置为标识,它后面的序列比前面的序列还要大,前面序列当做一个新的序列,重新按照前面继续排,后面序列也一样,所以可用递                     归,直到i>=j (i是前面数组递增下标0开始  j是后面数组递减下标数组长度-1)

冒泡排序:第一个记录与相邻记录比较,再交换位置,在相邻记录与下一个相邻记录比较,一趟下来,最大的记录就在最后一个(小到大)

基数排序

时间复杂度(平均):

直接插入、直接选择和冒泡排序为(O(N^2))  平方

快速排序、堆排序和归并排序 为(O(nlog2n))

稳定性(相同记录是,是否移动,移动了就不稳定):

稳定的排序算法:冒泡排序、插入排序、归并排序和基数排序

不稳定的排序算法:选择排序、快速排序、希尔排序、堆排序

能处理大数据排序的算法:快速排序、堆排序、归并排序

数据量小使用排序算法:插入排序、选择排序

注意:当原表有序或基本有序时,直接插入排序和冒泡排序将大大减少比较次数和移动记录的次数,时间复杂度可降至O(n),而快速排序则相反,当原表基本有序时,将变成冒泡排序,时间复杂度提高为O(n2)。

查找

静态查找:在查找表中数据是不变化的

有序:用折半查找(表中各记录查找概率一样) 或者次优查找树

无序:顺序查找

索引表:两层表 ,第一层用顺序存储用折半查找    第二层用无序存储  所以用顺序查找

 

动态查找:在查找表中查找过程数据是变化,有删除或者插入操作

二叉排序树:树的结构通常不是一次生成的,而是在查找的过程中,当树中不存在关键字等于给定的结点时,再进行插入。特点是根结点比左孩子结点大,比右孩子的小。删除数据时根据结点位置修改指针就可以。查找用折半查找。查找次数为二叉树的不超过它的深度。

平衡二叉树:它的左右子树都是平衡二叉树,且左子树与右子树的深度之差的绝对值不超过1。平衡因子是该结点的左子树进去该结点的右子树的值,所以只能为1,0,-1,让二叉排序树满足平衡二叉树需要用平衡因子做判断,不满足就旋转使最后满足。查找与二叉排序树(二叉查找树)一样,但他们都是等概率的。

红黑树:红黑树是每个节点都带颜色的树,节点颜色或是红色或是黑色,红黑树是一种查找树。红黑树有一个重要的性质,从根节点到叶子节点的最长的路径不多于最短的路径的长度的两倍。对于红黑树,插入,删除,查找的复杂度都是O(log N)。

B-与B+树:结点上还有一系列排序的数据。

哈希表:数组与关键字  哈希函数与处理冲突方法


有些内容不是很全以及有很多算法代码没给出,今后慢慢补充!