数据结构

数据结构是计算机存储、组织数据的方式,它是指相互之间存在一种或多种特定关系的数据元素的集合,也指数据的逻辑结构和数据的物理结构(也叫存储结构)。数据的逻辑结构就是数据表面上的关系。物理大小指数组的容量大小,而逻辑大小则指数组中实际已存储的数据元素的个数。数据的物理结构只有两个:一个是顺序存储,一个是链式存储。精心选择数据结构可以带来更高的运行或存储效率。数据结构往往同高效的检索算法和索引技术相关。常见的数据结构有:数组、队列、堆栈、链表等。

      数组是通过索引(下标)来访问数据元素的,数组中的元素存储在地址连续的内存中。索引是一种随机访问操作。在随机访问中,查找第一个元素和查找最后一个元素所需要的时间是一样的。 如果数组的逻辑大小等于物理大小,则代表数组已满;如果数组的逻辑大小为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&&current.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);

    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值