数据结构和算法03 之链表

在第一章的数组中,我们看到数组作为数据存储结构有一定的缺陷。在无序数组中,搜索时低效的;而在有序数组中,插入效率又很低;不管在哪一种数组中删除效率都很低。况且一个数组创建后,它的大小是无法改变的。

        在本章中,我们将讨论下链表这个数据结构,它可以解决上面的一些问题。链表可能是继数组之后第二种使用得最广泛的通用数据结构了。本章主要讨论单链表和双向链表。

        顾名思义,单链表只能从表头到表尾的顺序,每个节点中保存了指向下一个节点的指针;双向链表则可以反向遍历,因为节点中既保存了向后节点的指针,又保存了向前节点的指针。由于链表结构相对简单,这里不再赘述,直接通过程序来查看它们常见的操作:

    单链表:

[java] view plain copy

 

  1. public class LinkedList {  
  2.     private Link first;  
  3.     private int nElem; //链表中节点数量  
  4.     public LinkedList() {  
  5.         first = null;  
  6.         nElem = 0;  
  7.     }  
  8.       
  9.     public void insertFirst(int value) {//添加头结点  
  10.         Link newLink = new Link(value);  
  11.         newLink.next = first; //newLink-->old first  
  12.         first = newLink; //first-->newLink  
  13.         nElem ++;  
  14.     }  
  15.       
  16.     public Link deleteFirst() { //删除头结点  
  17.         if(isEmpty()) {  
  18.             System.out.println("链表为空!");  
  19.             return null;  
  20.         }  
  21.         Link temp = first;  
  22.         first = first.next;  
  23.         nElem --;  
  24.         return temp;  
  25.     }  
  26.   
  27.     /************************************************************ 
  28.      ***下面是有序链表的插入*** 
  29.      ***这样简单排序就可以用链表来实现,复杂度为O(N) 
  30.      ***定义一个方法,传入一个数组, 
  31.      ***在方法内,遍历数组并调用insert方法就可以将数组中的数据排好序 
  32.      ***********************************************************/  
  33.     public void insert(int value) {  
  34.         Link newLink = new Link(value);  
  35.         Link previous = null;  
  36.         Link current = first;  
  37.         while(current != null && value > current.data) {  
  38.             previous = current;  
  39.             current = current.next;  
  40.         }  
  41.         if(previous == null) {  
  42.             first = newLink;          
  43.         }  
  44.         else {  
  45.             previous.next = newLink;  
  46.         }  
  47.         newLink.next = current;  
  48.         nElem ++;  
  49.     }  
  50.       
  51.     public Link find(int value) { //查找特定的节点  
  52.         Link current = first;  
  53.         while(current.data != value) {  
  54.             if(current.next == null)   
  55.                 return null;  
  56.             else  
  57.                 current = current.next;  
  58.         }     
  59.         return current;  
  60.     }  
  61.       
  62.     public Link delete(int value) { //删除特定的节点  
  63.         Link current = first;  
  64.         Link previous = first;  
  65.         while(current.data != value) {  
  66.             if(current.next == null) {  
  67.                 return null;  
  68.             }  
  69.             previous = current;  
  70.             current = current.next;  
  71.         }  
  72.         if(current == first) {  
  73.             first = first.next;  
  74.         }  
  75.         else {  
  76.             previous.next = current.next;  
  77.         }  
  78.         nElem --;  
  79.         return current;  
  80.     }  
  81.       
  82.     public void displayList() {  
  83.         if(isEmpty()){  
  84.             System.out.println("链表为空!");  
  85.             return;  
  86.         }  
  87.         Link current = first;  
  88.         while(current != null) {  
  89.             current.displayLink();  
  90.             current = current.next;  
  91.         }  
  92.         System.out.println(" ");  
  93.     }  
  94.       
  95.     public boolean isEmpty() {  
  96.         return (first == null);  
  97.     }  
  98.       
  99.     public int size() {  
  100.         return nElem;  
  101.     }  
  102. }  
  103.   
  104. class Link {  
  105.     public int data;  
  106.     public Link next;  
  107.       
  108.     public Link(int data) {  
  109.         this.data = data;  
  110.         this.next = null;  
  111.     }  
  112.       
  113.     public void displayLink() {  
  114.         System.out.print("{" + data + "} ");  
  115.     }  
  116. }  

    双向链表:

[java] view plain copy

 

  1. public class DoublyLinkedList {  
  2.     private Node first; //头节点  
  3.     private Node last; //尾节点  
  4.     private int size;  
  5.       
  6.     public DoublyLinkedList() {  
  7.         first = null;  
  8.         last = null;  
  9.         size = 0;  
  10.     }  
  11.       
  12.     public int size() {  
  13.         return size;  
  14.     }  
  15.       
  16.     public boolean isEmpty() {  
  17.         return (first == null);  
  18.     }  
  19.       
  20.     public void insertFirst(long value) { //插入头节点  
  21.         Node newLink = new Node(value);  
  22.         if(isEmpty()) {  
  23.             last = newLink;  
  24.         }  
  25.         else{  
  26.             first.previous = newLink; //newLink <-- oldFirst.previous  
  27.             newLink.next = first; //newLink.next --> first  
  28.         }   
  29.         first = newLink; //first --> newLink  
  30.         size ++;  
  31.     }  
  32.       
  33.     public void insertLast(long value) {//插入尾节点  
  34.         Node newLink = new Node(value);  
  35.         if(isEmpty()){  
  36.             first = newLink;  
  37.         }  
  38.         else {  
  39.             last.next = newLink; //newLink <-- oldLast.next  
  40.             newLink.previous = last; //newLink.previous --> last  
  41.         }  
  42.         last = newLink;  
  43.         size ++;  
  44.     }  
  45.       
  46.     public Node deleteFirst() {//删除头结点  
  47.         if(first == null) {  
  48.             System.out.println("链表为空!");  
  49.             return null;  
  50.         }  
  51.         Node temp = first;  
  52.         if(first.next == null) { //只有一个节点  
  53.             last = null;  
  54.         }  
  55.         else {  
  56.             first.next.previous = null;  
  57.         }  
  58.         first = first.next;  
  59.         size --;  
  60.         return temp;  
  61.     }  
  62.       
  63.     public Node deleteLast() {//删除尾节点  
  64.         if(last == null) {  
  65.             System.out.println("链表为空");  
  66.             return null;  
  67.         }  
  68.         Node temp = last;  
  69.         if(last.previous == null) { //只有一个节点  
  70.             first = null;  
  71.         }  
  72.         else {  
  73.             last.previous.next = null;  
  74.         }  
  75.         last = last.previous;  
  76.         size --;  
  77.         return temp;  
  78.     }  
  79.       
  80.     public boolean insertAfter(long key, long value) { //在key后面插入值为value的新节点  
  81.         Node current = first;  
  82.         while(current.data != key) {  
  83.             current = current.next;  
  84.             if(current == null) {  
  85.                 System.out.println("不存在值为" + value + "的节点!");  
  86.                 return false;  
  87.             }  
  88.         }  
  89.         if(current == last) {  
  90.             insertLast(value);  
  91.         }  
  92.         else {  
  93.             Node newLink = new Node(value);  
  94.             newLink.next = current.next;  
  95.             current.next.previous = newLink;  
  96.             newLink.previous = current;  
  97.             current.next = newLink;  
  98.             size ++;  
  99.         }  
  100.         return true;  
  101.     }  
  102.       
  103.     public Node deleteNode(long key) {//删除指定位置的节点  
  104.         Node current = first;  
  105.         while(current.data != key) {  
  106.             current = current.next;  
  107.             if(current == null) {  
  108.                 System.out.println("不存在该节点!");  
  109.                 return null;  
  110.             }  
  111.         }  
  112.         if(current == first) {  
  113.             deleteFirst();  
  114.         }  
  115.         else if(current == last){  
  116.             deleteLast();  
  117.         }  
  118.         else {  
  119.             current.previous.next = current.next;  
  120.             current.next.previous = current.previous;  
  121.             size --;  
  122.         }  
  123.         return current;  
  124.     }  
  125.       
  126.     public void displayForward() { //从头到尾遍历链表  
  127.         System.out.println("List(first --> last): ");  
  128.         Node current = first;  
  129.         while(current != null) {  
  130.             current.displayLink();  
  131.             current = current.next;  
  132.         }  
  133.         System.out.println(" ");  
  134.     }  
  135.       
  136.     public void displayBackward() { //从尾到头遍历链表  
  137.         System.out.println("List(last --> first): ");  
  138.         Node current = last;  
  139.         while(current != null) {  
  140.             current.displayLink();  
  141.             current = current.previous;  
  142.         }  
  143.         System.out.println(" ");  
  144.     }  
  145. }  
  146.   
  147. class Node {  
  148.     public long data;  
  149.     public Node next;  
  150.     public Node previous;  
  151.       
  152.     public Node(long value) {  
  153.         data = value;  
  154.         next = null;  
  155.         previous = null;  
  156.     }  
  157.       
  158.     public void displayLink() {  
  159.         System.out.print(data + " ");  
  160.     }  
  161. }  

        在表头插入和删除速度很快,仅需改变一两个引用值,所以话费O(1)的时间。平均起来,查找、删除和在指定节点后面插入都需要搜索链表中的一半节点,需要O(N)次比较。在数组中执行这些操作也需要O(N)次比较,但是链表仍然要比数组快一些,因为当插入和删除节点时,链表不需要移动任何东西,增加的效率是很显著的,特别是当复制时间远远大于比较时间的时候。

        当然,链表比数组优越的另一个重要方面是链表需要多少内存就可以用多少内存,并且可以扩展到所有可用内存。数组的大小在它创建的时候就固定了,所以经常由于数组太大导致效率低下,或者数组太小导致空间溢出。可变数组可以解决这个问题,但是它经常只允许以固定大小的增量扩展,这个解决方案在内存使用率上来说还是比链表要低。

         链表比较简单,就讨论这么多,如有问题,欢迎留言指正~

转载:http://blog.csdn.net/eson_15/article/details/51136653

时间: 2024-08-30 23:36:19

数据结构和算法03 之链表的相关文章

JavaScript中数据结构与算法(三):链表

  这篇文章主要介绍了JavaScript中数据结构与算法(三):链表,本文分别讲解了单链表与双链表以及增加节和删除节的代码实例,需要的朋友可以参考下 我们可以看到在javascript概念中的队列与栈都是一种特殊的线性表的结构,也是一种比较简单的基于数组的顺序存储结构.由于javascript的解释器针对数组都做了直接的优化,不会存在在很多编程语言中数组固定长度的问题(当数组填满后再添加就比较困难了,包括添加删除,都是需要把数组中所有的元素全部都变换位置的,javascript的的数组确实直接

另类的链表数据结构以及算法

一般情况下,我们使用链表无非就是在链表结点中保存该链表中下一个元素的指针.如果为了删除方便,可能需要保存前一个元素的指针,也就是双向链表,这样在删除一个结点的时候就可以很快的定位到前面和后面的结点,并且改变它们相应的指向.在这些操作里面,指向链表元素的指针无疑是最关键的数据. 考虑这样一个问题,如果两个进程进行通信,A进程负责管理链表,B进程向A进程发出分配或者删除链表元素的请求.这种情况下,像上面所描述的那样A进程直接向B进程返回链表元素的指针是不能做到的了,很自然的,可以想到返回另一个key

Python实现的数据结构与算法之链表详解_python

本文实例讲述了Python实现的数据结构与算法之链表.分享给大家供大家参考.具体分析如下: 一.概述 链表(linked list)是一组数据项的集合,其中每个数据项都是一个节点的一部分,每个节点还包含指向下一个节点的链接. 根据结构的不同,链表可以分为单向链表.单向循环链表.双向链表.双向循环链表等.其中,单向链表和单向循环链表的结构如下图所示: 二.ADT 这里只考虑单向循环链表ADT,其他类型的链表ADT大同小异.单向循环链表ADT(抽象数据类型)一般提供以下接口: ① SinCycLin

基本数据结构和算法在Linux内核中使用

基本数据结构和算法在Linux内核中使用 gaufunga day ago 搬运工 Linux内核(源代码的链接在github). 1.链表.双向链表.无锁链表. 2.B+ 树,这是一些你无法在教科书上找到的说明. 一个相对简单的B+树的实现.我把它作为一个学习练习来帮助理解B+树是如何工作的.这同样也被证明是有用的. ... 一个在教科书中并不常见的技巧.最小的值在右侧而不是在左侧.所有在一个节点里用到的槽都在左侧,所有没有用到的槽包含了空值(NUL).大多数操作只简单地遍历所有的槽一次并在第

C++数据结构与算法专题

快速排序算法的C++实现 详解qsort函数的用法 C++求二个数的最大公约数与最小公倍数实例 小览CallStack(调用栈)(三)-用调试器脚本查看调用栈信息 小览call stack(调用栈) (二)--调用约定 小览call stack(调用栈) (一) C++/CLI中栈对象的设计问题 POJ 1694 C++ (排序) 高效实现Josephus算法 利用堆排序实现学生成绩管理 C++双向循环链表的操作与实现 基于Crtpto++的RSA签名算法 自定义函数使用map排序 C++数据结

JavaScript中数据结构与算法(二):队列

  这篇文章主要介绍了JavaScript中数据结构与算法(二):队列,队列是只允许在一端进行插入操作,另一个进行删除操作的线性表,队列是一种先进先出(First-In-First-Out,FIFO)的数据结构,需要的朋友可以参考下 队列是只允许在一端进行插入操作,另一个进行删除操作的线性表,队列是一种先进先出(First-In-First-Out,FIFO)的数据结构 队列在程序程序设计中用的非常的频繁,因为javascript单线程,所以导致了任何一个时间段只能执行一个任务,而且还参杂了异步

JavaScript数据结构和算法之图和图算法

 这篇文章主要介绍了JavaScript数据结构和算法之图和图算法,本文讲解了有向图.无序图.简单图.图的遍历等内容,需要的朋友可以参考下     图的定义 图(Graph)是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E),其中,G表示一个图,V是图G中顶点的集合,E是图G中边的集合. 有向图 有向边:若从顶点Vi到Vj的边有方向,则称这条边为有向边,也成为弧(Arc),用有序偶<Vi,Vj>来表示,Vi称为弧尾,Vj称为弧头. 无序图 无向边:若顶点Vi到Vj之间的边没

JavaScript数据结构和算法之二叉树详解

 这篇文章主要介绍了JavaScript数据结构和算法之二叉树详解,本文讲解了二叉树的概念.二叉树的特点.二叉树节点的定义.查找最大和最小值等内容,需要的朋友可以参考下     二叉树的概念 二叉树(Binary Tree)是n(n>=0)个结点的有限集合,该集合或者为空集(空二叉树),或者由一个根结点和两棵互不相交的.分别称为根结点的左子树和右子树的二叉树组成. 二叉树的特点 每个结点最多有两棵子树,所以二叉树中不存在度大于2的结点.二叉树中每一个节点都是一个对象,每一个数据节点都有三个指针,

数据结构和算法18 之总结篇

  前面介绍了经典的数据结构和算法,这一节我们对这些数据结构和算法做一个总结,具体细节,请参见各个章节的详细介绍,这里我们用表格来呈现它们的效率. 1. 数据结构部分 数据结构中常用的操作的效率表 通用数据结构 查找  插入   删除 遍历  数组 O(N) O(1) O(N) - 有序数组 O(logN) O(N) O(N) O(N) 链表 O(N) O(1) O(N) - 有序链表 O(N) O(N) O(N) O(N) 二叉树 O(logN) O(logN) O(logN) O(N) 二叉