Java实现节点链表

链结点  

   在链表中,每个数据项都被包含在‘点“中,一个点是某个类的对象,这个类可认叫做 

   LINK。因为一个链表中有许多类似的链结点,所以有必要用一个不同于链表的类来表达 

   链结点。每个 LINK 对象中都包含一个对下一个点引用的字段(通常叫做 next)但是

   本身的对象中有一个字段指向对第一个链结点的引用  

 

 

 

单链表是一种顺序存取的结构,为找第 i个数据元素,必须先找到第 i-1个数 

据元素。因此,查找第i个数据元素的基本操作为:移动指针,比较                      和  

 

    1、链接存储方法 

 

    链接方式存储的线性表简称为链表(LinkedList )。 

 

    链表的具体存储表示为: 

 

    ① 用一组任意的存储单元来存放线性表的结点(这组存储单元既可以是连续的, 

 

也可以是不连续的) 

 ② 链表中结点的逻辑次序和物理次序不一定相同。为了能正确表示结点间的逻 

 

辑关系,在存储每个结点值的同时,还必须存储指示其后继结点的地址(或位置)信 

 

息(称为指针(pointer )或链(link) ) 

 

    注意: 

 

    链式存储是最常用的存储方式之一,它不仅可用来表示线性表,而且可用来表示 

 

各种非线性的数据结构。 

 

    、链表的结点结构 

 

     ┌──┬──┐ 

 

     data next │ 

 

     └──┴──┘ 

 

    data --存放结点值的数据域 

 

    next --存放结点的直接后继的地址(位置)的指针域(链域) 

 

    注意: 

 

    ①链表通过每个结点的链域将线性表的 个结点按其逻辑顺序链接在一起的。 

 

    ②每个结点只有一个链域的链表称为单链表(Single                         Linked  List )。 

 

 

    、头指针 head 和终端结点指针域的表示 

 

    单链表中每个结点的存储地址是存放在其前趋结点 next 域中,而开始结点无前 

 

趋,故应设头指针 head 指向开始结点。 

 

    注意: 

 

    链表由头指针唯一确定,单链表可以用头指针的名字来命名。 

 

    【例】头指针名是 head 的链表可称为表 head 。 

 

    终端结点无后继,故终端结点的指针域为空,即 NULL 

 

 

 

[java]  view plain  copy
 print ?
  1. public class LinkList  
  2.   
  3.     public class Node{  //定义节点  
  4.         private data;  
  5.         private Node next;  
  6.         public Node(){  
  7.               
  8.          
  9.         public Node(T data,Node next){  
  10.             this.data=data;  
  11.             this.next=next;  
  12.          
  13.      
  14.       
  15.     private Node header;//头节点  
  16.     private Node tail;//尾节点  
  17.     private int size;//链表大小  
  18.       
  19.      
  20.     //构造函数初始化数据  
  21.     public LinkList(){  
  22.         header=null 
  23.         tail=null 
  24.      
  25.     public LinkList(T element){  
  26.         header=new Node(element,null);  
  27.         tail=header;  
  28.         size++;  
  29.      
  30.       
  31.     //链表长度  
  32.     public int length(){  
  33.         return size;  
  34.      
  35.       
  36.     //返回指定位置index的节点  
  37.     public get(int index){  
  38.         return getNodeByIndex(index).data;  
  39.      
  40.       
  41.     private Node getNodeByIndex(int index)  
  42.         if(index<</span>0||index>size-1){  
  43.             throw new IndexOutOfBoundsException("线性表索引越界");  
  44.          
  45.         Node current=header;  
  46.         for(int i=0;inull;i++,current=current.next){  
  47.             if(i==index){  
  48.                 return current;  
  49.              
  50.          
  51.         return null 
  52.      
  53.       
  54.     //返回element在链表的位置,-1表示不存在  
  55.     public int locate(T element){  
  56.         Node current=header;  
  57.         for(int i=0;inull;i++,current=current.next){  
  58.             if(current.data==element){  
  59.                 return i;  
  60.              
  61.          
  62.         return -1 
  63.      
  64.       
  65.       
  66.     //在index位置插入节点element  
  67.     public void insert(T element,int index){  
  68.         if(index<</span>0||index>size){  
  69.             throw new IndexOutOfBoundsException("线性表索引越界");  
  70.          
  71.         if(header==null){  
  72.             add(element);  
  73.         }else 
  74.             if(index==0){  
  75.                 addAtHeader(element);  
  76.             }else 
  77.                 Node prev=getNodeByIndex(index-1);  
  78.                 prev.next=new Node(element,prev.next);  
  79.                 size++;  
  80.              
  81.          
  82.      
  83.       
  84.     //采用尾插法为链表添加新节点  
  85.     private void add(T element)  
  86.         // TODO Auto-generated method stub  
  87.         if(header==null){  
  88.             header=new Node(element,null);  
  89.             tail=header;  
  90.         }else 
  91.             Node newNode=new Node(element,null);  
  92.             tail.next=newNode;  
  93.             tail=newNode;  
  94.          
  95.         size++;  
  96.      
  97.       
  98.     //采用头插法为链表添加新节点  
  99.     private void addAtHeader(T element){  
  100.         header=new Node(element,header);  
  101.         if(tail==null){  
  102.             tail=header;  
  103.          
  104.         size++;  
  105.      
  106.       
  107.     //删除index位置的节点  
  108.     public delete(int index){  
  109.         if(index<</span>0||index>size-1){  
  110.             throw new IndexOutOfBoundsException("线性表索引越界");  
  111.          
  112.         Node del=null 
  113.         if(index==0){  
  114.             del=header;  
  115.             header=header.next;  
  116.         }else 
  117.             Node prev=getNodeByIndex(index-1);  
  118.             del=prev.next;  
  119.             prev.next=del.next;  
  120.             del.next=null 
  121.          
  122.         size--;  
  123.         return del.data;  
  124.      
  125.       
  126.     //从链表后面删除一个节点  
  127.     public remove(){  
  128.         return delete(size-1);  
  129.      
  130.       
  131.     //是否为空  
  132.     public boolean empty(){  
  133.         return size==0 
  134.      
  135.     //清空链表  
  136.     public void clear(){  
  137.         header=null 
  138.         tail=null 
  139.         size=0 
  140.      
  141.       
  142.     public String toString(){  
  143.         if(empty()){  
  144.             return "[]" 
  145.         }else 
  146.             StringBuilder sb=new StringBuilder("[");  
  147.             for(Node current=header;current!=null;current=current.next){  
  148.                 sb.append(current.data.toString()+", ");  
  149.              
  150.             int len=sb.length();  
  151.             return sb.delete(len-2len).append("]").toString();  
  152.          
  153.      
  154.     public static void main(String[] args)  
  155.         LinkList list=new LinkList();  
  156.         list.insert("aaa"0);  
  157.         list.add("bbb");  
  158.         list.add("ccc");  
  159.         System.out.println(list.toString());  
  160.         list.insert("ddd"1);  
  161.         System.out.println(list.toString());  
  162.         list.delete(2);  
  163.         System.out.println(list.toString());  
  164.         System.out.println("ccc在链表中的位置:"+list.locate("ccc"));  
  165.         System.out.println("链表中索引2处的元素:"+list.get(2));  
  166.      
  167.   
  168. }
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
/* * 基于链表节点实现二叉树节点 */ package dsa; public class BinTreeNode implements BinTreePosition { protected Object element;//该节点中存放的对象 protected BinTreePosition parent;//父亲 protected BinTreePosition lChild;//左孩子 protected BinTreePosition rChild;//右孩子 protected int size;//后代数目 protected int height;//高度 protected int depth;//深度 /**************************** 构造方法 ****************************/ public BinTreeNode() { this(null, null, true, null, null); } public BinTreeNode( Object e,//节点内容 BinTreePosition p,//父节点 boolean asLChild,//是否作为父节点的左孩子 BinTreePosition l,//左孩子 BinTreePosition r)//右孩子 { size = 1; height = depth = 0; parent = lChild = rChild = null;//初始化 element = e;//存放的对象 //建立与父亲的关系 if (null != p) if (asLChild) p.attachL(this); else p.attachR(this); //建立与孩子的关系 if (null != l) attachL(l); if (null != r) attachR(r); } /**************************** Position接口方法 ********************************/ //返回当前节点中存放的对象 public Object getElem() { return element; } //将对象obj存入当前节点,并返回此前的内容 public Object setElem(Object obj) { Object bak = element; element = obj; return bak; } /**************************** BinTreePosition接口方法 *************************/ //判断是否有父亲(为使代码描述简洁) public boolean hasParent() { return null != parent; } //返回当前节点的父节点 public BinTreePosition getParent() { return parent; } //设置当前节点的父节点 public void setParent(BinTreePosition p) { parent = p; } //判断是否为叶子 public boolean isLeaf() { return !hasLChild() && !hasRChild(); } //判断是否为左孩子(为使代码描述简洁) //若当前节点有父亲,而且是左孩子,则返回true;否则,返回false public boolean isLChild() { return (hasParent() && this == getParent().getLChild()) ? true : false; } //判断是否有左孩子(为使代码描述简洁) public boolean hasLChild() { return null != lChild; } //返回当前节点的左孩子 public BinTreePosition getLChild() { return lChild; } //设置当前节点的左孩子(注意:this.lChild和c.parent都不一定为空) public void setLChild(BinTreePosition c) { lChild = c; } //判断是否为右孩子(为使代码描述简洁) //若当前节点有父亲,而且是右孩子,则返回true;否则,返回false public boolean isRChild() { return (hasParent() && this == getParent().getRChild()) ? true : false; } //判断是否有右孩子(为使代码描述简洁) public boolean hasRChild() { return null != rChild; } //返回当前节点的右孩子 public BinTreePosition getRChild() { return rChild; } //设置当前节点的右孩子(注意:this.rChild和c.parent都不一定为空) public void setRChild(BinTreePosition c) { rChild = c; } //返回当前节点后代元素的数目 public int getSize() { return size; } //在孩子发生变化后,更新当前节点及其祖先的规模 public void updateSize() { size = 1;//当前节点 if (hasLChild()) size += getLChild().getSize();//左子树的规模 if (hasRChild()) size += getRChild().getSize();//右子树的规模 if (hasParent()) getParent().updateSize();//递归更新各个真祖先的规模记录 } //返回当前节点的高度 public int getHeight() { return height; } //在孩子发生变化后,更新当前节点及其祖先的高度 public void updateHeight() { height = 0;//先假设没有左、右孩子 if (hasLChild()) height = Math.max(height, 1+getLChild().getHeight());//左孩子 if (hasRChild()) height = Math.max(height, 1+getRChild().getHeight());//右孩子 if (hasParent()) getParent().updateHeight();//递归更新各个真祖先的高度记录 } //返回当前节点的深度 public int getDepth() { return depth; } //在父亲发生变化后,更新当前节点及其后代的深度 public void updateDepth() { depth = hasParent() ? 1+getParent().getDepth() : 0;//当前节点 if (hasLChild()) getLChild().updateDepth();//沿孩子引用逐层向下, if (hasRChild()) getRChild().updateDepth();//递归地更新所有后代的深度记录 } //按照中序遍历的次序,找到当前节点的直接前驱 public BinTreePosition getPrev() { //若左子树非空,则其中的最大者即为当前节点的直接前驱 if (hasLChild()) return findMaxDescendant(getLChild()); //至此,当前节点没有左孩子 if (isRChild()) return getParent();//若当前节点是右孩子,则父亲即为其直接前驱 //至此,当前节点没有左孩子,而且是左孩子 BinTreePosition v = this;//从当前节点出发 while (v.isLChild()) v = v.getParent();//沿左孩子链一直上升 //至此,v或者没有父亲,或者是父亲的右孩子 return v.getParent(); } //按照中序遍历的次序,找到当前节点的直接后继 public BinTreePosition getSucc() { //若右子树非空,则其中的最小者即为当前节点的直接后继 if (hasRChild()) return findMinDescendant(getRChild()); //至此,当前节点没有右孩子 if (isLChild()) return getParent();//若当前节点是左孩子,则父亲即为其直接后继 //至此,当前节点没有右孩子,而且是右孩子 BinTreePosition v = this;//从当前节点出发 while (v.isRChild()) v = v.getParent();//沿右孩子链一直上升 //至此,v或者没有父亲,或者是父亲的左孩子 return v.getParent(); } //断绝当前节点与其父亲的父子关系 //返回当前节点 public BinTreePosition secede() { if (null != parent) { if (isLChild()) parent.setLChild(null);//切断父亲指向当前节点的引用 else parent.setRChild(null); parent.updateSize();//更新当前节点及其祖先的规模 parent.updateHeight();//更新当前节点及其祖先的高度 parent = null;//切断当前节点指向原父亲的引用 updateDepth();//更新节点及其后代节点的深度 } return this;//返回当前节点 } //将节点c作为当前节点的左孩子 public BinTreePosition attachL(BinTreePosition c) { if (hasLChild()) getLChild().secede();//摘除当前节点原先的左孩子 if (null != c) { c.secede();//c脱离原父亲 lChild = c; c.setParent(this);//确立新的父子关系 updateSize();//更新当前节点及其祖先的规模 updateHeight();//更新当前节点及其祖先的高度 c.updateDepth();//更新c及其后代节点的深度 } return this; } //将节点c作为当前节点的右孩子 public BinTreePosition attachR(BinTreePosition c) { if (hasRChild()) getRChild().secede();//摘除当前节点原先的右孩子 if (null != c) { c.secede();//c脱离原父亲 rChild = c; c.setParent(this);//确立新的父子关系 updateSize();//更新当前节点及其祖先的规模 updateHeight();//更新当前节点及其祖先的高度 c.updateDepth();//更新c及其后代节点的深度 } return this; } //前序遍历 public Iterator elementsPreorder() { List list = new List_DLNode(); preorder(list, this); return list.elements(); } //中序遍历 public Iterator elementsInorder() { List list = new List_DLNode(); inorder(list, this); return list.elements(); } //后序遍历 public Iterator elementsPostorder() { List list = new List_DLNode(); postorder(list, this); return list.elements(); } //层次遍历 public Iterator elementsLevelorder() { List list = new List_DLNode(); levelorder(list, this); return list.elements(); } /**************************** 辅助方法 ****************************/ //在v的后代中,找出最小者 protected static BinTreePosition findMinDescendant(BinTreePosition v) { if (null != v) while (v.hasLChild()) v = v.getLChild();//从v出发,沿左孩子链一直下降 //至此,v或者为空,或者没有左孩子 return v; } //在v的后代中,找出最大者 protected static BinTreePosition findMaxDescendant(BinTreePosition v) { if (null != v) while (v.hasRChild()) v = v.getRChild();//从v出发,沿右孩子链一直下降 //至此,v或者为空,或者没有右孩子 return v; } //前序遍历以v为根节的(子)树 protected static void preorder(List list, BinTreePosition v) { if (null == v) return;//递归基:空树 list.insertLast(v);//访问v preorder(list, v.getLChild());//遍历左子树 preorder(list, v.getRChild());//遍历右子树 } //中序遍历以v为根节的(子)树 protected static void inorder(List list, BinTreePosition v) { if (null == v) return;//递归基:空树 inorder(list, v.getLChild());//遍历左子树 list.insertLast(v);//访问v inorder(list, v.getRChild());//遍历右子树 } //后序遍历以v为根节的(子)树 protected static void postorder(List list, BinTreePosition v) { if (null == v) return;//递归基:空树 postorder(list, v.getLChild());//遍历左子树 postorder(list, v.getRChild());//遍历右子树 list.insertLast(v);//访问v } //层次遍历以v为根节的(子)树 protected static void levelorder(List list, BinTreePosition v) { Queue_List Q = new Queue_List();//空队 Q.enqueue(v);//根节点入队 while (!Q.isEmpty()) { BinTreePosition u = (BinTreePosition) Q.dequeue();//出队 list.insertLast(u);//访问v if (u.hasLChild()) Q.enqueue(u.getLChild()); if (u.hasRChild()) Q.enqueue(u.getRChild()); } } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值