数据结构与算法(Java语言描述)--链表-02

来源:互联网 发布:关口知宏2017来中国 编辑:程序博客网 时间:2024/06/05 09:09

此篇续着01篇,为基本链表的一些拓展

好我们继续


使用链表实现栈:

/*使用链表实现栈操作*/public class LinkStack {    public LinkList list = new LinkList();    // 用链表的向前插入数据 模拟压栈操作    public void push(long dd) { list.insertFirst(dd); }    // 用链表的从前开始山粗数据 模拟出栈操作    public Link pop() { return list.deleteFirst(); }    public boolean isEmpty() { return list.isEmpty(); }    public void displayStack() {        System.out.println("Stack: ( top -> bottom ) :");        list.displayList();    }    // Test}class LinkList {    public Link first;    public LinkList() {        first = null;    }    public boolean isEmpty() { return (first == null); }    // 从前向后添加数据    public void insertFirst(long dd) {        Link newLink = new Link(dd);        newLink.next = first;        first = newLink;    }    // 从前向后删除数据    public Link deleteFirst() {        Link temp = first;        first = first.next;        return temp;    }       // 打印链表    public void displayList() {        Link current = first;        while (current != null) {            current.displayLink();            current = current.next;        }    }}

使用链表实现队列
     使用链表实习那队列首先使用的是一个双端链表 取了它的 insertLast 方法模拟队列的 insert,然后选择了一个 deleteFirst 方法模拟队列的 remove 用不同端的操作,实现了数据的先出。

/** * 用链表模拟队列 */public class LinkQueue {    private FirstLastLink thelist;    public LinkQueue() { thelist = new FirstLastLink(); }    public boolean isEmpty() { return thelist.isEmpty(); }    public void insert(long dd) { thelist.insertLast(dd); }    public long remove() { return thelist.deletFirst().dData; }    public void displayQueue() { thelist.displayList(); }    // 测试数据省略}/*双端链表*/class FirstLastLink {    public Link first;    public Link last;    public FirstLastLink() {        first = null;        last = null;    }    public boolean isEmpty() {        return (first == null);    }    public void insertLast(long dd) {        Link newLink = new Link(dd);        if ( isEmpty() )            first = newLink;        else            last.next = newLink;        last = newLink;    }    public Link deletFirst() {        Link temp = first;        if (first.next == null)            last = null;        first = first.next;        return temp;    }    public void displayList() {        Link current = first;        while (current != null) {            current.displayLink();            current = current.next;        }        System.out.println("");    }}

有序链表
     有序链表的实现,主要的区别在于它的插入的操作上,它的插入操作 增加了排序的功能,通过比较链表中已有的数据,选择到合适的插入位置,然后进行插操作。
     有序链表插入和删除某一项数据的时候需要 O(N) 次比较 (平均 N/2)次,因此必须沿着链表上一步一步走才能找到正确的位置,但是这种数据结构可以在 O(1) 的时间内找到或者删除最小值,因为最小值的位置总是在表头!

/*有序链表*/public class sortedList     private Link first;    public sortedList() { first = null; }    public boolean isEmpty() { return (first == null); }    // 插入数据后排序    public void insert(long dd) {        Link newLink = new Link(dd);        // 创建一个新结点        Link previous = null;               // 之前的        Link current = first;               // 当前的        while (current != null && dd > current.dd) {    // 如果当前的结点不为空  且新插入的数据比当前节点的数据要大            previous = current;                         // 维护现在的结点            current = current.next;                     // 将现在的结点向后移动一个单位        }        // 找到合适的插入位置后进行数据的插入操作        if (previous == null)                           // 当插入的数据为最小的时候             first = newLink;                            // 就将该数据项直接加到最前的位置        else            previous.next = newLink;                    // 这时的 previous 就是最后一个有数据的结点  或者是最后一个比插入数据小的存在的结点        newLink.next = current;                         // 将新的结点放在  当下的 previous 和 current 结点之间完成插入操作    }    // 删除数据    public Link remove() {        Link temp = first;        first = first.next;        return temp;    }    public void displayList() {        System.out.println("List (first -> last) :");        Link current = first;        while (current != null) {            current.displayLink();            current = current.next;        }        System.out.println("");    }// Test  测试数据省略}

双向链表
     传统的链表存在着一个潜在的问题就是沿着链表的反方向遍历的话是非常困难的。
     双向链表的出现,提供了这样一个能力,允许其向前遍历。其中的秘密就在于每个链结点有两个指向其他链结点的引用。
这里写图片描述
      双向链表的缺点就在于,每次插入一个数据或者删除一个结点的数据的时候,要处理四个结点的引用,而不是两个,两个连接前一个链结点,两个连接后一个结点,由于多了两个引用,链接点的占用空间也大了一些!
下面为其代码演示

// 双向链表的链节点类:public class Link {    public long dData;    public Link next;    public Link previous;    public Link(long d) { dData = d; };    public void displayLink() { System.out.println("{" + dData + "}"); }}
// 双向链表的实现类public class DoublyLinkedList {    private Link first;    private Link last;    public DoublyLinkedList() { first = null; last = null;}    public boolean isEmpty() { return first == null; }    // 插入数据(前)    public void insertFirst(long dd) {        Link newLink = new Link(dd);    // 创建一个新结点        if (isEmpty())                  // 如果是新链表插入数据            last = newLink;             // 首先让 last 指向新的结点        else                                        first.previous = newLink;   // 如果不为空的话 让原首位结点的 prev 执行新节点        newLink.next = first;           // 新结点的 next 指向原首位结点        first = newLink;                // first 指向新结点    }    // 插入数据(后)    public void insertLast(long dd) {           Link newLink = new Link(dd);            if (isEmpty())                  // 如果是新链表插入数据            first = newLink;            // 首先让 first 执行新的结点        else {                                      last.next = newLink;        // 原末位的 next 指向新的结点             newLink.previous = last;    // 新结点的 prev 指向原末尾节点        }        last = newLink;                 // last 指向新节点    }    // 删除数据(前)    public Link deleteFirst() {        Link temp = first;              // 对要返回的数据进行维护        if (first.next == null)         // 如果链表中只有一个元素            last = null;                // 断开其与 last 的连接        else            first.next.previous = null; // 断开要首结点中后一结点对其的引用        first = first.next;             // first 指向下一个结点        return temp;    }    // 删除数据(后)    public Link deleteLast() {        Link temp = last;                       if (first.next == null)         // 如果链表中只有一个元素            first = null;               // 断开器与 first 的连接        else            last.previous.next = null;  // 断开尾结点前以结点对尾结点的引用        last = last.previous;           // last 指向前一个结点        return temp;    }    // 在制指定的结点后插入数据    public boolean insertAfter(long key, long dd) {        Link current = first;                   while (current.dData != key) {  // 如果当前结点的数据不等于 key            current = current.next;     // 查看下一个结点            if (current == null) {      // 表示 当前的结点为最后一个结点                return false;           // 没有找到对应的结点 返回 false            }        }                                        // --- 走到这说明已经找到了对应的结点  开始进行插入数据操作        Link newLink = new Link(dd);        if (current == last) {          // 如果找到的结点为最后一个            newLink.next = null;        // 新结点的 next 置为空, 因为每一个 尾结点的next 都为空            last = newLink;             // last 指向该结点        } else {                                // 如果该结点不在最后一个            newLink.next = current.next;        // 新结点的 next 指向当前结点的下一个结点            current.next.previous = newLink;    // 当前结点的下一个结点的前一个结点的 prev 指向新结点        }        newLink.previous = current;     // 新结点的 prev 指向当前结点        current.next = newLink;         // 当前节点的 next 指向新结点        return true;    }    // 删除指定的结点    public Link deleteKey(long key) {        Link current = first;        while (current.dData != key) {  // 找结点            current = current.next;            if (current == null)        // 若找不到                return null;            // 返回 null        }        if (current == first)           // 如果找到的结点是第一个            first = current.next;       // 将 first 的指向变为下一个结点        else            current.previous.next = current.next;   // 要删节点的前一个结点的 next 指向要删结点的下一个结点        if (current == last)            // 如果找到的为最后一个            last = current.previous;    // 将 last 的指向变为前一个节点        else            current.next.previous = current.previous;   // 要删结点的下一个节点的 prev 指向 要删结点的前一个节点        return current;    }    // 遍历( 前 -> 后 )    public void displayForward() {        System.out.println("List (first -> last) :");        Link current = first;        while (current != null) {            current.displayLink();            current = current.next; // 当前 ->        }        System.out.println();    }    // 遍历( 后 -> 前 )    public void displayBackward() {        System.out.println("List (last -> first) :");        Link current = last;        while (current != null) {            current.displayLink();            current = current.previous; // 当前 <-        }        System.out.println();    }}// 上面的 prev指的是某结点对其前一个结点的引用    next 指的是对后一个结点的引用

     个人觉得双向链表的实现,其实就是在基链表的基础上增加了一个引用的处理,其实原理还是很好理解的,就单说插从头部数据而言,其实就是两步:首先让新结点的 next 指向原头结点,再让 first 指向新结点, 对比一下,双向链表就是多了几道工序而已:当然这里说的是操作非空链表,首先得处理它和原来的头部结点的关系,就是让原头部结点的 prev 指向新结点,然后新结点的 next 指向原头部结点,最后再处理新结点个体的位置问题,那就是让 first 去指向它。这样就将新的结点插入到你的链表中去了,其实空的是一样的,他没有原头结点的关系处理,只是自己的位置问题要处理,其实就是让 first、last 指向自己,然后自己的 prev、next 都为空就行。

!!!作者小白一个如有有幸被某个大佬看到,并且发现问题一定要告诉我,感激不尽!!!

阅读全文
0 0