链表学习(Leetcode--初级算法)

链表的优缺点

优点:

  • 可以充分利用碎片化存储空间,不用像数组那样必须占用一片连续的空间,方便随时插入,只需改变前后结点(如果是双向链表)的指针域即可,不用移动大量数据。

缺点:

  • 查询第一个元素和最后一个元素的时间不同,必须从头结点进入,遍历其前所有节点,若链表很长,则查询速度将远低于数组类型。

基本概念

结点:数据元素的存储映像。由 数据域+指针域构成。

单链表:数据域+1个指针域

双链表:数据域+2个指针域(一个指向前继结点,一个指向后继结点)

循环链表:首尾相接的链表

头指针:通常使用“头指针”来标识一个链表,如单链表L,头指针为NULL的时表示一个空链表。

头结点:在单链表的第一个结点之前附加一个结点,称为头结点。头结点的Data域可以不设任何信息,也可以记录表长等相关信息。但头结点本身不在链表长度统计范围之内

[注意]无论是否有头结点,头指针始终指向链表的第一个结点。如果有头结点,头指针就指向头结点。

头结点的好处:

单链表的定义

 

//定义顺序链表
struct ListNode
{
    int val;
    ListNode *next;
};

创建顺序链表(头插法--有头结点)

void creatList_H_is_H(ListNode *&head, int length)
{
    head = new ListNode;
    head->next = NULL;
    for (int i = 0; i < length; i++)
    {
        ListNode *p = new ListNode;
        cout << "请输入val: ";
        cin >> p->val;
        p->next = head->next;
        head->next = p;
    }
}

创建顺序链表(头插法--无头结点)

void creatList_H_not_H(ListNode *&head, int length)
{
    head = new ListNode;
    head->next = NULL;
    for (int i = 0; i < length; i++)
    {
        ListNode *p = new ListNode;
        cout << "请输入val: ";
        cin >> p->val;
        p->next = head->next;
        head->next = p;
    }
    head = head->next;//只用在返回时返回其头结点的后继节点的地址即可
}

创建顺序链表(尾插法)

void creatList_R(ListNode *&head, int length)
{
    head = new ListNode;
    head->next = NULL;
    ListNode *r = head;
    for (int i = 0; i < length; i++)
    {
        ListNode *p = new ListNode;
        cout << "请输入val: ";
        cin >> p->val;
        p->next = NULL;
        r->next = p;
        r = p;
    }
}

显示顺序链表(有头结点)

void displayList_is_H(ListNode *head)
{
    cout << "遍历该链表为:" << endl;
    ListNode *p = head->next;//只需使第一个输出的结点由头结点指向首元结点即可
    ;
    while (p != NULL)
    {
        cout << p->val << "  ";
        p = p->next;
    }
    cout << endl;
}

显示顺序链表(无头结点)

void displayList_not_H(ListNode *head)
{
    cout << "遍历该链表为:" << endl;
    ListNode *p = head;//直接输出即可,不用后移
    
    while (p != NULL)
    {
        cout << p->val << "  ";
        p = p->next;
    }
    cout << endl;
}

求链表长度(有头结点)

int get_ListLength_is_H(ListNode *head)
{
    int i = 0;
    ListNode *p = head->next;
    while (p != NULL)
    {
        i++;
        p = p->next;
    }
    return i;
}

求链表长度(无头结点)

int get_ListLength_not_H(ListNode *head)
{
    int i = 0;
    ListNode *p = head;
    while (p != NULL)
    {
        i++;
        p = p->next;
    }
    return i;
}

删除倒数第n个结点

ListNode *removeNthFromEnd(ListNode *head, int n)
{
    ListNode *dummy = new ListNode; //定义头指针,这样头结点也有前驱节点,这样也可以删除头结点
    dummy->next = head;             //头指针连接头结点
    int length = get_ListLength_is_H(head);
    int i = 0;
    ListNode *p = dummy;
    while (i < length - n + 1)//将p定位到删除结点的前一个结点  
                                //如果是正数删除,则括号判断内容需要改变
    {

        p = p->next;
        ++i;
    }

    ListNode *q = p->next;
    p->next = q->next;
    ListNode *ans = dummy->next;
    delete q;
    delete dummy;

    return ans;
}

反转链表(无头结点)

ListNode *reverseList_not_H(ListNode *head)
{
    ListNode *L = new ListNode; //新链表的头结点
    L->next = NULL; 
    //采用头插法
    while (head != NULL)
    {
        ListNode *q = new ListNode;
        q->val = head->val;
        q->next = L->next;
        L->next = q;
        head = head->next;
    }
    return L->next;
}

合并两个有序链表

ListNode *mergeTwoLists_not_H(ListNode *list1, ListNode *list2)
{
    // ListNode *p1 = list1; //指向list1第一个元素
    // ListNode *p2 = list2; //指向list2第一个元素
    ListNode *p3 = new ListNode;
    p3->next = NULL; //初始化p3结点
    ListNode *p = p3;
    while (list1 != NULL && list2 != NULL)
    {
        if (list1->val <= list2->val)
        {
            p->next = list1;
            list2 = list1->next;
        }
        else
        {
            p->next = list2;
            list1 = list2->next;
        }
        p = p->next;
    }

    p->next = (list1 == NULL) ? list2 : list1;
    return p3->next;
}

环形链表

//利用数组查找迅速的特性查找环形链表
bool hasCycle(ListNode *head)
{
    if (head == NULL)
        return false;       //防止是空链表,提高代码健壮性
    vector<ListNode *> tmp; //构建动态数组
    tmp.push_back(head);
    vector<ListNode *>::iterator it;
    while (head->next != NULL)
    {

        it = find(tmp.begin(), tmp.end(), head->next);
        if (it != tmp.end()) //如果在数组当中找到,则实现环链表
        {
            return true;
        }
        else
        {
            head = head->next;
        }
        tmp.push_back(head);
    }
    //如果执行到这一步,说明到达链尾并且没有回环
    return false;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值