链表---详解

本文详细介绍了链表的基础概念,包括头节点的使用、无头链表的实现,以及如何通过快慢指针和哈希表检测循环链表。同时探讨了双向链表的特点和LeetCode中的一道相关问题.

链表

链表不一定由结构体构成,也可能是数与数之间的固定指向
一般来说,有头链表使用时更方便
无头链表 代码演示:
#include <iostream>
#include<map>
#include<ctime>
#include<cstdio>
#include<vector>
#include<cstdlib>
#include<unordered_map>
#include<stack>
using namespace std;
#define DIGIT_LEN 3
typedef struct Node {
       int data;
       Node* next;
}Node;
Node* getNewNode(int val) {
       Node* p = (Node*)malloc(sizeof(Node));
       p->data = val;
       p->next = NULL;
       return p;
}
void clear(Node* head) {
       if (head == NULL) return;
       for (Node* p = head, *q; p; p = q) {
              q = p->next;
              free(p);
       }
       return;
}
Node* insert(Node* head, int pos, int val) {
       if (pos == 0) {
              Node* p = getNewNode(val);
              p->next = head;
              return p;
       }
       Node* p = head;
       for (int i = 0; i < pos - 1; i++) {
              p=p->next;
       }
       Node* node = getNewNode(val);
       node->next = p->next;
       p->next = node;
       return  head;
}
Node* erase(Node* head, int pos) {
       Node* p = head;
       if (pos == 0) {
              head->data = 0;
              head = head->next;
              p->next = NULL;
              return head;
       }
       for (int i = 0; i < pos - 1; i++)
       {
              p = p->next;
       }
       p = p->next->next;
       return head;
}
void output_linklist(Node *head,int flag=0) {
       int  n = 0;
       for (Node* p = head; p; p = p->next) {
              ++n;
       }
       for (int i = 0; i < n; i++) {
              printf("%3d", i);
              printf("  ");
       }
       printf("\n");
       for (Node* p = head; p; p = p->next) {
              printf("%3d", p->data);
              if(p->next)printf("->");
       }
       if (flag == 0)printf("\n\n\n");
       else printf("\n");
       return;
}
int find(Node* head, int val) {
       Node* p = head;
       int n = 0;
       while (p) {
              if (p->data == val)
              {
                      output_linklist(head,1);
                      for (int i = 0; i < n; i++)
                             printf("     ");
                      printf("  ^  \n");
                      for (int i = 0; i < n; i++)
                             printf("     ");
                      printf("  |  \n");
                      return 1;
              }
              n += 1;
              p = p->next;
       }
       return 0;
}
int main()
{
       srand((unsigned int)time(0));
    #define MAX_OP 20
       Node* head = NULL;
       for (int i = 0; i < MAX_OP; i++) {
              int pos = rand() % (i + 1), val = rand() % 100;
              printf("insert %d at %d to linklist\n", val, pos);
              head=insert(head, pos, val);
              output_linklist(head);
       }
       int val;
       while (~scanf_s("%d", &val)) {
              if (!find(head, val)) {
                      printf("not found\n");
              }
       }
       clear(head);
       return 0;
}
有头节点运用于插入--减少了if
Node* insert(Node* head, int pos, int val) {
       Node new_head, * p = &new_head, * node = getNewNode(val);//临时创建头节点
       new_head.next = head;
       for (int i = 0; i < pos; i++) p = p->next;
       node->next = p->next;
       p->next = node;
       return new_head.next;
}
循环链表
特点:
  • 把链表的尾节点当作虚拟头节点
  • 通过快慢指针可以分辨是单向链表还是循环链表
代码:哈希
bool hasCycle(ListNode *head) {
        unordered_map<ListNode*,int> umap;
        ListNode *p=head;
        while(p){
            umap[p]++;
            if(umap[p]==2return true;
            p=p->next;
        }
        return false;
    }
快慢指针
bool hasCycle(ListNode *head) {
    ListNode *fast_ptr=head;
    ListNode *low_ptr=head; 
    while(fast_ptr&&fast_ptr->next){
        low_ptr=low_ptr->next;
        fast_ptr=fast_ptr->next->next; 
        if(low_ptr==fast_ptr) return true;
    } 
    return false;
}
  • 双指针等距移动法:确定链表中的倒数第几位的位置
leetcode:19
双向链表
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值