文章目录
前言
链表部分就是线性表的重点部分,是线性表的链式存储结构的实现,不需像顺序表一样使用大量连续的空间。
一、单链表
1.单链表的结构
typedef struct LNode{
int data;
struct LNode *next; //尾指针
}LNode, *LinkList; //用指针来表示一个单链表
2.初始化
带头结点的单链表的初始化的过程:创建链表指针的头结点,并创建、初始化和连接每个结点。
bool InitList(LinkList &L, int n){
L = (LinkList )malloc(sizeof(LNode));
if(!L) return false;
L->next = NULL; //带头结点的初始化,不带头结点的只需L = NULL
//以下实际是完成链表的插入:头插法(逆序插入)和尾插法(顺序插入),
//头插法是指每个结点插入L后,尾插法是每个结点插入尾指针后,再移动尾指针到最后,即这个结点处
LinkList p = L; //初始化尾指针
while(n--){
LinkList m = (LinkList )malloc(sizeof(LNode));
if(!m) return false;
scanf("%d", &m->data); //输入
m->next = p->next;
p->next = m;
p = m;
}
return true;
}
3.插入
找插入的前一个位置,若只能找到后一个位置的,可以新建一个结点,将两者的值调换,实现插入。
按位插入:
bool InsertList(LinkList &L, int i, Data e){
if( i < 1) return false;
LinkList p = L;
int j = 0;
while( p && j < i-1){ //找到i-1的结点
p = p->next;
j++;
}
if(!p) return false;
LinkList q =(LinkList )malloc(sizeof(LNode));
if(!q) return false;
q->s = e;
q->next = p->next;
p->next = q;
return true;
}
指定节点位置前后插入:
bool PriorLNode(LinkList &p, Data e){
LinkList q = (LinkList )malloc(sizeof(LNode));
if(!q) return false;
q->s = p->s;
p->s = e;
q->next = p->next;
p->next =q;
return true;
}
bool NextLNode(LinkList &p, Data e){
LinkList q = (LinkList )malloc(sizeof(LNode));
if(!q) return false;
q->s = e;
q->next = p->next;
p->next = q;
return true;
}
4.删除
按位删除:
bool DeleteList(LinkList &L, int i, Data &e){
if( i < 1 ) return false;
LinkList p = L;
int j = 0;
while( p && j < i-1 ){
p = p->next;
j++;
}
if(!p) return false;
e = p->next->s;
p->next = p->next->next;
free(p->next);
return true;
}
5.查询
简单略过
二、链表的问题
链表的问题大多是伴随着多指针的运用,这里也顺便总结一下双指针的用法。
1.链表的合并(归并排序merge过程)
//两递减链表,合并保留生成第三个递增的链表
int Merge(LinkList &La, LinkList &Lb, LinkList &Lc){
LinkList pa = La->next;
LinkList pb = Lb->next;
Lc = (LinkList )malloc(sizeof(LNode));
if(!Lc)
return false;
Lc->next = NULL;
int cns = 0;
//由于要求递增有序,原两个链表是递减的,
//就不需尾插法的尾指针,直接使用头结节的头插法
while(pa && pb){
LinkList pc = (LinkList )malloc(sizeof(LNode));
if(!pc) return false;
if(pa->val > pb->val){
pc->val = pa->val;
pa = pa->next;
}else if(pa->val < pb->val){
pc->val = pb->val;
pb = pb->next;
}else{
pc->val = pa->val;
pa = pa->next;
pb = pb->next;
}
cns++;
pc->next = Lc->next;
Lc->next = pc;
}
if(pb) pa = pb;
while(pa){
LinkList pc = (LinkList )malloc(sizeof(LNode));
if(!pc) return false;
pc->val = pa->val;
pc->next = Lc->next;
Lc->next = pc;
pa = pa->next;
cns++;
}
return true;
}
2.链表的逆置
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* ReverseList(ListNode* pHead){
if(!pHead || !pHead->next)
return pHead;
ListNode *pre = NULL;
ListNode *p = pHead;
ListNode *next = NULL;
while(p){
next = p->next;
p->next = pre;
pre = p;
p = next;
}
return pre;
}
};
3.链表是否有环——块慢指针法
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
if(head == NULL || head->next == NULL)
return false;
ListNode *fast,*slow;
fast = slow = head;
while(fast != NULL&& fast->next != NULL){
fast = fast->next->next;
slow = slow->next;
if(slow == fast)
return true;
}
return false;
}
};
4.双指针汇总问题
1.首尾双指针:排序数组查找目标等于两数之和的两个元素
2.同向指针:快慢指针问题,滑动窗口的问题
3.反向指针:最长回文子串
4.分离双指针:合并有序数组
总结
未完待续