网页右边,向下滑有目录索引,可以根据标题跳转到你想看的内容 如果右边没有就找找左边
一、数据结构
线性结构
常用的数据结构,特点是数据元素之间存在一对一的线性关系 有两种不同存储结构:顺序存储结构(线性表称为顺序表,存储元素是连续的)、链式存储结构(线性表称为链表,存储元素不一定连续,元素结点中存放数据元素以及相邻元素的地址信息) 常见线性结构有:数组、队列、链表和栈
非线性结构
二维数组,多维数组,广义表,树结构,图结构
1. 稀疏数组(了解时间换空间的思路)
假设保存一个五子棋的棋盘状态,我们通过二维数组表示棋盘,0表示空白,1表示黑子,2表示白子,下图可以看出,二维数组中记录了很多没意义的0,这时避免记录没意义的数据,就可以使用稀疏数组 处理方法
记录数组一共几行几列,有多少不同值(一般记录在arr[0]中) 把具有不同值的元素的行列及值记录在一个小规模数组中,从而缩小程序规模
稀疏数组实例(可见一个二维数组作为稀疏数组 arr[0]也就是第0行数据,记录棋盘共多少行,多少列,有几个不同值,就是非0值。因为一共8个非0值,然后依次记录这8个值的行列和值)
运行结果分析(可见类似这种无用元素非常多的数值,非常浪费空间,此时我们完全可以使用时间换取空间的方法,将数组压缩成为稀疏数组,这样我们在传输数据时,传输的数据量就由11 * 11=121个元素变为了3*3=9个) 代码(很多代码都是遍历的代码,可以省略,而且稀疏数组可以直接替换为集合,更加方便快捷)
public class SparseArray {
public static void main ( String [ ] args) {
int arr[ ] [ ] = new int [ 11 ] [ 11 ] ;
arr[ 1 ] [ 2 ] = 1 ;
arr[ 2 ] [ 3 ] = 2 ;
int sum = 0 ;
System . out. println ( "==============原数组长这样==========" ) ;
for ( int i = 0 ; i< arr. length; i++ ) {
for ( int j = 0 ; j< arr[ i] . length; j++ ) {
System . out. print ( arr[ i] [ j] + " " ) ;
if ( arr[ i] [ j] != 0 ) sum++ ;
}
System . out. println ( ) ;
}
System . out. println ( "================共有" + sum+ "个非0元素====================" ) ;
int sparseArr[ ] [ ] = new int [ sum+ 1 ] [ 3 ] ;
sparseArr[ 0 ] [ 0 ] = arr. length;
sparseArr[ 0 ] [ 1 ] = arr[ 0 ] . length;
sparseArr[ 0 ] [ 2 ] = sum;
int index = 1 ;
for ( int i = 0 ; i< arr. length; i++ ) {
for ( int j = 0 ; j< arr[ i] . length; j++ ) {
if ( arr[ i] [ j] != 0 ) {
sparseArr[ index] [ 0 ] = i;
sparseArr[ index] [ 1 ] = j;
sparseArr[ index] [ 2 ] = arr[ i] [ j] ;
index++ ;
}
}
}
System . out. println ( "===============稀疏数组结果===============" ) ;
int arr2[ ] [ ] = new int [ sparseArr[ 0 ] [ 0 ] ] [ sparseArr[ 0 ] [ 1 ] ] ;
for ( int i = 0 ; i< sparseArr. length; i++ ) {
System . out. println ( sparseArr[ i] [ 0 ] + " " + sparseArr[ i] [ 1 ] + " " + sparseArr[ i] [ 2 ] + " " ) ;
if ( i!= 0 ) arr2[ sparseArr[ i] [ 0 ] ] [ sparseArr[ i] [ 1 ] ] = sparseArr[ i] [ 2 ] ;
}
System . out. println ( "==============还原后数组长这样==========" ) ;
for ( int i = 0 ; i< arr2. length; i++ ) {
for ( int j = 0 ; j< arr2[ i] . length; j++ ) {
System . out. print ( arr2[ i] [ j] + " " ) ;
}
System . out. println ( ) ;
}
}
}
2. 队列
队列可以想象为一条只能同时通过一个人的走廊,那么有100个人想要从走廊一边走到另一边出去,那么就需要依次排队进入,先进去的就先从另一边出去,后进去的就后出 队列是一个有序列表,可用数组或链表实现,需要遵循先入先出原则,就是先进入队列中的程序、线程、数据,要先处理或执行,后进入的后处理 简单来说,就是我们从队列取数据,优先从头部取数据,也就是排在最前面,最先进队列的,而我们向队列添加数据,先从尾部添加,所以我们应该有两个指针,分别指向队列的头和尾,同时也要有一个属性,代表队列的容量
因为普通队列有一个问题,就是每取一个数据,头指针向后移一位,那么一旦头指针移到队列末尾,或者尾指针移动到末尾,此时没法移动到第一个位置,重新添加数据或获取数据,也就是一个队列只能使用一次,而循环队列解决了这个问题,当头或尾指针到达队列末尾,会根据算法,移动到可以使用的地方
实现结果(可见初始队列大小为3有3个元素1、2、3,头元素为1,当我们取出头元素1时,头元素变为2,当我们继续添加元素4时,根据环形队列特性,将前往第一个位置添加,但是我们遍历时,不能这样遍历出来,所以使用算法,达到后添加的出现在后面的效果) 代码,第一个代码块是队列数据结构整体实现,第二个代码块是测试类
public class MyQueue {
private int maxSize;
private int front;
private int rear;
private int [ ] arr;
public MyQueue ( int maxSize) {
this . maxSize = maxSize;
this . arr = new int [ this . maxSize] ;
this . front = this . rear = 0 ;
}
public MyQueue ( ) {
this . maxSize = 10 ;
this . arr = new int [ this . maxSize] ;
this . front = this . rear = 0 ;
}
public boolean isFull ( ) {
return ( rear+ 1 ) % maxSize == front;
}
public boolean isNull ( ) {
return rear == front;
}
public int effectiveElementCount ( ) {
return ( rear+ maxSize- front) % maxSize;
}
public boolean add ( int param) {
if ( isFull ( ) ) return false ;
arr[ this . rear] = param;
this . rear= ( this . rear+ 1 ) % maxSize;
return true ;
}
public int get ( ) {
if ( isNull ( ) ) {
throw new RuntimeException ( "队列为空!!!无法获取数据" ) ;
} else {
int param = arr[ this . front] ;
this . front = ( this . front+ 1 ) % maxSize;
return param;
}
}
public void showQueue ( ) {
if ( isNull ( ) ) return ;
for ( int i = front; i!= rear; i= ( i+ 1 ) % maxSize) {
System . out. print ( arr[ i] + " " ) ;
}
System . out. println ( ) ;
}
public int peekHead ( ) {
if ( isNull ( ) ) throw new RuntimeException ( "队列为空!!!没有头数据" ) ;
return arr[ this . front] ;
}
}
public class Test {
public static void main ( String [ ] args) {
MyQueue myQueue = new MyQueue ( 4 ) ;
myQueue. add ( 1 ) ;
myQueue. add ( 2 ) ;
myQueue. add ( 3 ) ;
System . out. println ( "队列元素为:" ) ;
myQueue. showQueue ( ) ;
System . out. println ( "头元素为" + myQueue. peekHead ( ) ) ;
System . out. println ( "是否满" + myQueue. isFull ( ) ) ;
System . out. println ( "取出一个数据" + myQueue. get ( ) ) ;
System . out. println ( "队列元素为:" ) ;
myQueue. showQueue ( ) ;
System . out. println ( "头元素为" + myQueue. peekHead ( ) ) ;
System . out. println ( "添加一个元素4" ) ;
myQueue. add ( 4 ) ;
System . out. println ( "队列元素为:" ) ;
myQueue. showQueue ( ) ;
System . out. println ( "头元素为" + myQueue. peekHead ( ) ) ;
if ( ! myQueue. add ( 5 ) ) System . out. println ( "添加元素5,队列满!!!无法继续添加元素" ) ;
}
}
3. 单链表
链表虽然是顺序存储,但在内存中未必 根据上图分析,head头结点,是链表第一个元素,它记录了下一个元素的内存地址150,那么通过150这个内存地址,找到a1元素,a1元素记录了它下一个元素地址110,通过110这个地址又可以找到a2元素,a2记录180地址,找到a4。依次类推 链表有带头结点的,也有不带头结点的,根据实际需求使用相应的即可 带头结点单链表逻辑结构(这是逻辑结构,虽然图表示出来a1后面就是a2,a2后面就是a3,但是实际上在内存中,他们未必甚至很难是连续的,而是通过指针依次找到他们,详细看上一张图)
运行结果与思路(首先链表,整体是一个对象,而每个结点又是一个对象(每个结点可以存储任意类型元素数据,但是我们链表只存储结点对象),整个链表通过head表示头结点,last表示下一个结点,next是每个结点指向的下一个节点,没有下一个节点,则赋值为null) 代码(第一个代码块是结点,第二个是链表,第三个是测试类)
public class ListNode {
private Object data;
private ListNode next;
public ListNode ( Object data) {
this . data = data;
}
public Object getData ( ) {
return data;
}
public void setData ( Object data) {
this . data = data;
}
public ListNode getNext ( ) {
return next;
}
public void setNext ( ListNode next) {
this . next = next;
}
}
public class SingleLinkList {
private ListNode head = null ;
private ListNode last = null ;
public int size = 0 ;
public void add ( Object element) {
if ( head == null ) {
head = new ListNode ( element) ;
last = head;
} else {
last. setNext ( new ListNode ( element) ) ;
last = last. getNext ( ) ;
}
size++ ;
}
public int indexOf ( Object element) {
ListNode node = head;
int index = 0 ;
while ( node != null ) {
if ( node. getData ( ) . equals ( element) ) {
return index;
}
index++ ;
node = node. getNext ( ) ;
}
return - 1 ;
}
public void delete ( Object element) {
ListNode node = head;
ListNode pre = null ;
while ( node != null ) {
if ( node. getData ( ) . equals ( element) ) {
if ( pre != null ) {
if ( node. getNext ( ) == null )
pre. setNext ( null ) ;
else
pre. setNext ( node. getNext ( ) ) ;
} else {
head = node. getNext ( ) ;
}
size-- ;
}
pre = node;
node = node. getNext ( ) ;
}
}
private ListNode selectNodeByIndex ( Integer index) {
if ( index < 0 || index >= size) {
System . out. println ( "下标无效" ) ;
return null ;
}
ListNode node = head;
int i = 0 ;
while ( i != index) {
node = node. getNext ( ) ;
i++ ;
}
return node;
}
public void deleteByIndex ( Integer index) {
if ( index < 0 || index >= size) {
System . out. println ( "下标无效" ) ;
return ;
}
delete ( selectNodeByIndex ( index) . getData ( ) ) ;
}
public void update ( Integer index, Object newElement) {
selectNodeByIndex ( index) . setData ( newElement) ;
}
public boolean selectByElement ( Object element) {
if ( indexOf ( element) >= 0 ) return true ;
return false ;
}
public Object selectByIndex ( Integer index) {
return selectNodeByIndex ( index) . getData ( ) ;
}
public String toString ( ) {
StringBuffer stringBuffer = new StringBuffer ( ) ;
ListNode node = head;
stringBuffer. append ( "[" ) ;
while ( node. getNext ( ) != null ) {
stringBuffer. append ( node. getData ( ) + " , " ) ;
node = node. getNext ( ) ;
}
stringBuffer. append ( node. getData ( ) + "]" ) ;
return stringBuffer. toString ( ) ;
}
}
class Test {
public static void main ( String [ ] args) {
Test arr[ ] = new Test [ 7 ] ;
for ( int i = 0 ; i< 7 ; i++ ) {
arr[ i] = new Test ( ) ;
}
System . out. println ( "=========================" ) ;
arr[ 0 ] . add ( ) ;
System . out. println ( "=========================" ) ;
arr[ 1 ] . indexOf ( ) ;
System . out. println ( "=========================" ) ;
arr[ 2 ] . delete ( ) ;
System . out. println ( "=========================" ) ;
arr[ 3 ] . deleteByIndex ( ) ;
System . out. println ( "=========================" ) ;
arr[ 4 ] . update ( ) ;
System . out. println ( "=========================" ) ;
arr[ 5 ] . selectByElement ( ) ;
System . out. println ( "=========================" ) ;
arr[ 6 ] . selectByIndex ( ) ;
}
private SingleLinkList singleLinkList = new SingleLinkList ( ) ;
void add ( ) {
singleLinkList. add ( 1 ) ;
singleLinkList. add ( "张三" ) ;
singleLinkList. add ( 3 ) ;
singleLinkList. add ( 4 ) ;
System . out. println ( "当前链表元素为:" + singleLinkList. toString ( ) + "~~~~共有元素" + singleLinkList. size+ "个" ) ;
}
void indexOf ( ) {
add ( ) ;
System . out. println ( "元素 1 的下标为:" + singleLinkList. indexOf ( 1 ) ) ;
System . out. println ( "元素 张三 的下标为:" + singleLinkList. indexOf ( "张三" ) ) ;
System . out. println ( "元素 3 的下标为:" + singleLinkList. indexOf ( 3 ) ) ;
System . out. println ( "元素 4 的下标为:" + singleLinkList. indexOf ( 4 ) ) ;
}
void delete ( ) {
add ( ) ;
singleLinkList. delete ( 1 ) ;
System . out. println ( "删除1后的链表为:" + singleLinkList. toString ( ) ) ;
singleLinkList. delete ( 3 ) ;
System . out. println ( "删除3后的链表为:" + singleLinkList. toString ( ) ) ;
singleLinkList. delete ( 4 ) ;
System . out. println ( "删除4后的链表为:" + singleLinkList. toString ( ) ) ;
}
void deleteByIndex ( ) {
add ( ) ;
singleLinkList. deleteByIndex ( 0 ) ;
System . out. println ( "删除下标为0元素后的链表为:" + singleLinkList. toString ( ) ) ;
singleLinkList. deleteByIndex ( 1 ) ;
System . out. println ( "删除下标为1元素后的链表为:" + singleLinkList. toString ( ) ) ;
singleLinkList. deleteByIndex ( 1 ) ;
System . out. println ( "删除下标为1元素后的链表为:" + singleLinkList. toString ( ) ) ;
}
void update ( ) {
add ( ) ;
singleLinkList. update ( 0 , "new 0" ) ;
System . out. println ( "修改下标为0元素数据为new 0 后链表:" + singleLinkList. toString ( ) ) ;
singleLinkList. update ( 1 , "new 1" ) ;
System . out. println ( "修改下标为1元素数据为new 1 后链表:" + singleLinkList. toString ( ) ) ;
singleLinkList. update ( 2 , "new 2" ) ;
System . out. println ( "修改下标为2元素数据为new 2 后链表:" + singleLinkList. toString ( ) ) ;
singleLinkList. update ( 3 , "new 3" ) ;
System . out. println ( "修改下标为3元素数据为new 3 后链表:" + singleLinkList. toString ( ) ) ;
}
void selectByElement ( ) {
add ( ) ;
System . out. println ( "列表是否存在数据 张三:" + singleLinkList. selectByElement ( "张三" ) ) ;
}
void selectByIndex ( ) {
add ( ) ;
System . out. println ( "下标为2的数据为:" + singleLinkList. selectByIndex ( 2 ) ) ;
}
}
面试题1:求单链表中有效节点个数
运行效果 代码
public int getLength ( ListNode head) {
if ( head == null ) return 0 ;
int length = 1 ;
ListNode node = head. getNext ( ) ;
while ( node != null ) {
length++ ;
node = node. getNext ( ) ;
}
return length;
}
面试题2:查找单链表中的倒数第k个节点
实现结果 代码
public ListNode TheLastNumber ( int k) {
int index = size - k;
if ( selectNodeByIndex ( index) == null ) {
System . out. println ( "没有找到结点···省略了异常处理" ) ;
return null ;
} else {
return selectNodeByIndex ( index) ;
}
}
private ListNode selectNodeByIndex ( Integer index) {
if ( index < 0 || index >= size) {
System . out. println ( "下标无效" ) ;
return null ;
}
ListNode node = head;
int i = 0 ;
while ( i != index) {
node = node. getNext ( ) ;
i++ ;
}
return node;
}
面试题3:单链表的反转
运行效果 代码
public void reverseLinkList ( ) {
ListNode reverseHead = new ListNode ( 0 ) ;
ListNode node = head;
head = null ;
ListNode next = null ;
while ( node != null ) {
next = node. getNext ( ) ;
node. setNext ( reverseHead. getNext ( ) ) ;
reverseHead. setNext ( node) ;
node = next;
}
head = reverseHead. getNext ( ) ;
}
面试题4:从尾到头打印单链表(方式一:反向遍历,方式二:Stack栈)
分析及运行效果
方式一反向遍历:先将单链表反转(上一道题的方法),然后遍历,会破坏链表结果,浪费空间,不推荐 利用数据结构,栈,将各个节点压入栈中,因为栈的特性是先进后出,就可以方便实现逆序打印
代码
public void reversePrint ( ) {
ListNode node = head;
Stack < ListNode > stack = new Stack < > ( ) ;
while ( node != null ) {
stack. add ( node) ;
node = node. getNext ( ) ;
}
while ( stack. size ( ) != 0 ) {
System . out. print ( stack. pop ( ) . getData ( ) + " " ) ;
}
}
面试题5:合并两个有序的单链表,合并之后的链表依然有序
面试题6:Josephu约瑟夫问题,使用单向环形链表
单向环形链表和单链表不同的地方就是,最后一个结点指向不是null了,而是头结点
Josephu问题
设编号为1,2,…n的n个人围坐在一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,知道所有人出列为止,由此产生一个出队编号的序列 思路,利用不带头结点的循环链表处理Josephu问题,先构成一个有n个结点的单循环链表,然后由k结点起从1开始计数,记到m时,对应节点从链表中删除,然后再从被删除结点的下一个结点又从1开始计数,直到最后一个结点从链表中删除算法结束
代码
public class Josephu {
public static void main ( String [ ] args) {
CircularLinkedList circularLinkedList = new CircularLinkedList ( ) ;
circularLinkedList. add ( 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ) ;
circularLinkedList. showPrint ( ) ;
System . out. println ( "从第一个结点报数,报的3的结点出列:" ) ;
circularLinkedList. josephu ( 1 , 3 ) ;
}
}
class JosephuNode {
private int data;
private JosephuNode next;
public JosephuNode ( int data) {
this . data = data;
}
public int getData ( ) {
return data;
}
public JosephuNode getNext ( ) {
return next;
}
public void setData ( int data) {
this . data = data;
}
public void setNext ( JosephuNode next) {
this . next = next;
}
}
class CircularLinkedList {
private JosephuNode first = null ;
private int size = 0 ;
public void add ( int . . . nums) {
if ( nums. length<= 1 ) {
System . out. println ( "结点必须多于1个!!!" ) ;
}
size = nums. length;
first = new JosephuNode ( nums[ 0 ] ) ;
first. setNext ( first) ;
JosephuNode node = first;
for ( int i = 1 ; i< nums. length; i++ ) {
JosephuNode josephuNode = new JosephuNode ( nums[ i] ) ;
node. setNext ( josephuNode) ;
josephuNode. setNext ( first) ;
node = josephuNode;
}
}
public void showPrint ( ) {
if ( first== null ) {
System . out. println ( "链表为空!!!" ) ;
return ;
}
JosephuNode node = first;
System . out. println ( "循环链表值为:" ) ;
while ( node. getNext ( ) != first) {
System . out. print ( node. getData ( ) + " " ) ;
node = node. getNext ( ) ;
}
System . out. println ( node. getData ( ) ) ;
}
public void josephu ( int k , int m) {
if ( k > size) {
System . out. println ( "一共就" + size+ "个节点,没有第" + k+ "个值" ) ;
return ;
}
JosephuNode node = first;
for ( int i = 1 ; i< k; i++ ) {
node = node. getNext ( ) ;
}
while ( size != 0 ) {
for ( int i = 2 ; i < m; i++ ) {
node = node. getNext ( ) ;
}
System . out. print ( node. getNext ( ) . getData ( ) + " " ) ;
node. setNext ( node. getNext ( ) . getNext ( ) ) ;
node = node. getNext ( ) ;
size-- ;
}
}
}
4. 双链表
它每个结点都有3个属性,前驱(记录前一个结点),数据,后继(记录后一个结点) 头结点前驱为null,尾结点后继为null 插入数据都是在两端插入,可以插入到前面,也可以插入到后面 如果头结点前驱指向为尾结点,尾结点后继指向头结点,此时链表变为循环链表(日后介绍)
运行效果 2. 代码(第一个代码块是结点实体类,第二个代码块是双链表实现类,第三代码块是测试代码)
public class DoubleListNode {
private Object data;
private DoubleListNode pre;
private DoubleListNode next;
public DoubleListNode ( Object data) {
this . data = data;
}
public DoubleListNode ( DoubleListNode pre, Object data, DoubleListNode next) {
this . pre = pre;
this . data = data;
this . next = next;
}
public Object getData ( ) {
return data;
}
public void setData ( Object data) {
this . data = data;
}
public DoubleListNode getPre ( ) {
return pre;
}
public void setPre ( DoubleListNode pre) {
this . pre = pre;
}
public DoubleListNode getNext ( ) {
return next;
}
public void setNext ( DoubleListNode next) {
this . next = next;
}
}
public class DoubleLinkList {
private DoubleListNode head;
private DoubleListNode last;
public int size = 0 ;
public void linkFirst ( Object element) {
final DoubleListNode first = head;
final DoubleListNode newNode = new DoubleListNode ( null , element, first) ;
head = newNode;
if ( first == null ) {
last = newNode;
} else {
first. setPre ( newNode) ;
}
size++ ;
}
public void linkLast ( Object element) {
final DoubleListNode l = last;
final DoubleListNode newNode = new DoubleListNode ( l, element, null ) ;
last = newNode;
if ( l == null ) {
head = newNode;
} else {
l. setNext ( newNode) ;
}
size++ ;
}
public void add ( Object element) {
linkLast ( element) ;
}
private DoubleListNode selectNodeByIndex ( Integer index) {
if ( index < 0 || index >= size) {
System . out. println ( "下标无效" ) ;
return null ;
}
DoubleListNode node = head;
int i = 0 ;
while ( i != index) {
node = node. getNext ( ) ;
i++ ;
}
return node;
}
private DoubleListNode selectNodeByElement ( Object element) {
DoubleListNode node = head;
while ( node != null ) {
if ( node. getData ( ) . equals ( element) ) {
return node;
}
node = node. getNext ( ) ;
}
return null ;
}
public int indexOf ( Object element) {
DoubleListNode node = head;
int index = 0 ;
while ( node != null ) {
if ( node. getData ( ) . equals ( element) ) {
return index;
}
index++ ;
node = node. getNext ( ) ;
}
return - 1 ;
}
public void delete ( Object element) {
DoubleListNode node = selectNodeByElement ( element) ;
if ( node == null ) {
System . out. println ( "要删除的结点不存在" ) ;
return ;
}
if ( node. getPre ( ) == null )
head = node. getNext ( ) ;
else
node. getPre ( ) . setNext ( node. getNext ( ) ) ;
if ( node. getNext ( ) == null )
last = node. getPre ( ) ;
else
node. getNext ( ) . setPre ( node. getPre ( ) ) ;
size-- ;
}
public void deleteByIndex ( Integer index) {
if ( index < 0 || index >= size) {
System . out. println ( "下标无效" ) ;
return ;
}
delete ( selectNodeByIndex ( index) . getData ( ) ) ;
}
public void update ( Integer index, Object newElement) {
selectNodeByIndex ( index) . setData ( newElement) ;
}
public boolean selectByElement ( Object element) {
if ( indexOf ( element) >= 0 ) return true ;
return false ;
}
public Object selectByIndex ( Integer index) {
return selectNodeByIndex ( index) . getData ( ) ;
}
@Override
public String toString ( ) {
StringBuffer stringBuffer = new StringBuffer ( ) ;
DoubleListNode node = head;
stringBuffer. append ( "[" ) ;
while ( node. getNext ( ) != null ) {
stringBuffer. append ( node. getData ( ) + " , " ) ;
node = node. getNext ( ) ;
}
stringBuffer. append ( node. getData ( ) + "]" ) ;
return stringBuffer. toString ( ) ;
}
}
class Test {
public static void main ( String [ ] args) {
Test arr[ ] = new Test [ 7 ] ;
for ( int i = 0 ; i< 7 ; i++ ) {
arr[ i] = new Test ( ) ;
}
System . out. println ( "=========================" ) ;
arr[ 0 ] . add ( ) ;
System . out. println ( "=========================" ) ;
arr[ 1 ] . indexOf ( ) ;
System . out. println ( "=========================" ) ;
arr[ 2 ] . delete ( ) ;
System . out. println ( "=========================" ) ;
arr[ 3 ] . deleteByIndex ( ) ;
System . out. println ( "=========================" ) ;
arr[ 4 ] . update ( ) ;
System . out. println ( "=========================" ) ;
arr[ 5 ] . selectByElement ( ) ;
System . out. println ( "=========================" ) ;
arr[ 6 ] . selectByIndex ( ) ;
}
private DoubleLinkList doubleLinkList = new DoubleLinkList ( ) ;
void add ( ) {
doubleLinkList. add ( 1 ) ;
doubleLinkList. add ( "张三" ) ;
doubleLinkList. add ( 3 ) ;
doubleLinkList. add ( 4 ) ;
System . out. println ( "当前链表元素为:" + doubleLinkList. toString ( ) + "~~~~共有元素" + doubleLinkList. size+ "个" ) ;
}
void indexOf ( ) {
add ( ) ;
System . out. println ( "元素 1 的下标为:" + doubleLinkList. indexOf ( 1 ) ) ;
System . out. println ( "元素 张三 的下标为:" + doubleLinkList. indexOf ( "张三" ) ) ;
System . out. println ( "元素 3 的下标为:" + doubleLinkList. indexOf ( 3 ) ) ;
System . out. println ( "元素 4 的下标为:" + doubleLinkList. indexOf ( 4 ) ) ;
}
void delete ( ) {
add ( ) ;
doubleLinkList. delete ( 1 ) ;
System . out. println ( "删除1后的链表为:" + doubleLinkList. toString ( ) ) ;
doubleLinkList. delete ( 3 ) ;
System . out. println ( "删除3后的链表为:" + doubleLinkList. toString ( ) ) ;
doubleLinkList. delete ( 4 ) ;
System . out. println ( "删除4后的链表为:" + doubleLinkList. toString ( ) ) ;
}
void deleteByIndex ( ) {
add ( ) ;
doubleLinkList. deleteByIndex ( 0 ) ;
System . out. println ( "删除下标为0元素后的链表为:" + doubleLinkList. toString ( ) ) ;
doubleLinkList. deleteByIndex ( 1 ) ;
System . out. println ( "删除下标为1元素后的链表为:" + doubleLinkList. toString ( ) ) ;
doubleLinkList. deleteByIndex ( 1 ) ;
System . out. println ( "删除下标为1元素后的链表为:" + doubleLinkList. toString ( ) ) ;
}
void update ( ) {
add ( ) ;
doubleLinkList. update ( 0 , "new 0" ) ;
System . out. println ( "修改下标为0元素数据为new 0 后链表:" + doubleLinkList. toString ( ) ) ;
doubleLinkList. update ( 1 , "new 1" ) ;
System . out. println ( "修改下标为1元素数据为new 1 后链表:" + doubleLinkList. toString ( ) ) ;
doubleLinkList. update ( 2 , "new 2" ) ;
System . out. println ( "修改下标为2元素数据为new 2 后链表:" + doubleLinkList. toString ( ) ) ;
doubleLinkList. update ( 3 , "new 3" ) ;
System . out. println ( "修改下标为3元素数据为new 3 后链表:" + doubleLinkList. toString ( ) ) ;
}
void selectByElement ( ) {
add ( ) ;
System . out. println ( "列表是否存在数据 张三:" + doubleLinkList. selectByElement ( "张三" ) ) ;
}
void selectByIndex ( ) {
add ( ) ;
System . out. println ( "下标为2的数据为:" + doubleLinkList. selectByIndex ( 2 ) ) ;
}
}
五、栈
根据例子体会栈的作用(一个表达式,它是一个字符串,我们需要分析数字,运算符,然后确定运算顺序。) 什么是栈
栈的英文为(stack) 栈是一个先入后出(FILO-First In Last Out)的有序列表。 栈(stack)是限制线性表中元素的插入和删除只能在线性表的同一端进行的一种特殊线性表。允许插入和删除的一端,为变化的一端,称为栈顶(Top),另一端为固定的一端,称为栈底(Bottom)。 根据栈的定义可知,最先放入栈中元素在栈底,最后放入的元素在栈顶,而删除元素刚好相反,最后放入的元素最先删除,最先放入的元素最后删除
入栈和出栈
实现思路—数组
通过数组模拟栈,我们需要top变量,指向栈顶,入栈时,top++,出栈时top–, 栈的大小也需要一个变量来规定
运行结果 代码
public class ArrayStackDome {
public static void main ( String [ ] args) {
ArrayStack arrayStack = new ArrayStack ( 5 ) ;
arrayStack. push ( 1 ) ;
arrayStack. push ( 2 ) ;
arrayStack. push ( 3 ) ;
arrayStack. push ( 4 ) ;
arrayStack. push ( 5 ) ;
arrayStack. showPrint ( ) ;
for ( int i = 0 ; i< 6 ; i++ ) {
System . out. println ( "=========执行出栈操作=============" ) ;
arrayStack. pop ( ) ;
arrayStack. showPrint ( ) ;
}
}
}
class ArrayStack {
private int [ ] stack;
private int top = - 1 ;
private int maxSize;
public ArrayStack ( int maxSize) {
this . maxSize = maxSize;
stack = new int [ maxSize] ;
}
private boolean isFull ( ) {
if ( top >= maxSize - 1 ) return false ;
return true ;
}
public boolean isEmpty ( ) {
return top == - 1 ;
}
public void push ( int element) {
if ( ! isFull ( ) ) {
System . out. println ( "栈已满!!!" ) ;
return ;
}
top++ ;
stack[ top] = element;
}
public int pop ( ) {
if ( isEmpty ( ) ) {
throw new RuntimeException ( "栈为空,无法执行出栈操作!!!" ) ;
}
return stack[ top-- ] ;
}
public void showPrint ( ) {
if ( isEmpty ( ) ) {
System . out. println ( "栈已空!!!" ) ;
return ;
}
System . out. println ( "栈中元素从栈顶到栈低依次为;" ) ;
for ( int i = top; i>= 0 ; i-- ) {
System . out. print ( stack[ i] + " " ) ;
}
System . out. println ( ) ;
}
}
面试题1:使用栈完成计算一位数加减乘除表达式的结果
思路分析(两个栈,一个存表达式的数字,一个存表达式的运算符,数字直接入数字栈,每个运算符入栈前,都进行判断,如果栈中没有运算符直接入栈,如果不是判断优先级,优先级比栈顶运算符大,直接入栈,比栈顶小,那么弹出当前栈顶的运算符(不是现在要入栈的运算符),再弹出数字栈中的两个数,进行运算,运算结果入栈到数字栈,然后当前运算符入栈,依次类推) 代码效果
代码(为了大家理解,加了很多输出语句,删掉其实没有多少代码)
public class ArrayStackDome {
public static void main ( String [ ] args) {
String str = new String ( "7*2*2-5+1-5+3-4" ) ;
System . out. println ( "计算表达式:" + str) ;
char [ ] chars = str. toCharArray ( ) ;
Map < Character , Integer > level = new HashMap < > ( ) ;
level. put ( '*' , 10 ) ;
level. put ( '/' , 10 ) ;
level. put ( '%' , 10 ) ;
level. put ( '+' , 9 ) ;
level. put ( '-' , 9 ) ;
ArrayStack numStack = new ArrayStack ( 15 ) ;
ArrayStack operStack = new ArrayStack ( 15 ) ;
for ( char c: chars) {
if ( level. get ( c) != null ) {
if ( operStack. isEmpty ( ) ) {
System . out. println ( "符号栈为空=====入栈" + c) ;
operStack. push ( c) ;
} else {
char pop = ( char ) operStack. pop ( ) ;
System . out. print ( "弹出" + pop+ "比较" + c+ " ============" ) ;
if ( level. get ( c) <= level. get ( pop) ) {
System . out. println ( "当前运算符优先级<=栈顶运算符" ) ;
switch ( pop) {
case '+' : {
int a = numStack. pop ( ) ;
int b = numStack. pop ( ) ;
System . out. print ( "数字栈弹出" + a+ "和" + b+ "计算" + a+ "+" + b+ "入栈" + ( a+ b) ) ;
numStack. push ( a+ b) ; break ;
}
case '-' : {
int a = numStack. pop ( ) ;
int b = numStack. pop ( ) ;
System . out. print ( "数字栈弹出" + a+ "和" + b+ "计算" + b+ "-" + a+ "入栈" + ( b- a) ) ;
numStack. push ( b- a) ; break ;
}
case '*' : {
int a = numStack. pop ( ) ;
int b = numStack. pop ( ) ;
System . out. print ( "数字栈弹出" + a+ "和" + b+ "计算" + a+ "*" + b+ "入栈" + ( a* b) ) ;
numStack. push ( a* b) ; break ;
}
case '/' : {
int a = numStack. pop ( ) ;
int b = numStack. pop ( ) ;
System . out. print ( "数字栈弹出" + a+ "和" + b+ "计算" + b+ "/" + a+ "入栈" + ( b/ a) ) ;
numStack. push ( b/ a) ; break ;
}
}
System . out. println ( " 符号栈入栈" + c) ;
operStack. push ( c) ;
} else {
System . out. println ( "===========运算符" + c+ "优先级没有栈顶" + pop+ "高,两个哥们入栈" ) ;
operStack. push ( pop) ;
operStack. push ( c) ;
}
}
} else {
Integer integer = Integer . valueOf ( c + "" ) ;
numStack. push ( integer) ;
System . out. println ( "数字栈入栈======" + integer) ;
}
}
while ( ! operStack. isEmpty ( ) ) {
char pop = ( char ) operStack. pop ( ) ;
switch ( pop) {
case '+' : {
int a = numStack. pop ( ) ;
int b = numStack. pop ( ) ;
System . out. print ( "数字栈弹出" + a+ "和" + b+ "计算" + a+ "+" + b+ "入栈" + ( a+ b) ) ;
numStack. push ( a+ b) ; break ;
}
case '-' : {
int a = numStack. pop ( ) ;
int b = numStack. pop ( ) ;
System . out. print ( "数字栈弹出" + a+ "和" + b+ "计算" + b+ "-" + a+ "入栈" + ( b- a) ) ;
numStack. push ( b- a) ; break ;
}
case '*' : {
int a = numStack. pop ( ) ;
int b = numStack. pop ( ) ;
System . out. print ( "数字栈弹出" + a+ "和" + b+ "计算" + a+ "*" + b+ "入栈" + ( a* b) ) ;
numStack. push ( a* b) ; break ;
}
case '/' : {
int a = numStack. pop ( ) ;
int b = numStack. pop ( ) ;
System . out. print ( "数字栈弹出" + a+ "和" + b+ "计算" + b+ "/" + a+ "入栈" + ( b/ a) ) ;
numStack. push ( b/ a) ; break ;
}
}
}
System . out. println ( ) ;
numStack. showPrint ( ) ;
System . out. println ( "弹出最终运算结果:" + numStack. pop ( ) ) ;
}
}
面试题2:使用栈完成计算多位数加减乘除的结果
分析
我们需要解决字符串一位一位读入的问题,比如70+1的读入是,7、0、+、1 我们需要将70作为一个整体数字,压栈
运行效果 修改的代码部分
int num = 0 ;
for ( int i = 0 ; i< chars. length; i++ ) {
char c = chars[ i] ;
if ( level. get ( c) != null ) {
if ( operStack. isEmpty ( ) ) {
operStack. push ( c) ;
} else {
char pop = ( char ) operStack. pop ( ) ;
if ( level. get ( c) <= level. get ( pop) ) {
switch ( pop) {
case '+' : {
int a = numStack. pop ( ) ;
int b = numStack. pop ( ) ;
numStack. push ( a+ b) ; break ;
}
case '-' : {
int a = numStack. pop ( ) ;
int b = numStack. pop ( ) ;
numStack. push ( b- a) ; break ;
}
case '*' : {
int a = numStack. pop ( ) ;
int b = numStack. pop ( ) ;
numStack. push ( a* b) ; break ;
}
case '/' : {
int a = numStack. pop ( ) ;
int b = numStack. pop ( ) ;
numStack. push ( b/ a) ; break ;
}
}
operStack. push ( c) ;
} else {
operStack. push ( pop) ;
operStack. push ( c) ;
}
}
} else {
Integer integer = Integer . valueOf ( c + "" ) ;
num= num* 10 + integer;
if ( i != chars. length- 1 ) {
if ( level. get ( chars[ i+ 1 ] ) == null )
continue ;
}
numStack. push ( num) ;
}
num = 0 ;
}
面试题3:前缀(波兰表达式)、中缀、后缀表达式(逆波兰表达式)
前缀表达式(波兰表达式)
前缀表达式的运算符位于操作数之前 举例:(3+4) * 5 - 6 对应前缀表达式为- * + 3 4 5 6
中缀表达式
就是我们常见的运算表达式(3+4)*5-6 是我们最为熟悉的表达式,但是对计算机来说却不好操作(我们前两道题就能看出此问题),因此,计算机计算结果时,会将中缀表达式转成其它表达式来操作(一般转变成后缀表达式)
后缀表达式(逆波兰表达式)
后缀表达式与前缀表达式相似,只是运算符位于操作数之后(可以理解为每个运算符会匹配前面两个数字运算,运算结果重新填回表达式,例如a+(b-c) 首先+运算符,对应a和(b-c),所以为a (b-c) +,而-运算符对应b和c,所以为 b c - ,那么最后将结果拼接为:a b c - +) 例如:(3+4)*5-6 对应的后缀表达式就是3 4 + 5 * 6 - 再比如a+b对应a b +、a+(b-c)对应 a b c - +、a+(b-c)*d对应a b c - d * + a+d*(b-c)对应a d b c - * + a = 1+3 对应 a 1 3 + =
难点分析
中缀表达式转换为后缀表达式
运行结果 代码
import java. util. ArrayList ;
import java. util. List ;
import java. util. Stack ;
public class Test {
public static void main ( String [ ] args) {
String expression = "1+((2+3)*4)-5" ;
List < String > infixExpressionList = toInfixExpressionList ( expression) ;
System . out. println ( "中缀表达式对应的List=" + infixExpressionList) ;
List < String > suffixExpreesionList = parseSuffixExpreesionList ( infixExpressionList) ;
System . out. println ( "后缀表达式对应的List" + suffixExpreesionList) ;
System . out. printf ( "expression=%d" , calculate ( suffixExpreesionList) ) ;
}
public static List < String > parseSuffixExpreesionList ( List < String > ls) {
Stack < String > s1 = new Stack < String > ( ) ;
List < String > s2 = new ArrayList < String > ( ) ;
for ( String item: ls) {
if ( item. matches ( "\\d+" ) ) {
s2. add ( item) ;
} else if ( item. equals ( "(" ) ) {
s1. push ( item) ;
} else if ( item. equals ( ")" ) ) {
while ( ! s1. peek ( ) . equals ( "(" ) ) {
s2. add ( s1. pop ( ) ) ;
}
s1. pop ( ) ;
} else {
while ( s1. size ( ) != 0 && Operation . getValue ( s1. peek ( ) ) >= Operation . getValue ( item) ) {
s2. add ( s1. pop ( ) ) ;
}
s1. push ( item) ;
}
}
while ( s1. size ( ) != 0 ) {
s2. add ( s1. pop ( ) ) ;
}
return s2;
}
public static List < String > toInfixExpressionList ( String s) {
List < String > ls = new ArrayList < String > ( ) ;
int i = 0 ;
String str;
char c;
do {
if ( ( c= s. charAt ( i) ) < 48 || ( c= s. charAt ( i) ) > 57 ) {
ls. add ( "" + c) ;
i++ ;
} else {
str = "" ;
while ( i < s. length ( ) && ( c= s. charAt ( i) ) >= 48 && ( c= s. charAt ( i) ) <= 57 ) {
str += c;
i++ ;
}
ls. add ( str) ;
}
} while ( i < s. length ( ) ) ;
return ls;
}
public static int calculate ( List < String > ls) {
Stack < String > stack = new Stack < String > ( ) ;
for ( String item : ls) {
if ( item. matches ( "\\d+" ) ) {
stack. push ( item) ;
} else {
int num2 = Integer . parseInt ( stack. pop ( ) ) ;
int num1 = Integer . parseInt ( stack. pop ( ) ) ;
int res = 0 ;
if ( item. equals ( "+" ) ) {
res = num1 + num2;
} else if ( item. equals ( "-" ) ) {
res = num1 - num2;
} else if ( item. equals ( "*" ) ) {
res = num1 * num2;
} else if ( item. equals ( "/" ) ) {
res = num1 / num2;
} else {
throw new RuntimeException ( "运算符有误" ) ;
}
stack. push ( "" + res) ;
}
}
return Integer . parseInt ( stack. pop ( ) ) ;
}
}
class Operation {
private static int ADD = 1 ;
private static int SUB = 1 ;
private static int MUL = 2 ;
private static int DIV = 2 ;
public static int getValue ( String operation) {
int result = 0 ;
switch ( operation) {
case "+" :
result = ADD;
break ;
case "-" :
result = SUB;
break ;
case "*" :
result = MUL;
break ;
case "/" :
result = DIV;
break ;
default :
System . out. println ( "不存在该运算符" + operation) ;
break ;
}
return result;
}
}
import java. util. ArrayList ;
import java. util. Collections ;
import java. util. List ;
import java. util. Stack ;
import java. util. regex. Pattern ;
public class ReversePolishMultiCalc {
static final String SYMBOL = "\\+|-|\\*|/|\\(|\\)" ;
static final String LEFT = "(" ;
static final String RIGHT = ")" ;
static final String ADD = "+" ;
static final String MINUS= "-" ;
static final String TIMES = "*" ;
static final String DIVISION = "/" ;
static final int LEVEL_01 = 1 ;
static final int LEVEL_02 = 2 ;
static final int LEVEL_HIGH = Integer . MAX_VALUE;
static Stack < String > stack = new Stack < > ( ) ;
static List < String > data = Collections . synchronizedList ( new ArrayList < String > ( ) ) ;
public static String replaceAllBlank ( String s ) {
return s. replaceAll ( "\\s+" , "" ) ;
}
public static boolean isNumber ( String s) {
Pattern pattern = Pattern . compile ( "^[-\\+]?[.\\d]*$" ) ;
return pattern. matcher ( s) . matches ( ) ;
}
public static boolean isSymbol ( String s) {
return s. matches ( SYMBOL) ;
}
public static int calcLevel ( String s) {
if ( "+" . equals ( s) || "-" . equals ( s) ) {
return LEVEL_01;
} else if ( "*" . equals ( s) || "/" . equals ( s) ) {
return LEVEL_02;
}
return LEVEL_HIGH;
}
public static List < String > doMatch ( String s) throws Exception {
if ( s == null || "" . equals ( s. trim ( ) ) ) throw new RuntimeException ( "data is empty" ) ;
if ( ! isNumber ( s. charAt ( 0 ) + "" ) ) throw new RuntimeException ( "data illeagle,start not with a number" ) ;
s = replaceAllBlank ( s) ;
String each;
int start = 0 ;
for ( int i = 0 ; i < s. length ( ) ; i++ ) {
if ( isSymbol ( s. charAt ( i) + "" ) ) {
each = s. charAt ( i) + "" ;
if ( stack. isEmpty ( ) || LEFT. equals ( each)
|| ( ( calcLevel ( each) > calcLevel ( stack. peek ( ) ) ) && calcLevel ( each) < LEVEL_HIGH) ) {
stack. push ( each) ;
} else if ( ! stack. isEmpty ( ) && calcLevel ( each) <= calcLevel ( stack. peek ( ) ) ) {
while ( ! stack. isEmpty ( ) && calcLevel ( each) <= calcLevel ( stack. peek ( ) ) ) {
if ( calcLevel ( stack. peek ( ) ) == LEVEL_HIGH) {
break ;
}
data. add ( stack. pop ( ) ) ;
}
stack. push ( each) ;
} else if ( RIGHT. equals ( each) ) {
while ( ! stack. isEmpty ( ) && LEVEL_HIGH >= calcLevel ( stack. peek ( ) ) ) {
if ( LEVEL_HIGH == calcLevel ( stack. peek ( ) ) ) {
stack. pop ( ) ;
break ;
}
data. add ( stack. pop ( ) ) ;
}
}
start = i ;
} else if ( i == s. length ( ) - 1 || isSymbol ( s. charAt ( i+ 1 ) + "" ) ) {
each = start == 0 ? s. substring ( start, i+ 1 ) : s. substring ( start+ 1 , i+ 1 ) ;
if ( isNumber ( each) ) {
data. add ( each) ;
continue ;
}
throw new RuntimeException ( "data not match number" ) ;
}
}
Collections . reverse ( stack) ;
data. addAll ( new ArrayList < > ( stack) ) ;
System . out. println ( data) ;
return data;
}
public static Double doCalc ( List < String > list) {
Double d = 0d ;
if ( list == null || list. isEmpty ( ) ) {
return null ;
}
if ( list. size ( ) == 1 ) {
System . out. println ( list) ;
d = Double . valueOf ( list. get ( 0 ) ) ;
return d;
}
ArrayList < String > list1 = new ArrayList < > ( ) ;
for ( int i = 0 ; i < list. size ( ) ; i++ ) {
list1. add ( list. get ( i) ) ;
if ( isSymbol ( list. get ( i) ) ) {
Double d1 = doTheMath ( list. get ( i - 2 ) , list. get ( i - 1 ) , list. get ( i) ) ;
list1. remove ( i) ;
list1. remove ( i- 1 ) ;
list1. set ( i- 2 , d1+ "" ) ;
list1. addAll ( list. subList ( i+ 1 , list. size ( ) ) ) ;
break ;
}
}
doCalc ( list1) ;
return d;
}
public static Double doTheMath ( String s1, String s2, String symbol) {
Double result ;
switch ( symbol) {
case ADD : result = Double . valueOf ( s1) + Double . valueOf ( s2) ; break ;
case MINUS : result = Double . valueOf ( s1) - Double . valueOf ( s2) ; break ;
case TIMES : result = Double . valueOf ( s1) * Double . valueOf ( s2) ; break ;
case DIVISION : result = Double . valueOf ( s1) / Double . valueOf ( s2) ; break ;
default : result = null ;
}
return result;
}
public static void main ( String [ ] args) {
String math = "12.8 + (2 - 3.55)*4+10/5.0" ;
try {
doCalc ( doMatch ( math) ) ;
} catch ( Exception e) {
e. printStackTrace ( ) ;
}
}
}
六、哈希表(散列表)
根据键值对(key-value)直接进行访问的数据结构,通过key隐射value,让我们可以快速的通过key拿到对应value值。这个映射函数叫做散列函数,存放记录的数组叫做散列表 常见实现哈希表的方式:数组+链表、数组+二叉树 一般我们自己实现哈希表,都是为了一些特殊场景,这些场景使用redis等缓存产品有些大材小用 运行效果 代码
public class Test {
public static void main ( String [ ] args) {
EmpHashTable empHashTable = new EmpHashTable ( 3 ) ;
empHashTable. add ( new Emp ( 1 , "张三" ) ) ;
empHashTable. add ( new Emp ( 2 , "李四" ) ) ;
empHashTable. add ( new Emp ( 3 , "王五" ) ) ;
empHashTable. add ( new Emp ( 4 , "六六" ) ) ;
empHashTable. add ( new Emp ( 5 , "七七" ) ) ;
empHashTable. add ( new Emp ( 6 , "巴巴" ) ) ;
empHashTable. add ( new Emp ( 7 , "救救" ) ) ;
empHashTable. add ( new Emp ( 8 , "试试" ) ) ;
empHashTable. print ( ) ;
empHashTable. findById ( 3 ) ;
}
}
class Emp {
private Integer id;
private String name;
private Emp next;
public Emp ( Integer id, String name) {
this . id = id;
this . name = name;
}
public Integer getId ( ) {
return id;
}
public void setId ( Integer id) {
this . id = id;
}
public String getName ( ) {
return name;
}
public void setName ( String name) {
this . name = name;
}
public Emp getNext ( ) {
return next;
}
public void setNext ( Emp next) {
this . next = next;
}
@Override
public String toString ( ) {
return "Emp{" +
"id=" + id +
", name='" + name + '\'' +
'}' ;
}
}
class EmpLinkedList {
private Emp head = null ;
public void add ( Emp emp) {
if ( head == null ) {
head = emp;
} else {
Emp node = head;
while ( node. getNext ( ) != null ) {
node = node. getNext ( ) ;
}
node. setNext ( emp) ;
}
}
public void print ( ) {
if ( head == null ) {
System . out. println ( "链表为空!!!" ) ;
return ;
}
Emp node = head;
while ( node!= null ) {
System . out. print ( node. toString ( ) + "------" ) ;
node = node. getNext ( ) ;
}
}
public Emp findById ( Integer id) {
if ( head == null ) {
System . out. println ( "链表为空" ) ;
return null ;
}
Emp node = head;
while ( node!= null ) {
if ( node. getId ( ) == id) return node;
node = node. getNext ( ) ;
}
return null ;
}
}
class EmpHashTable {
private EmpLinkedList [ ] empLinkedListArray;
private Integer size;
public EmpHashTable ( int size) {
this . size = size;
empLinkedListArray = new EmpLinkedList [ size] ;
for ( int i = 0 ; i< size; i++ ) {
empLinkedListArray[ i] = new EmpLinkedList ( ) ;
}
}
public int hashFun ( int id) {
return id % size;
}
public void add ( Emp emp) {
int i = hashFun ( emp. getId ( ) ) ;
empLinkedListArray[ i] . add ( emp) ;
}
public void print ( ) {
for ( int i = 0 ; i< size; i++ ) {
System . out. print ( "key:" + i+ " value{" ) ;
empLinkedListArray[ i] . print ( ) ;
System . out. println ( "}" ) ;
}
}
public Emp findById ( Integer id) {
int i = hashFun ( id) ;
Emp emp = empLinkedListArray[ i] . findById ( id) ;
if ( emp == null ) {
System . out. println ( "没找到!!!" ) ;
return null ;
}
System . out. println ( "查找id为" + id+ "的节点,找到的节点为" + emp. toString ( ) ) ;
return emp;
}
}
七、树
八、图