• 泛型,链表


    泛型的定义:泛型是JDK 1.5的一项新特性,它的本质是参数化类型(Parameterized Type)的应用,也就是说所操作的数据类型被指定为一个参数,在用到的时候在指定具体的类型。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口和泛型方法。

      泛型技术在C#和Java之中的使用方式看似相同,但实现上却有着根本性的分歧,C#里面泛型无论在程序源码中、编译后的IL中(Intermediate Language,中间语言,这时候泛型是一个占位符)或是运行期的CLR中都是切实存在的,List<int>与List<String>就是两个不同的类型,它们在系统运行期生成,有自己的虚方法表和类型数据,这种实现称为类型膨胀,基于这种方法实现的泛型被称为真实泛型。

      Java语言中的泛型则不一样,它只在程序源码中存在,在编译后的字节码文件中,就已经被替换为原来的原始类型(Raw Type,也称为裸类型)了,并且在相应的地方插入了强制转型代码,因此对于运行期的Java语言来说,ArrayList<int>与ArrayList<String>就是同一个类。所以说泛型技术实际上是Java语言的一颗语法糖,Java语言中的泛型实现方法称为类型擦除,基于这种方法实现的泛型被称为伪泛型。(类型擦除在后面在学习)

      使用泛型机制编写的程序代码要比那些杂乱的使用Object变量,然后再进行强制类型转换的代码具有更好的安全性和可读性。泛型对于集合类来说尤其有用。

      泛型程序设计(Generic Programming)意味着编写的代码可以被很多不同类型的对象所重用。

    链表

    链表是一种重要的数据结构,在程序设计中占有很重要的地位。C语言和C++语言中是用指针来实现链表结构的,由于Java语言不提供指针,所以有人认为在Java语言中不能实现链表,其实不然,Java语言比C和C++更容易实现链表结构。Java语言中的对象引用实际上是一个指针(本文中的指针均为概念上的意义,而非语言提供的数据类型),所以我们可以编写这样的类来实现链表中的结点。

      class Node
      {
      Object data;
      Node next;//指向下一个结点
      }

      将数据域定义成Object类是因为Object类是广义超类,任何类对象都可以给其赋值,增加了代码的通用性。为了使链表可以被访问还需要定义一个表头,表头必须包含指向第一个结点的指针和指向当前结点的指针。为了便于在链表尾部增加结点,还可以增加一指向链表尾部的指针,另外还可以用一个域来表示链表的大小,当调用者想得到链表的大小时,不必遍历整个链表。下图是这种链表的示意图:

      链表的数据结构

      我们可以用类List来实现链表结构,用变量Head、Tail、Length、Pointer来实现表头。存储当前结点的指针时有一定的技巧,Pointer并非存储指向当前结点的指针,而是存储指向它的前趋结点的指针,当其值为null时表示当前结点是第一个结点。那么为什么要这样做呢?这是因为当删除当前结点后仍需保证剩下的结点构成链表,如果Pointer指向当前结点,则会给操作带来很大困难。那么如何得到当前结点呢,我们定义了一个方法cursor(),返回值是指向当前结点的指针。类List还定义了一些方法来实现对链表的基本操作,通过运用这些基本操作我们可以对链表进行各种操作。例如reset()方法使第一个结点成为当前结点。insert(Object d)方法在当前结点前插入一个结点,并使其成为当前结点。remove()方法删除当前结点同时返回其内容,并使其后继结点成为当前结点,如果删除的是最后一个结点,则第一个结点变为当前结点。

      链表类List的源代码如下:

      import java.io.*;
      public class List
      {
      /*用变量来实现表头*/
      private Node Head=null;
      private Node Tail=null;
      private Node Pointer=null;
      private int Length=0;
      public void deleteAll()
      /*清空整个链表*/
      {
      Head=null;
      Tail=null;
      Pointer=null;
      Length=0;
      }
      public void reset()
      /*链表复位,使第一个结点成为当前结点*/
      {
      Pointer=null;
      }
      public boolean isEmpty()
      /*判断链表是否为空*/
      {
      return(Length==0);
      }
      public boolean isEnd()
      /*判断当前结点是否为最后一个结点*/
      {
      if(Length==0)
       throw new java.lang.NullPointerException();
      else if(Length==1)
       return true;
      else
       return(cursor()==Tail);
      }
      public Object nextNode()
      /*返回当前结点的下一个结点的值,并使其成为当前结点*/
      {
      if(Length==1)
       throw new java.util.NoSuchElementException();
      else if(Length==0)
       throw new java.lang.NullPointerException();
      else
      {
       Node temp=cursor();
       Pointer=temp;
       if(temp!=Tail)
        return(temp.next.data);
       else
        throw new java.util.NoSuchElementException();
      }
      }
      public Object currentNode()
      /*返回当前结点的值*/
      {
      Node temp=cursor();
      return temp.data;
      }
      
      public void insert(Object d)
      /*在当前结点前插入一个结点,并使其成为当前结点*/
      {
      Node e=new Node(d);
      if(Length==0)
      {
       Tail=e;
       Head=e;
      }
      else
      {
       Node temp=cursor();
       e.next=temp;
       if(Pointer==null)
        Head=e;
       else
        Pointer.next=e;
      }
      Length++;
      }
      public int size()
      /*返回链表的大小*/
      {
      return (Length);
      }
      public Object remove()
      /*将当前结点移出链表,下一个结点成为当前结点,如果移出的结点是最后一个结点,则第一个结点成为当前结点*/
      {
      Object temp;
      if(Length==0)
       throw new java.util.NoSuchElementException();
      else if(Length==1)
      {
       temp=Head.data;
       deleteAll();
      }
      else
      {
       Node cur=cursor();
       temp=cur.data;
       if(cur==Head)
        Head=cur.next;
       else if(cur==Tail)
       {
        Pointer.next=null;
        Tail=Pointer;
        reset();
       }
       else
        Pointer.next=cur.next;
        Length--;
      }
      return temp;
      }
      private Node cursor()
      /*返回当前结点的指针*/
      {
      if(Head==null)
       throw new java.lang.NullPointerException();
      else if(Pointer==null)
       return Head;
      else
       return Pointer.next;
      }
      public static void main(String[] args)
      /*链表的简单应用举例*/
      {
      List a=new List ();
      for(int i=1;i<=10;i++)
       a.insert(new Integer(i));
       System.out.println(a.currentNode());
       while(!a.isEnd())
        System.out.println(a.nextNode());
        a.reset();
        while(!a.isEnd())
        {
         a.remove();
        }
        a.remove();
        a.reset();
        if(a.isEmpty())
         System.out.println("There is no Node in List ");
         System.in.println("You can press return to quit ");
        try
        {
         System.in.read();
         //确保用户看清程序运行结果
        }
        catch(IOException e)
        {}
       }
      }
      class Node
      /*构成链表的结点定义*/
      {
       Object data;
       Node next;
       Node(Object d)
       {
        data=d;
        next=null;
       }
      }

      读者还可以根据实际需要定义新的方法来对链表进行操作。双向链表可以用类似的方法实现只是结点的类增加了一个指向前趋结点的指针。

      可以用这样的代码来实现:

      class Node
      {
      Object data;
      Node next;
      Node previous;
      Node(Object d)
      {
      data=d;
      next=null;
      previous=null;
      }
      }

      当然,双向链表基本操作的实现略有不同。链表和双向链表的实现方法,也可以用在堆栈和队列的实现中,这里就不再多写了,有兴趣的读者可以将List类的代码稍加改动即可

  • 相关阅读:
    洛谷 P1077 摆花
    洛谷 P2323 [HNOI2006]公路修建问题
    2017.10.17 模拟赛
    【渗透测试小白系列】之BurpSuite爆破High级别的DVWA(含CSRF-Token防爆破程序)
    【漏洞复现】之sudo提权漏洞(CVE-2019-14287)复现
    【漏洞复现】Maccms潜藏后门分析复现
    杂乱的计算机网络基础
    简述数据库管理
    【漏洞复现】之微信DLL劫持反弹shell复现
    【渗透测试小白系列】之简单使用Ettercap实现DNS劫持
  • 原文地址:https://www.cnblogs.com/storm47/p/5261967.html
Copyright © 2020-2023  润新知