数据结构和算法03 之链表

简介:

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

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

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

    单链表:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  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
  在CODE上查看代码片 派生到我的代码片
  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

目录
相关文章
|
2月前
|
存储 人工智能 算法
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
这篇文章详细介绍了Dijkstra和Floyd算法,这两种算法分别用于解决单源和多源最短路径问题,并且提供了Java语言的实现代码。
84 3
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
|
2月前
|
算法 索引
❤️算法笔记❤️-(每日一刷-141、环形链表)
❤️算法笔记❤️-(每日一刷-141、环形链表)
50 0
|
6天前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
28 5
|
29天前
|
存储 C语言
【数据结构】手把手教你单链表(c语言)(附源码)
本文介绍了单链表的基本概念、结构定义及其实现方法。单链表是一种内存地址不连续但逻辑顺序连续的数据结构,每个节点包含数据域和指针域。文章详细讲解了单链表的常见操作,如头插、尾插、头删、尾删、查找、指定位置插入和删除等,并提供了完整的C语言代码示例。通过学习单链表,可以更好地理解数据结构的底层逻辑,提高编程能力。
55 4
|
1月前
|
算法 安全 搜索推荐
2024重生之回溯数据结构与算法系列学习之单双链表精题详解(9)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第2.3章之IKUN和I原达人之数据结构与算法系列学习x单双链表精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
1月前
|
存储 Web App开发 算法
2024重生之回溯数据结构与算法系列学习之单双链表【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构之单双链表按位、值查找;[前后]插入;删除指定节点;求表长、静态链表等代码及具体思路详解步骤;举例说明、注意点及常见报错问题所对应的解决方法
|
2月前
|
存储 算法 Java
Set接口及其主要实现类(如HashSet、TreeSet)如何通过特定数据结构和算法确保元素唯一性
Java Set因其“无重复”特性在集合框架中独树一帜。本文解析了Set接口及其主要实现类(如HashSet、TreeSet)如何通过特定数据结构和算法确保元素唯一性,并提供了最佳实践建议,包括选择合适的Set实现类和正确实现自定义对象的hashCode()与equals()方法。
36 4
|
2月前
|
存储 缓存 算法
经典算法之链表篇(三)
经典算法之链表篇(三)
|
2月前
|
算法
经典算法之链表篇(二)
经典算法之链表篇(二)
|
2月前
|
算法 索引
经典算法之链表篇
经典算法之链表篇