Loading...

数据结构与算法(三+)——列表的Java实现

数据结构与算法(三+)——列表的Java实现
  iwehdio的博客园:https://www.cnblogs.com/iwehdio/
Github:https://github.com/iwehdio/DSA_THU_DJH_asJava

1、项目结构

理论部分见:https://www.cnblogs.com/iwehdio/p/12290282.html

  • 相比上一节的向量的实现,为了整个数据结构更加体系化,将所有实现集合在一个项目下,优化了体系结构。

  • 核心类体系结构与功能:

  • 此外,还有选择查询Sorter_Selectsort类和插入排序Sorter_Insertsort类,都实现了排序器接口。

2、单向链表

  • Position 接口:

    • C++ 中的 Position 指的是指向列表节点的指针,但在 Java 中没有指针。

    • Position 接口给出了获取和设置元素的方法,实际上是对应了指针分别作为右值和左值的功能。

      public interface Position<T> {
         public T getElem();
         public T setElem(T e);
      }
      
  • Node 类:

    • 实现了单向链表的节点,即只有指向后一个元素的数据。

      public class Node<T> implements Position<T> {
      
          private T element;      //存储的数据内容
          private Node<T> next;   //指向下一个节点
      
          public Node(){
              this(null, null);
          }
          public Node(T e, Node<T> n){
              this.element = e;
              this.next = n;
          }
      
          @Override
          public T getElem() {
              return this.element;
          }
      
          @Override
          public T setElem(T e) {
              T ori_element = this.element;
              this.element = e;
              return ori_element;
          }
      
          //单链表节点方法
          public void setNext(Node<T> newNext) {
              this.next = newNext;
          }
      
          public Node<T> getNext() {
              return next;
          }
      }
      
  • List 接口:

    public interface List<T> {
        //规模
        public int getSize();
        //判空
        public boolean isEmpty();
        //首元素
        public Position<T> first();
        //末元素
        public Position<T> last();
        //获取给定元素的前驱
        public Position<T> getPrev(Position<T> p)
                throws ExceptionPositionInvalid, ExceptionBoundaryViolation;
        //获取给定元素的后继
        public Position<T> getNext(Position<T> p)
                throws ExceptionPositionInvalid, ExceptionBoundaryViolation;
        //作为首元素插入
        public Position<T> insertFirst(T e);
        //作为末元素插入
        public Position<T> insertLast(T e);
        //在给定元素前插入
        public Position<T> insertBefore(Position<T> p, T e)
                throws  ExceptionPositionInvalid;
        //在给定元素后插入
        public Position<T> insertAfter(Position<T> p, T e)
                throws ExceptionPositionInvalid;
        //删除给定元素
        public T remove(Position<T> p)
                throws ExceptionPositionInvalid;
        //删除首元素
        public T removeFirst();
        //删除末元素
        public T removeLast();
        //替换给定元素
        public T replace(Position<T> p, T e)
                throws ExceptionPositionInvalid;
        //位置迭代器
        public Iterator positions();
        //元素迭代器
        public Iterator elements();
        //显示
        public void show();
    }
    
  • List_SLNode 类:

    • 单链表的实现类。

    • 因为对于外部调用,应禁止对首尾哨兵进行操作或将首尾哨兵作为参数,创建辅助方法用于检测传入参数是否合法。

    • 但是辅助方法同时导致,单链表的getPrev()getNext()方法不能返回头尾哨兵。

    • 所以不能直接调用insertBefore()insertAfter()方法而要单独实现可以返回哨兵的内部方法(getPrevIn()getNextIn())。

    • 使用枚举,对不同的方法进行不同的合法性检测。

      enum checkFlag {
          PREV, NEXT, BOTH
      }
      
      public class List_SLNode<T> implements List<T> {
      
          private int size;
          private Node<T> header;
          private Node<T> trailer;
      
          public List_SLNode() {
              this.size = 0;
              this.header = new Node<T>(null, null);
              this.trailer = new Node<T>(null, null);
              this.header.setNext(this.trailer);
          }
      
          //辅助方法,检测传入参数是否合法  flag参数 {"prev","next","both"}
          protected Node<T> checkPosition(Position<T> p, checkFlag flag) throws ExceptionPositionInvalid {
              if(null == p)
                  throw new ExceptionPositionInvalid("错误3:传入的位置为空");
              if (checkFlag.PREV.equals(flag) || checkFlag.BOTH.equals(flag)) {
                  if(header == p)
                      throw new ExceptionPositionInvalid("错误4:传入的位置为头哨兵节点");
              }
              if (checkFlag.NEXT.equals(flag) || checkFlag.BOTH.equals(flag)) {
                  if(trailer == p)
                      throw new ExceptionPositionInvalid("错误5:传入的位置为尾哨兵节点");
              }
              return (Node<T>)p;
          }
      
      
          @Override
          public int getSize() {
              return size;
          }
      
          @Override
          public boolean isEmpty() {
              return (size == 0);
          }
      
          @Override
          public Node<T> first() throws ExceptionListEmpty {
              if (isEmpty())
                  throw new ExceptionListEmpty("错误6:单链表为空");
              return header.getNext();
          }
      
          @Override
          public Node<T> last() throws ExceptionListEmpty {
              if (isEmpty())
                  throw new ExceptionListEmpty("错误6:单链表为空");
              Node<T> temp = header;
              while (!temp.getNext().equals(trailer))
                  temp = temp.getNext();
              return temp;
          }
      
          protected Node<T> prev(Position<T> p, checkFlag flag) throws ExceptionPositionInvalid {
              Node<T> theElem = checkPosition(p, flag);
              Node<T> prev = header;
              while (!prev.getNext().equals(theElem))
                  prev = prev.getNext();
              return prev;
          }
          protected Node<T> next(Position<T> p, checkFlag flag) throws ExceptionPositionInvalid {
              Node<T> theElem = checkPosition(p, flag);
              return theElem.getNext();
          }
      
          @Override
          public Node<T> getPrev(Position<T> p) throws ExceptionPositionInvalid, ExceptionBoundaryViolation {
              Node<T> prev = prev(p, checkFlag.BOTH);
              if (prev == header)
                  throw new ExceptionBoundaryViolation("错误7:企图越过单链表前端");
              return prev;
          }
      
          @Override
          public Node<T> getNext(Position<T> p) throws ExceptionPositionInvalid, ExceptionBoundaryViolation {
              Node<T> next = next(p, checkFlag.BOTH);
              if (next == trailer)
                  throw new ExceptionBoundaryViolation("错误8:企图越过单链表后端");
              return next;
          }
      
          /*
          因为单链表的getPrev()和getNext()方法不能返回头尾哨兵,
          所以不能直接调用insertBefore()和insertAfter()方法而要单独实现.
          实现可以返回哨兵的内部方法
          */
          protected Node<T> getPrevIn(Position<T> p) throws ExceptionPositionInvalid {
              return prev(p, checkFlag.PREV);
          }
      
          protected Node<T> getNextIn(Position<T> p) throws ExceptionPositionInvalid {
              return next(p, checkFlag.NEXT);
          }
      
      
          @Override
          public Node<T> insertFirst(T e) {
              Node<T> newNode = new Node<T>(e, header.getNext());
              header.setNext(newNode);
              size++;
              return newNode;
          }
      
          @Override
          public Node<T> insertLast(T e) {
              Node<T> newNode = new Node<T>(e, trailer);
              Node<T> prev = getPrevIn(trailer);            //这样返回末节点的效率很低,另一种方法是单独存储末节点
              prev.setNext(newNode);
              size++;
              return newNode;
          }
      
          @Override
          public Node<T> insertBefore(Position<T> p, T e) throws ExceptionPositionInvalid {
              Node<T> theElem = checkPosition(p, checkFlag.BOTH);
              Node<T> newNode = new Node<T>(e, theElem);
              Node<T> prev = getPrev(theElem);
              prev.setNext(newNode);
              size++;
              return newNode;
          }
      
          @Override
          public Node<T> insertAfter(Position<T> p, T e) throws ExceptionPositionInvalid {
              Node<T> theElem = checkPosition(p, checkFlag.BOTH);
              Node<T> newNode = new Node<T>(e, theElem.getNext());
              theElem.setNext(newNode);
              size++;
              return newNode;
          }
      
          @Override
          public T remove(Position<T> p) throws ExceptionPositionInvalid {
              Node<T> theElem = checkPosition(p, checkFlag.BOTH);
              Node<T> prevNode = getPrevIn(theElem);
              prevNode.setNext(theElem.getNext());
              T elem = theElem.getElem();
              //将该位置(节点)从列表中摘出,以便系统回收其占用的空间
              theElem.setNext(null);
              size--;
              return elem;
          }
      
          @Override
          public T removeFirst() {
              return remove(header.getNext());
          }
      
          @Override
          public T removeLast() {
              return remove(getPrev(trailer));
          }
      
          @Override
          public T replace(Position<T> p, T e) throws ExceptionPositionInvalid {
              Node<T> theElem = checkPosition(p, checkFlag.BOTH);
              T elem = theElem.getElem();
              theElem.setElem(e);
              return elem;
          }
      
          @Override
          public Iterator<T> positions() {
              return new IteratorPosition<T>(this);
          }
      
          @Override
          public Iterator<T> elements() {
              return new IteratorElement<T>(this);
          }
      
          @Override
          public void show() {
              if (size == 0) System.out.println("单链表为空");
              else {
                  Position<T> elem = first();
                  System.out.print("[");
                  while (getNextIn(elem) != trailer) {
                      System.out.print(elem.getElem() + ", ");
                      elem = getNext(elem);
                  }
                  System.out.println(elem.getElem() + "]");
              }
          }
      }
      
  • Iterator 接口:

    • 迭代器接口,只有检查是否还有下一个元素和获取下一个元素两个功能。

      public interface Iterator<T> {
          boolean hasNext();
          Object getNext();
      }
      
    • IteratorElement 类:

      • 元素迭代器,只能获取元素,不能修改元素。

        public class IteratorElement<T> implements Iterator<T> {
            private List<T> list;
            private Position<T> nextPosition;
            public IteratorElement() {
                this.list = null;
            }
            public IteratorElement(List<T> L) {
                this.list = L;
                if (this.list.isEmpty())
                    this.nextPosition = null;
                else
                    this.nextPosition = this.list.first();
            }
        
            @Override
            public boolean hasNext() {
                return (this.nextPosition != null);
            }
        
            @Override
            public T getNext() throws ExceptionNoSuchElement {
                if (!hasNext()) throw new ExceptionNoSuchElement("错误9:迭代器中没有下一元素");
                Position<T> currentPosition = this.nextPosition;
                if (currentPosition == this.list.last())
                    this.nextPosition = null;
                else
                    this.nextPosition = list.getNext(currentPosition);
                return currentPosition.getElem();
            }
        }
        
    • IteratorPosition 类:

      • 位置迭代器,既能获取元素,也能修改元素。

        public class IteratorPosition<T> implements Iterator<T> {
            private List<T> list;
            private Position<T> nextPosition;
            public IteratorPosition() {
                list = null;
            }
            public IteratorPosition(List<T> L) {
                this.list = L;
                if (list.isEmpty())
                    nextPosition = null;
                else
                    nextPosition = list.first();
            }
        
            @Override
            public boolean hasNext() {
                return (nextPosition != null);
            }
        
            @Override
            public Position<T> getNext() throws ExceptionNoSuchElement {
                if (!hasNext()) throw new ExceptionNoSuchElement("错误9:迭代器中没有下一元素");
                Position<T> currentPosition = nextPosition;
                if (currentPosition == list.last())
                    nextPosition = null;
                else
                    nextPosition = list.getNext(currentPosition);
                return currentPosition;
            }
        }
        
  • SLList_Test 类:

    • 测试单链表的有关功能。

      public class SLList_Test {
          public static void main(String[] args) {
      
              List<Integer> list = new List_SLNode<Integer>();
              Random random = new Random();
      
              if (list.isEmpty()) {
                  System.out.println("单链表为空");
              }
              System.out.println("初始化单链表:");
              int num = 20;
              for (int i=0; i<num; i++) {
                  list.insertLast(random.nextInt(100));
              }
              list.show();
      
              //元素迭代器只能遍历并取出元素
              System.out.println("元素迭代器遍历单链表");
              Iterator<Integer> elements = list.elements();
              while (elements.hasNext()) {
                  System.out.print(elements.getNext() + " ");
              }
              System.out.println();
      
              //位置迭代器可以修改元素
              System.out.println("位置迭代器遍历并修改单链表内容为原来的三倍:");
              Iterator<Integer> positions1 = list.positions();
              while (positions1.hasNext()) {
                  Position<Integer> position = (Position<Integer>) positions1.getNext();
                  position.setElem(position.getElem() * 3);
              }
              list.show();
      
              System.out.println("在单链表首尾插入0");
              list.insertFirst(0);
              list.insertLast(0);
              list.show();
      
              System.out.println("在单链表首后尾前插入-5");
              list.insertAfter(list.first(), -5);
              list.insertBefore(list.last(), -5);
              list.show();
      
              System.out.println("位置迭代器遍历单链表,将大于200的元素置为200,小于0的元素删除:");
              Iterator<Integer> positions2 = list.positions();
              while (positions2.hasNext()) {
                  Position<Integer> position = (Position<Integer>) positions2.getNext();
                  if (position.getElem() > 200) {
                      list.replace(position, 200);
                  }
                  if (position.getElem() < 0) {
                      list.remove(position);
                  }
              }
              System.out.println("还剩" + list.getSize() + "个元素");
              list.show();
          }
      }
      
    • 测试结果:

      单链表为空
      初始化单链表:
      [25, 30, 3, 77, 67, 78, 17, 33, 63, 49, 34, 47, 44, 71, 57, 82, 79, 66, 45, 32]
      元素迭代器遍历单链表
      25 30 3 77 67 78 17 33 63 49 34 47 44 71 57 82 79 66 45 32 
      位置迭代器遍历并修改单链表内容为原来的三倍:
      [75, 90, 9, 231, 201, 234, 51, 99, 189, 147, 102, 141, 132, 213, 171, 246, 237, 198, 135, 96]
      在单链表首尾插入0
      [0, 75, 90, 9, 231, 201, 234, 51, 99, 189, 147, 102, 141, 132, 213, 171, 246, 237, 198, 135, 96, 0]
      在单链表首后尾前插入-5
      [0, -5, 75, 90, 9, 231, 201, 234, 51, 99, 189, 147, 102, 141, 132, 213, 171, 246, 237, 198, 135, 96, -5, 0]
      位置迭代器遍历单链表,将大于200的元素置为200,小于0的元素删除:
      还剩22个元素
      [0, 75, 90, 9, 200, 200, 200, 51, 99, 189, 147, 102, 141, 132, 200, 171, 200, 200, 198, 135, 96, 0]
      

3、双向链表

  • DL_Node 类:

    • 双链表节点实现类,存有指向前驱和后继的位置信息。

      public class DL_Node<T> implements Position<T> {
          private T element;      //存储的数据内容
          private DL_Node<T> prev;    //指向上一个节点
          private DL_Node<T> next;   //指向下一个节点
          public DL_Node(){
              this(null, null, null);
          }
          public DL_Node(T e, DL_Node<T> p, DL_Node<T> n){
              this.element = e;
              this.prev = p;
              this.next = n;
          }
          @Override
          public T getElem() {
              return element;
          }
          @Override
          public T setElem(T e) {
              T ori_element = element;
              element = e;
              return ori_element;
          }
          //双链表节点方法
          public void setNext(DL_Node<T> newNext) {
              next = newNext;
          }
          public void setPrev(DL_Node<T> newPrev) {
              prev = newPrev;
          }
          public DL_Node<T> getNext() {
              return next;
          }
          public DL_Node<T> getPrev() {
              return prev;
          }
      }
      
  • List_DLNode 类:

    • 双向链表实现类。

    • 查找操作的接口定义是前n个真前驱(不包括)。

    • 去重操作中,删除前驱中的雷同项比较方便,否则处理指向比较复杂。

      public class List_DLNode<T> implements List<T> {
      
          private int size;
          private DL_Node<T> header;
          private DL_Node<T> trailer;
      
          public List_DLNode() {
              this.size = 0;
              this.header = new DL_Node<T>(null, null, null);
              this.trailer = new DL_Node<T>(null, this.header, null);
              this.header.setNext(this.trailer);
          }
      
          public List_DLNode(DL_Node<T> h, int n) {
              this.size = 1;
              this.header = new DL_Node<T>(null, null, null);
              this.trailer = new DL_Node<T>(null, null, null);
              DL_Node<T> newNode = new DL_Node<T>(h.getElem(), this.header, this.trailer);
              this.header.setNext(newNode);
              this.trailer.setPrev(newNode);
              while (--n > 0) {
                  newNode = insertAfter(newNode, h.getNext().getElem());
                  h = h.getNext();
              }
          }
      
          //辅助方法,检测传入参数是否合法  flag参数 {"prev","next","both"}
          protected DL_Node<T> checkPosition(Position<T> p, checkFlag flag) throws ExceptionPositionInvalid {
              if(null == p)
                  throw new ExceptionPositionInvalid("错误3:传入的位置为空");
              if (checkFlag.PREV.equals(flag) || checkFlag.BOTH.equals(flag)) {
                  if(this.header == p)
                      throw new ExceptionPositionInvalid("错误4:传入的位置为头哨兵节点");
              }
              if (checkFlag.NEXT.equals(flag) || checkFlag.BOTH.equals(flag)) {
                  if(this.trailer == p)
                      throw new ExceptionPositionInvalid("错误5:传入的位置为尾哨兵节点");
              }
              return (DL_Node<T>)p;
          }
      
      
          @Override
          public int getSize() {
              return size;
          }
      
          @Override
          public boolean isEmpty() {
              return (size == 0);
          }
      
          @Override
          public DL_Node<T> first() throws ExceptionListEmpty {
              if (isEmpty())
                  throw new ExceptionListEmpty("错误10:双链表为空");
              return header.getNext();
          }
      
          @Override
          public DL_Node<T> last() throws ExceptionListEmpty {
              if (isEmpty())
                  throw new ExceptionListEmpty("错误10:双链表为空");
              return trailer.getPrev();
          }
      
          protected DL_Node<T> prev(Position<T> p, checkFlag flag) throws ExceptionPositionInvalid {
              DL_Node<T> theElem = checkPosition(p, flag);
              return theElem.getPrev();
          }
          protected DL_Node<T> next(Position<T> p, checkFlag flag) throws ExceptionPositionInvalid {
              DL_Node<T> theElem = checkPosition(p, flag);
              return theElem.getNext();
          }
      
          @Override
          public DL_Node<T> getPrev(Position<T> p) throws ExceptionPositionInvalid, ExceptionBoundaryViolation {
              DL_Node<T> prev = prev(p, checkFlag.BOTH);
              if (prev == header)
                  throw new ExceptionBoundaryViolation("错误11:企图越过单链表前端");
              return prev;
          }
      
          @Override
          public DL_Node<T> getNext(Position<T> p) throws ExceptionPositionInvalid, ExceptionBoundaryViolation {
              DL_Node<T> next = next(p, checkFlag.BOTH);
              if (next == this.trailer)
                  throw new ExceptionBoundaryViolation("错误12:企图越过单链表后端");
              return next;
          }
      
          protected DL_Node<T> getPrevIn(Position<T> p) throws ExceptionPositionInvalid {
              return prev(p, checkFlag.PREV);
          }
      
          protected DL_Node<T> getNextIn(Position<T> p) throws ExceptionPositionInvalid {
              return next(p, checkFlag.NEXT);
          }
      
          @Override
          public DL_Node<T> insertFirst(T e) {
              DL_Node<T> newNode = new DL_Node<T>(e, header, header.getNext());
              header.getNext().setPrev(newNode);
              header.setNext(newNode);
              size++;
              return newNode;
          }
      
          @Override
          public DL_Node<T> insertLast(T e) {
              DL_Node<T> newNode = new DL_Node<T>(e, trailer.getPrev(), trailer);
              trailer.getPrev().setNext(newNode);
              trailer.setPrev(newNode);
              size++;
              return newNode;
          }
      
          @Override
          public DL_Node<T> insertBefore(Position<T> p, T e) throws ExceptionPositionInvalid {
              DL_Node<T> theElem = checkPosition(p, checkFlag.BOTH);
              DL_Node<T> newNode = new DL_Node<T>(e, theElem.getPrev(), theElem);
              theElem.getPrev().setNext(newNode);
              theElem.setPrev(newNode);
              size++;
              return newNode;
          }
      
          @Override
          public DL_Node<T> insertAfter(Position<T> p, T e) throws ExceptionPositionInvalid {
              DL_Node<T> theElem = checkPosition(p, checkFlag.BOTH);
              DL_Node<T> newNode = new DL_Node<T>(e, theElem, theElem.getNext());
              theElem.getNext().setPrev(newNode);
              theElem.setNext(newNode);
              size++;
              return newNode;
          }
      
          @Override
          public T remove(Position<T> p) throws ExceptionPositionInvalid {
              DL_Node<T> theElem = checkPosition(p, checkFlag.BOTH);
              DL_Node<T> prevNode = getPrevIn(theElem);
              theElem.getNext().setPrev(prevNode);
              prevNode.setNext(theElem.getNext());
              T elem = theElem.getElem();
              //将该位置(节点)从列表中摘出,以便系统回收其占用的空间
              theElem.setPrev(null);
              theElem.setNext(null);
              size--;
              return elem;
          }
      
          @Override
          public T removeFirst() {
              return remove(header.getNext());
          }
      
          @Override
          public T removeLast() {
              return remove(trailer.getPrev());
          }
      
          @Override
          public T replace(Position<T> p, T e) throws ExceptionPositionInvalid {
              DL_Node<T> theElem = checkPosition(p, checkFlag.BOTH);
              T elem = theElem.getElem();
              theElem.setElem(e);
              return elem;
          }
      
          @Override
          public Iterator<T> positions() {
              return new IteratorPosition<T>(this);
          }
      
          @Override
          public Iterator<T> elements() {
              return new IteratorElement<T>(this);
          }
      
          @Override
          public void show() {
              if (size == 0) System.out.println("双链表为空");
              else {
                  Position<T> elem = first();
                  System.out.print("[");
                  while (getNextIn(elem) != trailer) {
                      System.out.print(elem.getElem() + ", ");
                      elem = getNext(elem);
                  }
                  System.out.println(elem.getElem() + "]");
              }
          }
      
          //循秩访问
          public DL_Node<T> getAtRank(int Rank) {
              if (Rank < 0 || Rank >= size)
                  throw new ExceptionBoundaryViolation("错误13:传入的秩越界");
              DL_Node<T> node = first();
              while (Rank-- > 0) {
                  node = node.getNext();
              }
              return node;
          }
      
          //查找
          public DL_Node<T> find(T e, int n, Position<T> p) throws ExceptionPositionInvalid,NullPointerException {
              if (e == null)
                  throw new NullPointerException("错误14:传入的数值为空");
              DL_Node<T> node = checkPosition(p, checkFlag.BOTH).getPrev();      //注意,接口定义是前n个真前驱(不包括)
              while (n-- > 0) {
                  if (e.equals(node.getElem())) {     //防止空指针异常
                      return node;
                  }
                  node = node.getPrev();
              }
              return null;
          }
      
          //去重
          public int uniquify()  throws ExceptionPositionInvalid, NullPointerException {
              if (size < 2) return 0;
              DL_Node<T> node = first();
              int prevNum = 0;
              int removeNum = 0;
              while (node != trailer) {
                  DL_Node<T> temp = find(node.getElem(),prevNum, node);
                  if ((temp != null)) {       //删除前驱中的雷同项比较方便,否则处理指向比较复杂
                      remove(temp);
                      removeNum++;
                  } else {
                      prevNum++;
                  }
                  node = node.getNext();
              }
              return removeNum;
          }
      }
      
  • DLList_Test 类:

    • 双向链表测试类。

      public class DLList_Test {
          public static void main(String[] args) {
      
              List_DLNode<Integer> list = new List_DLNode<Integer>();
              Random random = new Random();
      
              if (list.isEmpty()) {
                  System.out.println("双链表为空");
              }
              System.out.println("初始化双链表:");
              int num = 20;
              for (int i=0; i<num; i++) {
                  list.insertLast(random.nextInt(100));
              }
              list.show();
      
              //元素迭代器只能遍历并取出元素
              System.out.println("元素迭代器遍历双链表");
              Iterator<Integer> elements = list.elements();
              while (elements.hasNext()) {
                  System.out.print(elements.getNext() + " ");
              }
              System.out.println();
      
              //位置迭代器可以修改元素
              System.out.println("位置迭代器遍历并修改双链表内容为原来的三倍:");
              Iterator<Integer> positions1 = list.positions();
              while (positions1.hasNext()) {
                  Position<Integer> position = (Position<Integer>) positions1.getNext();
                  position.setElem(position.getElem() * 3);
              }
              list.show();
      
              System.out.println("在双链表首尾插入0");
              list.insertFirst(0);
              list.insertLast(0);
              list.show();
      
              System.out.println("在双链表首后尾前插入-5");
              list.insertAfter(list.first(), -5);
              list.insertBefore(list.last(), -5);
              list.show();
      
              System.out.println("位置迭代器遍历双链表,将大于200的元素置为200,小于0的元素删除:");
              Iterator<Integer> positions2 = list.positions();
              while (positions2.hasNext()) {
                  Position<Integer> position = (Position<Integer>) positions2.getNext();
                  if (position.getElem() > 200) {
                      list.replace(position, 200);
                  }
                  if (position.getElem() < 0) {
                      list.remove(position);
                  }
              }
              System.out.println("还剩" + list.getSize() + "个元素");
              list.show();
      
              System.out.println("基于复制的构造:");
              System.out.println("完全复制:");
              List_DLNode<Integer> list2 = new List_DLNode<Integer>((DL_Node<Integer>)list.first(), list.getSize());
              list2.show();
              System.out.println("复制前10个元素:");
              List_DLNode<Integer> list3 = new List_DLNode<Integer>((DL_Node<Integer>)list.first(), 10);
              list3.show();
      
              System.out.println("获取秩为7的元素:");
              System.out.println(list.getAtRank(7).getElem());
              System.out.println("在其后插入-10");
              list.insertAfter(list.getAtRank(7), -10);
              list.show();
      
              System.out.println("在整个双链表中查找为-10的元素:");
              DL_Node<Integer> node = list.find(-10, list.getSize(), list.last());
              if (node != null)
                  System.out.println("值为" + node.getElem() + "的元素的前驱和后继分别为" + node.getPrev().getElem() + "和" + node.getNext().getElem());
      
              System.out.println("去重");
              int removeNum = list.uniquify();
              System.out.println("共删除了" + removeNum + "个重复元素");
              list.show();
      
              System.out.println("选择排序:");
              Sorter_Selectsort<Integer> selectsort = new Sorter_Selectsort<Integer>();
              selectsort.sort(list);
              list.show();
          }
      }
      
    • 测试结果:

      双链表为空
      初始化双链表:
      [84, 78, 82, 15, 70, 9, 55, 28, 9, 86, 40, 92, 27, 96, 91, 57, 77, 96, 15, 44]
      元素迭代器遍历双链表
      84 78 82 15 70 9 55 28 9 86 40 92 27 96 91 57 77 96 15 44 
      位置迭代器遍历并修改双链表内容为原来的三倍:
      [252, 234, 246, 45, 210, 27, 165, 84, 27, 258, 120, 276, 81, 288, 273, 171, 231, 288, 45, 132]
      在双链表首尾插入0
      [0, 252, 234, 246, 45, 210, 27, 165, 84, 27, 258, 120, 276, 81, 288, 273, 171, 231, 288, 45, 132, 0]
      在双链表首后尾前插入-5
      [0, -5, 252, 234, 246, 45, 210, 27, 165, 84, 27, 258, 120, 276, 81, 288, 273, 171, 231, 288, 45, 132, -5, 0]
      位置迭代器遍历双链表,将大于200的元素置为200,小于0的元素删除:
      还剩22个元素
      [0, 200, 200, 200, 45, 200, 27, 165, 84, 27, 200, 120, 200, 81, 200, 200, 171, 200, 200, 45, 132, 0]
      基于复制的构造:
      完全复制:
      [0, 200, 200, 200, 45, 200, 27, 165, 84, 27, 200, 120, 200, 81, 200, 200, 171, 200, 200, 45, 132, 0]
      复制前10个元素:
      [0, 200, 200, 200, 45, 200, 27, 165, 84, 27]
      获取秩为7的元素:
      165
      在其后插入-10
      [0, 200, 200, 200, 45, 200, 27, 165, -10, 84, 27, 200, 120, 200, 81, 200, 200, 171, 200, 200, 45, 132, 0]
      在整个双链表中查找为-10的元素:
      值为-10的元素的前驱和后继分别为165和84
      去重
      共删除了12个重复元素
      [165, -10, 84, 27, 120, 81, 171, 200, 45, 132, 0]
      选择排序:
      [-10, 0, 27, 45, 81, 84, 120, 132, 165, 171, 200]
      

4、有序列表

  • List_SortedDLNode 类:

    • 有序列表实现类,继承自双链表。

      public class List_SortedDLNode<T extends Comparable> extends List_DLNode<T> {
      
          public boolean isSorted() {
              DL_Node<T> head = super.first();
              while (!head.equals(super.last())) {
                  if (head.getElem().compareTo(head.getNext().getElem()) == 1) {
                      return false;
                  }
                  head = head.getNext();
              }
              return true;
          }
      
          public DL_Node<T> search(T e, int n, DL_Node<T> p) throws ExceptionPositionInvalid,NullPointerException {
              if (e == null)
                  throw new NullPointerException("错误14:传入的数值为空");
              DL_Node<T> node = checkPosition(p, checkFlag.BOTH).getPrev();      //注意,接口定义是前n个真前驱(不包括)
              DL_Node<T> res = new DL_Node<T>();
              while (n-- > 0) {
                  if (e.compareTo(node.getElem()) < 0) {     //防止空指针异常
                      res = node;
                  }
                  node = node.getPrev();
              }
              return res.getPrev();
          }
      
          @Override
          public int uniquify() throws ExceptionListNotSorted, ExceptionPositionInvalid, NullPointerException {
              if (!isSorted())
                  throw new ExceptionListNotSorted("错误15:列表不是有序的,不能直接调用有序列表的方法");
              if (getSize() < 2) return 0;
              int removeNum = 0;
              DL_Node<T> p = first();
              DL_Node<T> q = p.getNext();
              while (!super.last().equals(q)) {
                  if (!p.getElem().equals(q.getElem())) {
                      p = q;
                  } else {
                      remove(q);
                      removeNum++;
                  }
                  q = p.getNext();
              }
              return removeNum;
          }
      }
      
  • Sorter_Selectsort 类:

    • 选择排序排序器,实现了排序器接口。

    • head是头哨兵,注意初始化要获取p的前驱,不然删除操作作用于p,会使得p的指向发生变化。同样的,在操作时要在对head的后继操作。

    • insertBefore()无法对尾哨兵操作,需要单独进行处理。

      public class Sorter_Selectsort<T> implements Sorter<T> {
      
          private Comparator C;
      
          public Sorter_Selectsort()
          {  this(new ComparatorDefault()); }
      
          public Sorter_Selectsort(Comparator comp)
          {  C = comp; }
      
      
          @Override
          public void sort(Vector<T> vector) {
      
          }
      
          @Override
          public void sort(List<T> list) {
              selectionSort((List_DLNode<T>)list, (DL_Node<T>)list.first(), list.getSize());
          }
      
          private void selectionSort(List_DLNode<T> list, DL_Node<T> p, int n) {
              DL_Node<T> head = p.getPrev();          //head是头哨兵,注意这里要获取p的前驱,不然删除操作作用于p,会使得p发生变换
              DL_Node<T> tail = p;
              for (int i=0; i<n; i++)
                  tail = tail.getNext();
              if (list.last().getNext().equals(tail)) {       //insertBefore无法对尾哨兵操作
                  list.insertLast(list.remove(selectMax(head.getNext(), n--)));       //对head的后继操作
                  tail = tail.getPrev();
              }
              while (1 < n) {
                  list.insertBefore(tail, list.remove(selectMax(head.getNext(), n)));
                  tail = tail.getPrev();
                  n--;
              }
          }
      
          private DL_Node<T> selectMax(DL_Node<T> p, int n) {     //起始于p的n个元素(包括p)的最大值
              DL_Node<T> max = p;
              for (DL_Node<T> cur = p; 1<n; n--) {
                  cur = cur.getNext();
                  if (C.compare(cur.getElem(), max.getElem()) >= 0) {
                      max = cur;
                  }
              }
              return max;
          }
      }
      
  • Sorter_Insertsort 类:

    • 插入排序排序器,实现了排序器接口。

    • 由于传入的是无序列表,所以无法调用无序列表的子类方法search(),需要手动再实现一遍。

      public class Sorter_Insertsort<T> implements Sorter<T> {
      
          private Comparator C;
      
          public Sorter_Insertsort()
          {  this(new ComparatorDefault()); }
      
          public Sorter_Insertsort(Comparator comp)
          {  C = comp; }
      
      
          @Override
          public void sort(Vector<T> vector) {
      
          }
      
          @Override
          public void sort(List<T> list) {
              insertionSort((List_DLNode<T>)list, (DL_Node<T>)list.first(), list.getSize());
          }
      
          private void insertionSort(List_DLNode<T> list, DL_Node<T> p, int n) throws ExceptionPositionInvalid, NullPointerException {
      
              for (int r=0; r<n; r++) {
                  if (p == null || p.getElem() == null)
                      throw new NullPointerException("错误14:传入的数值为空");
                  if (p.equals(list.first().getPrev()))
                      throw new ExceptionPositionInvalid("错误4:传入的位置为头哨兵节点");
                  if (p.equals(list.last().getNext()))
                      throw new ExceptionPositionInvalid("错误5:传入的位置为尾哨兵节点");
                  DL_Node<T> node = p;
                  DL_Node<T> res = p;
                  int k = r;
                  T e = p.getElem();
                  while (k-- >= 0) {
                      if (C.compare(e, node.getElem()) < 0) {
                          res = node;
                      }
                      node = node.getPrev();
                  }
                  res = res.getPrev();
                  if (res.equals(list.first().getPrev())) {
                      list.insertFirst(e);
                  } else {
                      list.insertAfter(res, e);
                  }
                  p = p.getNext();
                  list.remove(p.getPrev());
              }
          }
      }
      
  • SortedDLList_Test 类:

    • 有序列表测试类。

      public class SortedDLList_Test {
          public static void main(String[] args) {
      
              List_SortedDLNode<Integer> list1 = new List_SortedDLNode<Integer>();
              Random random = new Random();
      
              System.out.println("初始化有序双链表:");
              int num = 20;
              for (int i=0; i<num; i++) {
                  list1.insertLast(random.nextInt(100));
              }
              list1.show();
      
              System.out.println("在首节点后插元素50");
              list1.insertAfter(list1.first(), 50);
              list1.show();
      
              System.out.println("选择排序:");
              Sorter_Selectsort<Integer> selectsort = new Sorter_Selectsort<Integer>();
              selectsort.sort(list1);
              list1.show();
      
              System.out.println("去重");
              int removeNum = list1.uniquify();
              System.out.println("共删除了" + removeNum + "个重复元素");
              list1.show();
      
              System.out.println("查找元素50并删除:");       //对于最后一个元素要单独判断,因为接口定义的是判断真前驱(不包括),而且无法传入尾哨兵
              DL_Node<Integer> node = list1.search(50, list1.getSize()-1, list1.last());
              list1.remove(node);
              list1.show();
      
      
              List_SortedDLNode<Integer> list2 = new List_SortedDLNode<Integer>();
      
              System.out.println("初始化有序双链表:");
              for (int i=0; i<num; i++) {
                  list2.insertLast(random.nextInt(100));
              }
              list2.show();
      
              System.out.println("插入排序:");
              Sorter_Insertsort<Integer> insertsort = new Sorter_Insertsort<Integer>();
              selectsort.sort(list2);
              list2.show();
      
          }
      }
      
    • 测试结果:

      初始化有序双链表:
      [11, 63, 7, 28, 47, 50, 68, 17, 86, 52, 78, 19, 24, 4, 33, 41, 4, 95, 93, 45]
      在首节点后插元素50
      [11, 50, 63, 7, 28, 47, 50, 68, 17, 86, 52, 78, 19, 24, 4, 33, 41, 4, 95, 93, 45]
      选择排序:
      [4, 4, 7, 11, 17, 19, 24, 28, 33, 41, 45, 47, 50, 50, 52, 63, 68, 78, 86, 93, 95]
      去重
      共删除了2个重复元素
      [4, 7, 11, 17, 19, 24, 28, 33, 41, 45, 47, 50, 52, 63, 68, 78, 86, 93, 95]
      查找元素50并删除:
      [4, 7, 11, 17, 19, 24, 28, 33, 41, 45, 47, 52, 63, 68, 78, 86, 93, 95]
      初始化有序双链表:
      [3, 77, 41, 24, 21, 2, 33, 65, 17, 63, 61, 3, 17, 92, 9, 1, 98, 84, 33, 17]
      插入排序:
      [1, 2, 3, 3, 9, 17, 17, 17, 21, 24, 33, 33, 41, 61, 63, 65, 77, 84, 92, 98]
      

5、思考

  • 序列 Sequence 接口继承了向量和列表接口,但是其传入向量或列表的方法仍然需要分别实现。

  • 在列表操作中,指向的赋予顺序很重要。

  • 涉及删除操作时,不要删除要复用的变量,不然会出现空指针异常(指向为空),可以删除复用变量的前驱或后继。

  • 虽然不能让外部传入哨兵节点,但是列表的内部操作经常需要传入参数为哨兵节点。

  • Java中的枚举:

    //创建
    enum checkFlag {
        PREV, NEXT, BOTH
    }
    checkFlag flag;
    //判等,用 == 也可以
    boolean b = checkFlag.PREV.equals(flag);
    //更多见https://www.cnblogs.com/singlecodeworld/p/9887926.html
    
  • Java中方法没有传入的默认参数,一般用重载实现这个需求。

  • 列表部分的异常:

    1. List_SLNode:错误3:传入的位置为空。
    2. List_SLNode:错误4:传入的位置为头哨兵节点。
    3. List_SLNode:错误5:传入的位置为尾哨兵节点。
    4. List_SLNode:错误6:单链表为空。
    5. List_SLNode:错误7:企图越过单链表前端。
    6. List_SLNode:错误8:企图越过单链表后端。
    7. List_SLNode:错误9:迭代器中没有下一元素。
    8. List_DLNode:错误10:双链表为空。
    9. List_DLNode:错误11:企图越过单链表前端。
    10. List_DLNode:错误12:企图越过单链表后端。
    11. List_DLNode:错误13:传入的秩越界。
    12. List_DLNode:错误14:传入的数值为空。
    13. List_SortedDLNode:错误15:列表不是有序的,不能直接调用有序列表的方法。

iwehdio的博客园:https://www.cnblogs.com/iwehdio/

posted @ 2020-04-02 18:02  iwehdio  阅读(185)  评论(0编辑  收藏  举报