链表

链表的定义

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,每个结点包括两个部分:一个是存储数据元素的数据域,一个是存储下一个节点地址的指针域。
由于不必按照顺序存储,链表在插入的时候可以达到O(1)的复杂度,但是查找的时候则需要O(n)的时间复杂度,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)

分类

单向链表

单链表是链表中结构最简单的。一个单链表的节点(Node)分为两个部分,第一个部分(data)保存或者显示关于节点的信息,另一个部分存储下一个节点的地址。最后一个节点存储地址的部分指向空值。


单链表.png

新增节点.png

删除节点

代码实现

class SingleLinkedList {
    private var size:Int = 0
    private var head: Node? = null//头节点
    val isEmpty:Boolean//判断链表是否为空
    get() = size==0

    init {
        size=0
        head=null
    }

    class Node(var data:Any){//每个节点数据
        var next:Node?=null//每个节点指向的下一个节点地址
    }

    //在表头添加元素
    fun addHead(obj:Any):Any{
        var newHead=Node(obj)
        if(size==0){
            head=newHead
        }else{
            newHead.next=head
            head=newHead
        }
        size++
        return obj
    }

    //在链表头删除元素
    fun deleteHead():Any{
        val obj=head!!.data
        head=head!!.next
        size--
        return obj
    }

    //查找指定元素,找到了返回节点Node,找不到返回null
    fun find(obj:Any):Node?{
        var current=head
        var tempSize=size
        while (tempSize>0){
            if(obj==current!!.data){
                return current
            }else{
                current=current.next
            }
            tempSize--
        }
        return null
    }

    //删除指定元素,删除成功返回true
    fun delete(value: Any):Boolean{
        if(size==0){
            return false
        }
        var current=head
        var previous=head
        while (current!!.data!=value){
            if(current.next==null){
                return false
            }else{
                previous=current
                current=current.next
            }
        }

        if(current==head){//如果删除的节点是第一个节点
            head= current.next
            size--
        }else{
            previous!!.next=current.next
            size--
        }
        return true
    }

    //显示节点信息
    fun display():String{
        if(size>0){
            var node=head
            var tempSize=size
            var str=StringBuffer()
            if(tempSize==1){//当前链表只有一个节点
                return "["+node!!.data+"]"
            }
            while (tempSize>0){
                if(node==head){//第一个元素
                    str.append("[").append(node!!.data).append("->")
                }else if(node!!.next==null){//最后一个元素
                    str.append(node.data).append("]")
                }else{
                   str.append(node.data).append("->")
                }
                node=node.next
                tempSize--
            }
            return str.toString()
        }else{
            return "[]"
        }
    }
}

具体的调用方法

override fun onClick(v: View?) {
        when(v!!.id){
            R.id.tvAdd->{//添加
                singleList.addHead("A")
                singleList.addHead("B")
                singleList.addHead("C")
                singleList.addHead("D")
            }
            R.id.tvFind->{//查找
                tvResult.text="结果:"+singleList.find("B")!!.data
                singleList.find("C")
            }
            R.id.tvDisplay->{//展示
                tvResult.text="结果:"+singleList.display()
            }
            R.id.tvDelete->{//删除
                singleList.delete("B")
            }
        }
    }

双端链表

双端链表与单链表十分相似,不同的是它新增一个对尾结点的引用。双端链表不是双向链表


双端链表
class DoublePointLinkedList {
    private var head:Node?=null//头节点
    private var tail:Node?=null//尾节点
    var size:Int=0//链表节点数
    private set
    val isEmpty:Boolean
    get() = size==0

    class Node(var data:Any){
        var next:Node?=null
    }

    init {
        size=0
        head=null
        tail=null
    }

    //链表头新增节点
    fun addHead(data:Any){
        val node=Node(data)
        if(size==0){//如果链表为空,那么头节点和尾节点都是该新增节点
            head=node
            tail=node
            size++
        }else{
            node.next=head
            head=node
            size++
        }
    }

    //链表尾新增节点
    fun addTail(data:Any){
        val node=Node(data)
        if(size==0){//如果链表为空,那么头节点和尾节点都是该新增节点
            head=node
            tail=node
            size++
        }else{
            tail!!.next =node
            tail=node
            size++
        }
    }

    //删除头部节点,成功返回true,失败返回false
    fun deleteHead():Boolean{
        if(size==0){
            return false
        }
        if (head!!.next==null){//当前链表节点数为1
            head=null
            tail=null
        }else{
            head=head!!.next
        }
        size--
        return true
    }

    //显示节点信息
    fun display():String{
        var str=StringBuffer()
        if(size>0){
            var node=head
            var tempSize=size
            if(tempSize==1){//当前链表只有一个节点
                str.append("[").append(node!!.data.toString()).append("]")
                return str.toString()
            }
            while (tempSize>0){
                if(node==head){
                    str.append("[").append(node!!.data.toString()).append("->")
                }else if(node!!.next==null){
                    str.append(node!!.data.toString()).append("]")
                }else{
                    str.append(node!!.data.toString()).append("->")
                }
                node=node.next
                tempSize--
            }
        }else{
            str.append("[]")
        }
        return str.toString()
    }
}

具体调用就不写了,和上面差不多

双向链表

双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表

双向链表

具体代码实现:

class TwoWayLinkedList{

    private var head:Node?=null
    private var tail:Node?=null
    var size:Int=0//获得链表的节点个数
    private set
    val isEmpty:Boolean//判断链表是否为空
    get() = size==0

    class Node(val data:Any){
        var next:Node?=null
        var prev:Node?=null
    }

    init {
        head=null
        tail=null
        size=0
    }

    //在链表头增加节点
    fun addHead(data:Any){
        val newNode=Node(data)
        if(size==0){
            head=newNode
            tail=newNode
            size++
        }else{
            head!!.prev=newNode
            newNode.next=head
            head=newNode
            size++
        }
    }

    //在链表尾增加节点
    fun addTail(data:Any){
        val newNode=Node(data)
        if(size==0){
            head=newNode
            tail=newNode
            size++
        }else{
            newNode.prev=tail
            tail!!.next=newNode
            tail=newNode
            size++
        }
    }

    //删除链表头
    fun deleteHead(): Node? {
        val temp=head
        if(size!=0){
            head=head!!.next
            head!!.prev=null
            size--
        }
        return temp
    }

    //删除链表尾
    fun deleteTail():Node?{
        val temp=tail
        if(size!=0) {
            tail=tail!!.prev
            tail!!.next=null
            size--
        }
        return temp
    }

    //显示节点信息
    fun display():String{
        var str=StringBuffer()
        if(size>0){
            var node=head
            var tempSize=size
            if(tempSize==1){
                str.append("[").append(node!!.data).append("]")
                return str.toString()
            }
            while (tempSize>0){
                if(node==head){
                    str.append("[").append(node!!.data.toString()).append("->")
                }else if(node!!.next==null){
                    str.append(node!!.data.toString()).append("]")
                }else{
                    str.append(node!!.data.toString()).append("->")
                }
                node=node.next
                tempSize--
            }
        }else{
            str.append("[]")
        }
        return str.toString()
    }
}

典型案例:

1.合并两个有序链表(LeetCode第21题)

将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

class Solution {

    ListNode(var `val`: Int) {
        var next: ListNode? = null
    }

    fun mergeTwoLists(l1: ListNode?, l2: ListNode?): ListNode? {
        var mL1=l1
        var mL2=l2
        if (mL1==null){//判断l1是否为空,如果为空,返回l2
            return l2
        }else if(mL2==null){//判断l2是否为空,如果为空,返回l1
            return l1
        }else if(mL1.`val`<mL2.`val`){//判断l1和l2哪个头元素更小
            mL1.next=mergeTwoLists(mL1.next,mL2)
            return mL1
        }else{
            mL2.next=mergeTwoLists(mL2.next,mL1)
            return mL2
        }
    }
}
2.回文链表(LeetCode第234题)

请判断一个链表是否为回文链表
示例 1:
输入: 1->2
输出: false
示例 2:
输入: 1->2->2->1
输出: true
题解:双指针
定义两个指针,fast指针每次走两步,slow指针每次走一步
fast指针走到链表末尾的时候,slow指针走到链表的中间位置结点(链表长度n为偶数)或中间位置的前一个结点(链表长度n为奇数)

fun isPalindrome(head: ListNode?): Boolean {
        //双指针
        var mHead=head
        if(mHead==null || mHead!!.next==null){//判断是否为空
            return true
        }
        //定义两个指针,fast指针每次走两步,slow指针每次走一步
        var fast=mHead.next!!.next
        var slow=mHead.next
        while (fast?.next != null){
            fast= fast.next!!.next
            slow=slow!!.next
        }
       //翻转链表前半部分(以slow为界)
        var pre:ListNode?=null
        var next:ListNode?=null
        while (mHead!=slow){
            next=mHead!!.next
            mHead.next=pre
            pre=mHead
            mHead=next
        }
        //如果是奇数个节点,去掉后半部分的第一个节点
        if(fast!=null){
            slow=slow.next
        }
        //回文校验
        while (pre!=null){
            if(pre.`val`!=slow!!.`val`){
                return false
            }
            pre= pre.next
            slow=slow.next
        }
        return true
    }

参考:
http://www.cnblogs.com/ysocean/

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

推荐阅读更多精彩内容