数据结构与算法之数组与链表

线性表包括数组,链表(单链表,双向链表,循环链表,双向循环链表,静态链表),栈(顺序栈,链式栈),队列(普通队列,双端队列,阻塞队列,并发队列,阻塞并发队列)。

数组

数组(Array)是一种线性表数据结构,它用一组连续的内存空间来存储一组具有相同类型的数据。相信大家对数组都不会陌生,每种编程语言中都会有这种数据类型。数组的下标都是从0开始的,那么数组的下标为什么从 0 开始而不是从 1 开始呢?这里牵扯到内存地址计算的问题,举个例子说明,我们声明一个长度为 10 的整型数组 int[] array = new int[10] ,每一个整型需要4个字节,所以这个数组需要分配40字节的连续的内存空间,我们假设是从1000 - 1039,数组的每一个元素的内存地址是怎么计算的呢,array[i]-address = base-address + i*type-size, 就是元素的地址等于基地址加上元素所占的大小,例如第一个元素的地址应该是该连续内存空间的首地址,即偏移为0,所以说从 0 开始有利于计算机快速计算数据元素的地址。
C#或Java中都有ArrayList,ArrayList封装了数组的一些操作饼支持动态扩展,而数组使用时必须提前指定大小。
数组插入、删除的时间复杂度是O(n)

链表

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。
使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。链表最明显的好处就是,常规数组排列关联项目的方式可能不同于这些数据项目在记忆体或磁盘上顺序,数据的存取往往要在不同的排列顺序中转换。链表允许插入和移除表上任意位置上的节点,但是不允许随机存取。链表有很多种不同的类型:单向链表,双向链表以及循环链表。链表可以在多种编程语言中实现。像Lisp和Scheme这样的语言的内建数据类型中就包含了链表的存取和操作。程序语言或面向对象语言,如C,C++和Java依靠易变工具来生成链表。

下图为单链表结构


单链表

链表中第一个结点的存储位置叫做头指针,头结点的数据域可以不存储任何信息,最后一个节点指针为空NULL

  • 头指针,是指链表指向第一个结点的指针,若链表有头结点,则是指向头结点的指针,头指针具有标识作用,所以常用头指针冠以链表的名字,无论链表是否为空,头指针均不为空,头指针是链表的必要元素
  • 头结点,是为了操作的统一和方便而设立的,放在第一个元素的结点之前,其数据域一般无意义(也可存放链表的长度),有了头结点,对在第一个元素结点前出入结点和删除第一个结点,其操作与其它结点的操作就统一了,头结点不一定是链表的必须要素。
    链表的插入、删除操作的时间复杂度是O(1), 链表随机访问的速度没有数组好,需要O(n) 的时间复杂度。
    下图来源于网络,用动画模式展示了单链表反转的操作步骤


    单链表反转
package dataStructures;
//单链表的一些常见操作(Java)
public class singlyLinkedList {

    private Node head = null;

    public void insertToHead(String value) {
        Node newNode = new Node(value, null);
        insertToHead(newNode);
    }

    public void insertToHead(Node newNode) {
        if (head == null) {
            head = newNode;
        } else {
            newNode.next = head;
            head = newNode;
        }
    }

    public void insertToTail(String value) {
        if (head == null) {
            head = new Node(value, null);
        } else {
            Node lastNode = head.next;
            if (lastNode == null) {
                lastNode = new Node(value, null);
                head.next = lastNode;
            } else {
                while (lastNode.next != null) {
                    lastNode = lastNode.next;
                }
                lastNode.next = new Node(value, null);
            }
        }
    }

    public void insertAfter(Node p, String value) {
        Node newNode = new Node(value, null);
        insertAfter(p, newNode);
    }

    public void insertAfter(Node p, Node newNode) {
        if (p == null) return;
        newNode.next = p.next;
        p.next = newNode;
    }

    public void insertBefore(Node p, String value) {
        Node newNode = new Node(value, null);
        insertBefore(p, newNode);
    }

    public void insertBefore(Node p, Node newNode) {
        if (p == null) return;
        if (head == p) {
            insertToHead(newNode);
            return;
        }
        Node tmpNode = head;
        while (tmpNode != null && tmpNode.next != p) {
            tmpNode = tmpNode.next;
        }
        if (tmpNode == null) return;

        tmpNode.next = newNode;
        newNode.next = p;
    }

    //链表反转
    public void reverse() {
        Node prev = null;
        Node current = head;
        Node nextNode;
        while (current != null) {
            nextNode = current.next;
            current.next = prev;
            prev = current;
            current = nextNode;
        }
        head = prev;
    }

    public Node findByValue(String value) {
        Node tmpNode = head;
        while (tmpNode != null && tmpNode.getData() != value) {
            tmpNode = tmpNode.next;
        }
        return tmpNode;
    }

    public void printAll() {
        Node tmpNode = head;
        while (tmpNode != null) {
            System.out.print(tmpNode.data + " ");
            tmpNode = tmpNode.next;
        }
        System.out.println();
    }

    static class Node {
        private String data;
        private Node next;

        public Node(String data, Node next) {
            this.data = data;
            this.next = next;
        }

        public String getData() {
            return data;
        }
    }

    public static void main(String[] args) {
        singlyLinkedList list = new singlyLinkedList();
        list.head = new Node("Start", null);
        list.insertToTail("First");
        list.insertToTail("Second");
        list.insertToTail("Third");
        list.insertToHead("BeforeHead");
        Node first = list.findByValue("First");
        list.insertBefore(first, "BeforeFirst");
        list.printAll();//输出 BeforeHead Start BeforeFirst First Second Third 
        list.reverse();
        list.printAll();//输出 Third Second First BeforeFirst Start BeforeHead 
    }
}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容