tip1:先找到待反转链表的前一个结点,然后把待反转的结点一个个拆下来用头插法构建一个反转的链表,最后把链表接回到原链表中去。
tip2:鉴于这里没有头结点,增加一个空的头结点更方便操作从第一个结点开始反转的情况。
tip3:注意链表尾部置空的问题。
struct ListNode* reverseBetween(struct ListNode* head, int m, int n ) {
int k = 1;
if(m == n)
return head; //只反转单个结点相当于不反转
struct ListNode* phead = (struct ListNode*)malloc(sizeof(struct ListNode));
//加一个虚拟头结点更方便操作
phead->next = head; //指向第一个结点
struct ListNode *pre = phead, *p = head; //用pre找到前驱
struct ListNode *q, *r;
while(k < m){
pre = pre->next; //直到开始反转的前一个结点
k++;
}
p = pre->next; //开始反转的结点
r = pre->next; //翻转后的接口
pre->next = NULL; //拆链后前链的末尾要置空
struct ListNode * L = NULL; //为反转链表加一个头指针
while(k <= n ){ //开始反转
q = p->next;
p->next = L;
L = p;
p = q;
k++;
}
if(p == NULL) //一直反转到原链表表尾的情况
pre->next = L; //只需要链接前面接口
else{
pre->next = L; //链接前面接口
r->next = p; //链接后面接口
}
return phead->next; //无论从哪里开始反转,最后第一个结点都是虚头结点的下一个结点
}
当然,不把结点拆下来反转组装再接回去,而是直接在原链表中通过改变指针来改变其位置更方便。
struct ListNode* reverseBetween(struct ListNode* head, int m, int n ) {
if( head == NULL || m == n)
return head;
struct ListNode *xuhead = malloc(sizeof(struct ListNode)); //虚头结点
xuhead->next = head; //虚头结点的指针域指向第一个结点
struct ListNode * p = xuhead; //p指针用来找到第一个反转结点的前驱,初始指空
for(int i = 0; i<m-1; i++) //m=1时,p不动;m=1时,p走一步
p = p->next; //p停在待反转的结点的前驱,且一直不变
struct ListNode* r = p->next; //r指向第一个反转结点
struct ListNode* tmp; //用来跟踪后继,以防掉链
for(int i = 0; i< n-m; i++){ //循环n-m次
tmp = r->next; //暂存后继
r->next = tmp->next;
tmp->next = p->next;
p->next = tmp;
}
return xuhead->next;
}
画图更好理解

京公网安备 11010502036488号