图示来源:王道考研
链表
对于顺序表可以随机存取表中任一元素,但是插入和删除需要移动大量元素,而通过链表存储线性表时,不需要使用地址连续的存储单元,插入和删除不需要移动元素,而只需修改指针,但也失去了顺序表可随机存取的优点。
定义方法
struct Node {
int data;
Node* next;
}node ,*head;
一.初始化
这里使用有头结点的链表
void init(Node* &head) {
head = (Node*)malloc(sizeof(Node));
head->next = NULL;
}
malloc 主要的作用是开辟一块 Node 类型的内存,然后将地址返回回来。
二.建立
2.1 头插法
特点:逆序
void head_insert(Node* &head) {
int x;
scanf("%d",&x);
while(x!=-1) {
Node* temp = (Node*)malloc(sizeof(Node));
temp->data = x;
temp->next = head->next;
head->next = temp;
scanf("%d",&x);
}
}
2.2 尾插法
特点:顺序
void tail_insert(Node* &head) {
int x;
Node* L=head;
scanf("%d",&x);
while(x!=-1) {
Node* temp = (Node*)malloc(sizeof(Node));
temp->data = x;
temp->next = NULL;
L->next = temp;
L = L->next;
scanf("%d",&x);
}
}
三.遍历
void output(Node* head) {
Node *temp = head->next;
while(temp!=NULL) {
printf("%d",temp->data);
temp = temp->next;
}
}
四.链表合并
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
ListNode* p=list1;
ListNode* q=list2;
ListNode* head=(ListNode*)malloc(sizeof(ListNode));
ListNode* L=head;
while(p!=NULL&&q!=NULL)
{
if(p->val <= q->val)
{
L->next=p;
p=p->next;
}
else
{
L->next=q;
q=q->next;
}
L=L->next;
}
L->next= p == NULL ? q:p;
return head->next;
}
五.环形链表
判断链表是否有环,采用方法:快慢指针,先定义一个快指针,再定义一个慢指针, 快指针一次走两步,慢指针一次走一步,如果两个指针最终相遇,则证明存在环。
class Solution {
public:
bool hasCycle(ListNode *head) {
if(head==nullptr || head->next==nullptr){
return false;
}
ListNode* slow=head;
ListNode* fast=head->next;
while(slow!=fast){
if(fast==nullptr || fast->next==nullptr)
{
return false;
}
slow=slow->next;
fast=fast->next->next;
}
return true;
}
};