2020/11/16
前言
注意:在使用下列代码时,若无特别说明,链表都是带头结点的。
typedef struct LNode{
int val;
struct LNode *next;
}LNode;
题目一:使用头插法创建链表
/*
arr:链表数据
head:头指针
*/
LNode* createListByHead(int arr[], LNode *head, int len){
int i; //p为工作指针
LNode *p = NULL; //工作指针
head->next = NULL; //将头结点中的next指针置为空
for(i=0; i<len; ++i){
//创建结点并设置数值域
p = (LNode*)malloc(sizeof(LNode)); //为新结点开辟空间,并将工作指针p指向它
p->val = arr[i];
//头插
p->next = head->next;
head->next = p;
}
return head;
}
题目二:使用尾插法创建链表
/*
arr:链表数据
head:头指针
*/
LNode* createListByTail(int arr[], LNode *head, int len){
int i;
LNode *p = NULL, *r = head; //p为工作指针;r为链表的尾指针,起始位置指向头结点
for(i=0; i<len; ++i){
//创建结点并设置数据域
p = (LNode*)malloc(sizeof(LNode)); //为新结点开辟空间,并将工作指针p指向它
p->val = arr[i];
p->next = NULL; //记得将新节点中的next指针置为空
//尾插
r->next = p;
r = p;
}
return head;
}
题目三:反转链表
/*
head:头指针
思想:
步骤一:将表的头结点与其后续断开
步骤二:遍历后序部分,依次向前序部分头插
*/
LNode* reverseList(LNode *head){
LNode *p, *s; //s指向p的后继结点,两者起始位置相同
p = s = head->next;
head->next = NULL; //将表头与后序断开
while(p){
s = p->next; //s指向p指向结点的后继,否则一会找不到下一个头插的结点
//当前结点头插到前序部分
p->next = head->next;
head->next = p;
//p指向即将进行头插的结点
p = s;
}
return head;
}
题目四:删除链表所有值为指定值的结点
/*
head:头指针
x:指定值
*/
LNode* deleteListByValue(LNode *head, int x){
LNode *p, *pPre;
p = head->next, pPre = head; //p为工作指针,从第一个结点开始,pPre指向工作指针所指向结点的前驱
while(p){
if(p->val == x){
pPre->next = p->next; //删除该结点
free(p); //释放结点所占空间
p = pPre->next;
continue;
}
p = p->next;
pPre = pPre->next;
}
return head;
}
题目五:合并两个有序链表
/*
l1:链表1
l2:链表2
注意:该题l1,l2无头结点,返回的l3也不带头结点
感兴趣的可以自己在LeetCode上实现一下:https://leetcode-cn.com/problems/merge-two-sorted-lists/
*/
LNode* mergeTwoLists(LNode* l1, LNode* l2){
LNode *l3 = (LNode*)malloc(sizeof(LNode));
LNode *p = l3; //p为工作指针
if(!l1) return l2;
if(!l2) return l1;
while(l1 && l2){
if(l1->val < l2->val){
p->next = l1;
l1 = l1->next;
}else{
p->next = l2;
l2 = l2->next;
}
p = p->next;
}
if(!l1) p->next = l2;
if(!l2) p->next = l1;
return l3->next;
}
题目五:使用选择排序对链表排序
/*
!无头结点
head:指向第一个结点
*/
struct ListNode* sortList(struct ListNode* head){
struct ListNode *p = head, *q, *minp;
int temp;
while(p){
minp = p;
q = p->next;
while(q){
if(minp->val > q->val){
minp = q;
}
q = q->next;
}
//交换值
if(minp != p){
temp = minp->val;
minp->val = p->val;
p->val = temp;
}
p = p->next;
}
return head;
}
题目六:求链表中倒数第K个结点的值
/*
思想:
①首先定义指针p指向头结点,q也指向头结点
②q向前移动k次
③然后p、q同时移动,最终当q指向最后一个结点时,p指向倒数第K个结点
*/
题目七:判断链表是否为回文链表
/*
思想:
①首先定义一个slow指针和一个fast指针
②从起点开始,slow每次向后移动一次,fast每次向后移动两次,直到fast指向NULL结束{
当链表长度为偶数时,slow正好指向右半部分的第一个结点
当链表长度为奇数时:slow正好指向中间结点,其左边一侧结点个数等于右边一侧结点个数
}
③将右半部分反转。
④左侧第一个结点与右侧第一个结点比较,两者依次向后比较。
*/
题目八:求两链表的公共结点
/*
思路:若两个链表有一个公共结点,则该公共结点到两链表尾部每个都是依次重合的。
*/
struct ListNode* searchCommon(struct ListNode* l1, struct ListNode*l2){
int len1=Length(l1), len2=Length(l2);
int i,diffLen;
//比较长度并移动指针
if(len1 > len2){
diffLen=len1-len2;
for(i=0; i<diffLen; i++){
l1=l1->next;
}
}else{
diffLen=len2-len1;
for(i=0; i<diffLen; i++){
l2=l2->next;
}
}
//从该位置依次往后比较
while(l1 && l2){
if(l1==l2) return l1; //两个结点及其它后继结点全部相同l1==l2才成立
else{
l1=l1->next;
l2=l2->next;
}
}
return NULL;
}
题目八:设计算法判断带头结点的循环双链表是否对称
boolen simiar(ListNode* L){
ListNode *p=L->next,*q=L->poior; //首位工作指针
while(p!=q && q->next!=p){ //循环直接条件,!是q->next
if(p->data==q->data){
p=p->next;
q=q->poior;
}else return 0;
}
return 1;
}
题目九:判断链表中是否有环
思路:快慢指针,一个一次向后移动一次,另一个一次向后移动两次。