zoukankan      html  css  js  c++  java
  • 数据结构与算法(三+)——列表的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/

  • 相关阅读:
    移动零
    移除元素
    Ubuntu下安装PIL
    CSS颜色代码大全
    Test__GUI__用java编写一个简单的记事本程序,打包成jar双击运行
    Test__GUI__列出指定目录内容
    GUI__【GUI概述】【布局】【Frame】【事件监听机制】【窗体事件】【按钮】【鼠标事件】【键盘事件】【Dialog对话框】【菜单】
    Test__IO流综合应用的小练习
    IO流__【转换流的字符编码】【编码与解码】【字符编码-“联通”】
    IO流__【对象的序列化】【管道流】【RandomAccessFile】【DataStream】【ByteArrayStream等】
  • 原文地址:https://www.cnblogs.com/iwehdio/p/12621460.html
Copyright © 2011-2022 走看看