数据结构(四) 链表

版权声明:转载请附上文章地址https://blog.csdn.net/qq_42672839

什么是链表结构:

  链表结构是由许多节点构成的,每个节点都包含两部分:

  1.   数据部分:保存该节点的实际数据。
  2.   地址部分:保存的是下一个节点的地址。

链表的特点:

结点在存储器中的位置是任意的,即逻辑上相邻的数 据元素在物理上不一定相邻
访问时只能通过头指针进入链表,并通过每个结点的 指针域向后扫描其余结点,所以寻找第一个结点和最后一 个结点所花费的时间不等


链表的优点:

数据元素的个数可以自由扩充 、插入、删除等操作不必移动数据,只需 修改链接指针,修改效率较

链表的缺点:

存储密度小 、存取效率不高,必须采用顺序存取,即存 取数据元素时,只能按链表的顺序进行访问 

 

链表的类型有多种:单链表,双链表,有序链表

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。

 

链表与数组比较:

优点:链表不需要确定长度大小,也不需要连续的内存空间,

缺点:由于不是连续的空间,所以查找元素比较吃力;相比数组只存储元素,链表的元素还要存储其它元素的地址,内存开销相对增大。

 

单链表:

java代码实现如下:

public class LinkedListDemo1 { //表示整个链表对象

    private Node first;        //链表对象的第一个引用
    
    public LinkedListDemo1(){
        
    }
    
    
    public Node getFirst() {
        return first;
    }


    public void setFirst(Node first) {
        this.first = first;
    }


    class Node{              //节点对象
         Item item;          //存储的数据对象
         Node next;          //下一个节点对象的引用
        public Item getItem() {
            return item;
        }
        public void setItem(Item item) {
            this.item = item;
        }
        public Node getNext() {
            return next;
        }
        public void setNext(Node next) {
            this.next = next;
        }
        
        
    }
}

c语言

单向链表的节点包括:

  1. 数据域:用于存储数据元素的值。
  2. 指针域(链域):用于存储下一个结点地址或者说指向其直接后继结点的指针。

struct Node{
     int value;
     Node * next;
 };

1.2双向链表

双向链表的节点包括:

  1. 数据域:用于存储数据元素的值。
  2. 左指针域(左链域):用于存储上一个结点地址或者说指向其直接前继结点的指针。
  3. 右指针域(右链域):用于存储下一个结点地址或者说指向其直接后继结点的指针。

struct DNode{
     int value;
     DNode * left;
     DNode * right;
 };

1.3翻转链表

题意即为将链表反过来,即,原本为p1-p2-p3翻转为p3-p2-p1。读者需自行画图体会指针操作。

//翻转链表
Node * reverseLinkedList(Node* head,int k){
    Node *reversedHead = NULL;
    Node *pNode = head;
    Node *pre = NULL;
    while (pNode!=NULL) {
        if (pNode->next==NULL) {
            reversedHead = pNode;
        }
        Node* nxt = pNode->next;
        pNode->next = pre;
        pre=pNode;
        pNode=nxt;
    }
    return reversedHead;
}

1.4判断链表是否有环路,获取连接点,计算环的长度

判断是否含有环:slow和fast,slow指针每次走一步,fast指针每次走两步,若是链表有环,fast必能追上slow(相撞),若fast走到NULL,则不含有环。

//判断是否含有环
bool containLoop(Node* head){
    if (head==NULL) {
        return false;
    }
    Node* slow = head;
    Node* fast = head;
    while (slow!=fast&&fast->next!=NULL) {
        slow = slow->next;
        fast = fast->next->next;
    }
    if (fast==NULL) {
        return false;
    }
    return true;
}

判断环的长度:在相撞点处,slow和fast继续走,当再次相撞时,slow走了length步,fast走了2*length步,length即为环得长度。

//获得环的长度
int getLoopLength(Node* head){
    if (head==NULL) {
        return 0;
    }
    Node* slow = head;
    Node* fast = head;
    while (slow!=fast&&fast->next!=NULL) {
        slow = slow->next;
        fast = fast->next->next;
    }
    if (fast==NULL) {
        return 0;
    }
    //slow和fast首次相遇后,slow和fast继续走
    //再次相遇时,即slow走了一圈,fast走了两圈
    int length = 0;
    while (slow!=fast) {
        length++;
        slow = slow->next;
        fast = fast->next->next;
    }
    return length;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值