在第一章的数组中,我们看到数组作为数据存储结构有一定的缺陷。在无序数组中,搜索时低效的;而在有序数组中,插入效率又很低;不管在哪一种数组中删除效率都很低。况且一个数组创建后,它的大小是无法改变的。
在本章中,我们将讨论下链表这个数据结构,它可以解决上面的一些问题。链表可能是继数组之后第二种使用得最广泛的通用数据结构了。本章主要讨论单链表和双向链表。
顾名思义,单链表只能从表头到表尾的顺序,每个节点中保存了指向下一个节点的指针;双向链表则可以反向遍历,因为节点中既保存了向后节点的指针,又保存了向前节点的指针。由于链表结构相对简单,这里不再赘述,直接通过程序来查看它们常见的操作:
单链表:
- public class LinkedList {
- private Link first;
- private int nElem; //链表中节点数量
- public LinkedList() {
- first = null;
- nElem = 0;
- }
- public void insertFirst(int value) {//添加头结点
- Link newLink = new Link(value);
- newLink.next = first; //newLink-->old first
- first = newLink; //first-->newLink
- nElem ++;
- }
- public Link deleteFirst() { //删除头结点
- if(isEmpty()) {
- System.out.println("链表为空!");
- return null;
- }
- Link temp = first;
- first = first.next;
- nElem --;
- return temp;
- }
- /************************************************************
- ***下面是有序链表的插入***
- ***这样简单排序就可以用链表来实现,复杂度为O(N)
- ***定义一个方法,传入一个数组,
- ***在方法内,遍历数组并调用insert方法就可以将数组中的数据排好序
- ***********************************************************/
- public void insert(int value) {
- Link newLink = new Link(value);
- Link previous = null;
- Link current = first;
- while(current != null && value > current.data) {
- previous = current;
- current = current.next;
- }
- if(previous == null) {
- first = newLink;
- }
- else {
- previous.next = newLink;
- }
- newLink.next = current;
- nElem ++;
- }
- public Link find(int value) { //查找特定的节点
- Link current = first;
- while(current.data != value) {
- if(current.next == null)
- return null;
- else
- current = current.next;
- }
- return current;
- }
- public Link delete(int value) { //删除特定的节点
- Link current = first;
- Link previous = first;
- while(current.data != value) {
- if(current.next == null) {
- return null;
- }
- previous = current;
- current = current.next;
- }
- if(current == first) {
- first = first.next;
- }
- else {
- previous.next = current.next;
- }
- nElem --;
- return current;
- }
- public void displayList() {
- if(isEmpty()){
- System.out.println("链表为空!");
- return;
- }
- Link current = first;
- while(current != null) {
- current.displayLink();
- current = current.next;
- }
- System.out.println(" ");
- }
- public boolean isEmpty() {
- return (first == null);
- }
- public int size() {
- return nElem;
- }
- }
- class Link {
- public int data;
- public Link next;
- public Link(int data) {
- this.data = data;
- this.next = null;
- }
- public void displayLink() {
- System.out.print("{" + data + "} ");
- }
- }
双向链表:
- public class DoublyLinkedList {
- private Node first; //头节点
- private Node last; //尾节点
- private int size;
- public DoublyLinkedList() {
- first = null;
- last = null;
- size = 0;
- }
- public int size() {
- return size;
- }
- public boolean isEmpty() {
- return (first == null);
- }
- public void insertFirst(long value) { //插入头节点
- Node newLink = new Node(value);
- if(isEmpty()) {
- last = newLink;
- }
- else{
- first.previous = newLink; //newLink <-- oldFirst.previous
- newLink.next = first; //newLink.next --> first
- }
- first = newLink; //first --> newLink
- size ++;
- }
- public void insertLast(long value) {//插入尾节点
- Node newLink = new Node(value);
- if(isEmpty()){
- first = newLink;
- }
- else {
- last.next = newLink; //newLink <-- oldLast.next
- newLink.previous = last; //newLink.previous --> last
- }
- last = newLink;
- size ++;
- }
- public Node deleteFirst() {//删除头结点
- if(first == null) {
- System.out.println("链表为空!");
- return null;
- }
- Node temp = first;
- if(first.next == null) { //只有一个节点
- last = null;
- }
- else {
- first.next.previous = null;
- }
- first = first.next;
- size --;
- return temp;
- }
- public Node deleteLast() {//删除尾节点
- if(last == null) {
- System.out.println("链表为空");
- return null;
- }
- Node temp = last;
- if(last.previous == null) { //只有一个节点
- first = null;
- }
- else {
- last.previous.next = null;
- }
- last = last.previous;
- size --;
- return temp;
- }
- public boolean insertAfter(long key, long value) { //在key后面插入值为value的新节点
- Node current = first;
- while(current.data != key) {
- current = current.next;
- if(current == null) {
- System.out.println("不存在值为" + value + "的节点!");
- return false;
- }
- }
- if(current == last) {
- insertLast(value);
- }
- else {
- Node newLink = new Node(value);
- newLink.next = current.next;
- current.next.previous = newLink;
- newLink.previous = current;
- current.next = newLink;
- size ++;
- }
- return true;
- }
- public Node deleteNode(long key) {//删除指定位置的节点
- Node current = first;
- while(current.data != key) {
- current = current.next;
- if(current == null) {
- System.out.println("不存在该节点!");
- return null;
- }
- }
- if(current == first) {
- deleteFirst();
- }
- else if(current == last){
- deleteLast();
- }
- else {
- current.previous.next = current.next;
- current.next.previous = current.previous;
- size --;
- }
- return current;
- }
- public void displayForward() { //从头到尾遍历链表
- System.out.println("List(first --> last): ");
- Node current = first;
- while(current != null) {
- current.displayLink();
- current = current.next;
- }
- System.out.println(" ");
- }
- public void displayBackward() { //从尾到头遍历链表
- System.out.println("List(last --> first): ");
- Node current = last;
- while(current != null) {
- current.displayLink();
- current = current.previous;
- }
- System.out.println(" ");
- }
- }
- class Node {
- public long data;
- public Node next;
- public Node previous;
- public Node(long value) {
- data = value;
- next = null;
- previous = null;
- }
- public void displayLink() {
- System.out.print(data + " ");
- }
- }
在表头插入和删除速度很快,仅需改变一两个引用值,所以话费O(1)的时间。平均起来,查找、删除和在指定节点后面插入都需要搜索链表中的一半节点,需要O(N)次比较。在数组中执行这些操作也需要O(N)次比较,但是链表仍然要比数组快一些,因为当插入和删除节点时,链表不需要移动任何东西,增加的效率是很显著的,特别是当复制时间远远大于比较时间的时候。
当然,链表比数组优越的另一个重要方面是链表需要多少内存就可以用多少内存,并且可以扩展到所有可用内存。数组的大小在它创建的时候就固定了,所以经常由于数组太大导致效率低下,或者数组太小导致空间溢出。可变数组可以解决这个问题,但是它经常只允许以固定大小的增量扩展,这个解决方案在内存使用率上来说还是比链表要低。
相关推荐
在计算机科学中,数据结构与算法是至关重要的基础,它们直接影响到程序的效率和性能。本次上机实验主要关注的是链表,一种常用的数据结构,它在C++中有着广泛的应用。链表不同于数组,其元素不是连续存储的,而是...
本书主要介绍了 JavaScript 语言的基础知识,包括数据结构和算法。以下是该书的详细知识点: 一、JavaScript 基础知识 * 变量和数据类型 * 运算符和控制结构 * 函数和对象 * 数组和字符串 二、数据结构 * 数组:...
总的来说,C++中的链表数据结构是理解和掌握数据结构和算法的基础,对于编写高效、灵活的代码至关重要。通过深入学习链表,可以更好地理解和运用其他高级数据结构,如树、图等。在实际编程中,合理选择链表和其他...
本项目“C语言实现部分数据结构和算法,包括链表,栈,队列,哈希表,树,排序算法,图算法等等.zip”提供了C语言实现这些基本数据结构和算法的实例,对于学习和理解它们的工作原理非常有帮助。 首先,让我们逐一...
数据结构与算法是计算机科学的基础,对于理解和设计高效的软件至关重要。C语言因其高效、底层特性,常被用于实现数据结构和算法,使得程序更接近硬件,性能更优。本资源"数据结构与算法分析--C语言描述"是针对数据...
数据结构、C语言和算法是计算机科学的基础,也是软件开发中的核心技术。在这些主题中,树、图和链表是尤为关键的数据结构,它们在解决复杂问题时扮演着至关重要的角色。 首先,让我们来深入了解一下数据结构。数据...
双向链表 - 数据结构与算法 C 双向链表 - 数据结构与算法 C 。。。。。。
总的来说,"数据结构之链表合并算法.pdf"这份文档可能详细介绍了链表合并算法的原理、实现方法、性能分析和应用案例,为学习者提供了一套全面的教程。通过深入学习,可以增强对数据结构的理解,提高解决实际问题的...
数据结构-基本算法-静态链表(学生时代源码,调试可运行)
在数据结构和算法领域中,存在大量不同的概念和术语,这些都构成了计算机科学的基础。思维导图是一种有效的方式来组织和回顾这些概念,通过可视化方式帮助记忆和理解。从提供的文件【标题】:"数据结构和算法-思维...
《数据结构与算法分析C++语言描述第四版》是一本深度探讨数据结构和算法的经典教材。这本书由Mark Allen Weiss撰写,旨在帮助读者理解和掌握如何在C++编程环境中有效地设计和实现数据结构及算法。第四版更新了内容,...
《Java数据结构与算法第二版源代码》是一个深入学习Java编程和算法的重要资源,它包含了丰富的实例和程序,旨在帮助开发者提升对数据结构和算法的理解与应用能力。在这个压缩包中,有两个主要的子文件:...
在编程领域,算法和数据结构是核心技术之一,对于学习编程和寻找工作的学生来说,掌握这些概念至关重要。"算法大全-面试题-链表-栈-二叉树-数据结构"这个压缩包文件提供了丰富的知识资源,旨在帮助学习者深入理解和...
总结来说,双链表是一种高效的数据结构,尤其适用于需要频繁进行双向遍历和插入删除操作的场景。通过理解和熟练掌握双链表及其算法,对于提升编程能力,尤其是解决复杂数据处理问题的能力,具有重要意义。
本文将深入探讨Java中常见的数据结构,包括链表、树、图、数组和队列,以及相关的搜索和查找算法。 1. 链表:链表是一种动态数据结构,每个元素称为节点,包含数据和指向下一个节点的引用。在Java中,可以使用`...
数据结构与算法(C#).PDF及代码 第1章 Collections类、泛型类和Timing类概述 第2章 数组和ArrayList 第3章 基础排序算法 ...第15章 用于查找的高级数据结构和算法 第16章 图和图的算法 第17章 高级算法
数据结构与算法是计算机科学的基础,链表作为其中的一个核心概念,对于理解和处理复杂的数据问题至关重要。本节将深入探讨链表的原理、实现细节以及常见的应用。 链表是一种线性数据结构,与数组不同,它不依赖于...
在计算机科学中,链表是一种常用的数据结构,用于存储和管理大量数据。然而,在链表中进行排序操作是一个具有挑战性的任务,因为链表的节点分布在内存中,可能会导致缓存未命中的情况。因此,选择合适的排序算法对于...