数据结构是计算机存储、组织数据的方式,它是指相互之间存在一种或多种特定关系的数据元素的集合,也指数据的逻辑结构和数据的物理结构(也叫存储结构)。数据的逻辑结构就是数据表面上的关系。物理大小指数组的容量大小,而逻辑大小则指数组中实际已存储的数据元素的个数。数据的物理结构只有两个:一个是顺序存储,一个是链式存储。精心选择数据结构可以带来更高的运行或存储效率。数据结构往往同高效的检索算法和索引技术相关。常见的数据结构有:数组、队列、堆栈、链表等。
数组是通过索引(下标)来访问数据元素的,数组中的元素存储在地址连续的内存中。索引是一种随机访问操作。在随机访问中,查找第一个元素和查找最后一个元素所需要的时间是一样的。 如果数组的逻辑大小等于物理大小,则代表数组已满;如果数组的逻辑大小为0,则代表数组为空;在数组已满的情况下,数组的最后一个元素的索引值为逻辑大小减1,访问第一个数组元素的索引下标为0。
例如:
int []array=new int[3];
array[0]=2;
array[1]=5;
array[2]=3;
for(int i=0;i<array.length;i++)
{
System.out.println(array[i];
}
链表由多个节点(对象)组成,每个节点在内存中是散乱存放的,即存放在一个叫做“对象堆”的不连续地址内存中。其中每个节点(除了尾节点外)都有一个特定的引用下一个节点的变量,从而实现一个完整链表。查找链表中的数据则必须欧诺个链表的一端开始,沿着链一直移动,直到找到查询的数据为止。由于链表的不连续地址内存机制,则往链表中插入和删除数据时,不会像数组那样移动其他数据项,而是在空闲内存中为新的节点对象分配空间,然后将该节点和链表中特定位置的节点连接起来。链表分为单向链表、双向链表、循环链表。
要实现双向链表,首先需要定义一个节点的类,具有next(Node类型,引用下一个节点)、previous(Node类型,引用上一个节点)和data(节点中存放的数据)属性。代码如下:
public class Node{
public Node next;//引用下一个节点
public Node previous;//引用上一个节点
private int data;//节点中存放的数据
public int getData()
{
return data;
}
public void setData (int data)
{
this.data=data;
}
public Node(int data){
this.data=data;
}
public String toString(){ //覆盖该方法,用来打印该节点
return data+"";
}
public boolean equals(Object other){
//进行两个节点的比较
Node temp=null;
if(other instanceof Node){
//判断是否是Node类型
temp=(Node)other;
//进行数据的比较
if(temp.getData()==this.getData()){
return ture;
}else{
return false;
}
}else{
return false;
}
}
}
双向链表类DoubleLink需要提供addEnd(在链表尾部添加节点)、addFirst(在链表头部添加节点)、delete(输出节点A,该节点的上一个节点B的next指向该节点的下一个节点C,节点c的previous属性指向B),该类的参考代码如下:
public class DoubleLink{
priate Node first;
private Node end;
public void addFirst(int data){
Node node=new Node(data);
if(first !=null){
node.next=first;
first.previous=node;
first=node;
}else{
first=node;
end=node;
}
}
public void addEnd(int data){
Node node=new Node(data);
if(end !=null){
end.next=node;
node.previous=end;
end=node;
}else{
first=node;
end=node;
}
}
public Node find(int data){
Node temp=new Node(data);//从该数据创建一个节点进行比较
Node f=first;//从头节点开始找
while(f !=null){
if(f.equals(temp))
break;
else
f=f.next;
}
return f;
}
public void delete(int data){
Node node=find(data);//首先查找容器中有无该数据
if(node !=null){ //如果找到要删的数据,则进行指针移位,从而删除
node.previous,next=node.next;
node.next.previous=node.previous;
}
}
public void update(int ydata,int mdata){
Node node=find(ydata);//查找数据
node.setData(mdata);//修改数据
}
public String toString(){
//不要直接使用String类,存在效率问题
StringBuffer sb=new StringBuffer();
Node temp=first;
while(temp !=null){
if(temp==end)
sb.append("["+temp.getData()+"]");
else
sb.append("["+temp.getData()+"]");
temp=temp.next;
}
return sb.toString();
}
public static void main(String []args){
DoubleLink dl=new DoubleLink();
dl.addFirst(30);
dl.addFirst(40);
dl.addFirst(50);
dl.addFirst(60);
dl.addEnd(70);
dl.addEnd(80);
dl.addEnd(90);
dl.delete(50);
System.out.println(dl);
}
}
运行结果:[60],[40],[30],[70],[80],[90]
栈是一个仅在一端访问的线性集合,它遵循后进先出的协议(LIFO)。栈的两个基本操作为:
(1)push:入栈
(2)pop:出栈
栈的应用:
(1)中缀表达式到后缀表达式的转换,以及对后缀表达式的求值
(2)回溯算法
(3)方法调用
(4)文本编辑器中的撤销功能
(5)Web浏览器的链接历史信息的保留
队列是线性集合,它只允许在表的一端进行插入,即队尾(rear),删除则在另一端,即队头(front),支持先进先出(FIFO)。队列应用最常见的有:CPU访问、磁盘访问和打印机访问等。
树是由一个或多个节点组成的有限集合。每棵树都必须有一个特定的节点,叫做“根节点”。根节点下可以有零个或多个子节点。
二叉树和树的区别:
(1)二叉树可以为空,而树不可以
(2)二叉树的子树有顺序关系
(3)二叉树的分支度必须为0、1或2,而树的分支度可以大于2。
使用Java实现二叉树的简单功能,首先需要提供树的节点类,例如TreeNode,该类有left(TreeNode类型,表示左二子),right(TreeNode类型,表示右儿子)、data(数据)属性,代码如下:
public class TreeNode{
int data;
TreeNode left;
TreeNode right;
public TreeNode(int data){
this.data=data;
}
public String toString(){
return data+"";
}
}
树型结构是用来存取数据效率比较好的一种数据结构,增、删、改效率都比前面介绍的数据结构要高,缺点就是实现起来比较负责。实现二叉树的增、删、改、查询等方法的参考如下:
public class Tree{
TreeNode root;
TreeNode parent;
boolean b;
public boolean add(int d){
//增加数据的方法
TreeNode jd=new TreeNode(d);
if(root==null){
//如果根节点为空,那么把新节点加给根节点
root=jd;
}else{
TreeNode current=root;
while(current !=null){
//试找到一个位置加新节点
if(d==current.data){
//如果已经存在,则直接返回false表示加失败
return false;
}else if(d>current){
//如果该值大于当前节点,那么应该往右边找
parent=current;//记录要加新节点的父节点
b=true;//记录是左边还是右边
current=current.right;
}else if(d<current.data){
parent =current;
b=false;
current=current.left;
}
}
if(b){
//如果是右儿子为空,就加父节点的右边
parent.right=jd;
}else{
parent.left=jd;
}
}
return true;
}
public TreeNode find(int d){
//查询的方法
TreeNode current =root;
while(current !=null){
if(current.data==d)
return current;
else{
//记录找到节点的父节点,以方便删除操作
parent=current;
if(d>current.data){
current=current.right;
b=true;
}else if(d<current){
current=current.left;
b=false;
}
}
}
return current;
}
public boolean delete(int d){
TreeNode current=find(d);
if(current==null){
return false;
}else if(current.left==null&¤t.right==null){
//如果要删除的节点是叶节点
if(current==root){
//如果是根节点(也是叶节点),直接让根节点==null
root==null;
}else if(b){
parent.right=null;
}else{
parent.left=null;
}
}else if(current.left==null){
//如果删除节点只有右节点
if(b){
parent.right=current.right;
}else{
parent.left=current.right;
}
}else if(current.right==null){
//如果删除节点只有左节点
if(b){
//该变量记录了要删除的节点,在其父节点的左边还是右边
parent.right=current.left;
}else{
parent.left=current.left;
}
}else{
TreeNode temp=fenlie(current);
//分裂节点
if(b)
parent.right=temp;
else
parent.left=temp;
}
return true;
}
public TreeNode fenlie(TreeNode c){
TreeNode temp=c.right;
TreeNode p=temp;//用来记录要删除及诶单右儿子那边的最小节点
TreeNode pp=termp;//用来记录要删除节点右儿子那边的最小及诶单的父节点
while(temp !=null){
//找到要删除及诶单右儿子那边的最小节点
pp=p;
p=temp;
temp=temp.left;
}
if(pp==p){
//如果删除节点的右儿子节点没有左儿子
//把删除节点的左二子加到删除节点的右儿子的左边
pp.left=c.left;
return pp;
}else{
pp.left=p.right;//把找到的节点的右儿子部分加到该节点父节点的左边
p.left=c.left;//把删除节点的左二子加到分裂节点的左边
p.right=c.right;//把删除节点的右儿子加到分裂节点的右边
return p;
}
}
public boolean modify(int s,int m){
//修改数据的方法=先删除后增加,这样还是有顺序的
delete(s);
return add(m);
}
public void print(TreeNode jd){
//递归中序遍历该有序二叉树
if(jd !=null){
print(jd.left);
System.out.print(jd+" ");
print(jd.right);
}
}
public void p(){
print (root);
}
}
编写测试代码:
public static void main(String args[]){
Tree t=new Tree();
t.add(5);
t.add(7);
t.add(3);
t.add(9);
t.add(1);
t.p();
System.out.println();
t.modify(3,18);
t.delete(9);
t.p();
}
运行结果:
1 3 5 7 9
1 5 7 18
面试题:
1、栈通常采用的两种存储结构是顺序存储结构和链式存储结构。
2、线性表若采用链式存储结构时,要求内存中的可用存储单元的地址连续和不连续都可以。
3、具有3个节点的二叉树有5种形态。
设一颗二叉树中有3个叶子节点,有8个度为1的节点,则该二叉树中总的节点数为13个
解:因为n0=n2+1
总结点数=叶子节点(3)+度为1的节点(8)+度为2节点(2)=13
4、求a+aa+aaa+...+aa...a相加的值,其中a是一个数字。
答案:考题需要用到一种数据结构,即一维数组。代码如下:
public class SumNumbers{
public sumNumbers(int num,int count){
int []r=getNumbers(num,count);
System.out.println(getString(r)+"="+calResult(r));
}
public int[] getNumbers(int num,int count){
int[] numbers=new int[count];
int temp=0;
for(int i=0;i<count;i++){
for(int j=0;j<count;j++){
int a=10;
temp+=num*Math.pow(a,j);
}
numbers[i]=temp;
temp=0;
}
return numbers;
}
public int calResult(int[] numbers){
int result=0;
for(int i=0;i<numbers.length;i++){
result+=numbers[i];
}
return result;
}
public String getString(int[] numbers){
String temp="";
String result;
int len=numbers.length;
for(int i=len-1;i>=0;i--){
temp+=numbers[i]+"+";
}
result=temp.subString(0,temp.length()-1);
return result;
}
public static void main(String args[]){
new SumNumbers(3,4);
}
}