力扣链接
自己的效率较低的思路,看看即可
struct ListNode* reverseList(struct ListNode* head)
{
struct ListNode* cur=head;
struct ListNode* tail=head;//追踪倒数第二个节点,快慢指针法
struct ListNode* Newhead=head;
if(head==NULL)
{
return head;
}
if(head->next==NULL)
{
return head;
}
while(cur->next!=NULL)
{
tail=cur;
cur=cur->next;
}
tail->next=NULL;
Newhead=cur;//记录新节点
struct ListNode* CunNewhead=Newhead;//不让新节点改变
while(head->next!=NULL)
{
cur=head;
while(cur->next!=NULL)
{
tail=cur;
cur=cur->next;
}
tail->next=NULL;
CunNewhead->next=cur;
CunNewhead=cur;
}
CunNewhead->next=head;
return Newhead;
}
经典解法
struct ListNode* reverseList(struct ListNode* head)
{
struct ListNode* cur=head;
struct ListNode* prev=NULL;
struct ListNode* tmp=NULL;
while(cur)
{
tmp=cur->next;
cur->next=prev;
prev=cur;
cur=tmp;
}
cur=prev;
return cur;
}
83. 删除排序链表中的重复元素 - 力扣(LeetCode)
struct ListNode* deleteDuplicates(struct ListNode* head){
if(head==NULL) return head;
//仔细看题是已排序过的
struct ListNode* slow=head;
struct ListNode* fast=head->next;
struct ListNode* tail;
while(fast)//暴力解法(双指针),
{//每次迭代时,慢指针跟快指针先比较
//如果相等,快指针继续走
//直到快指针走到NULL,因为快指针肯定先走完
if(slow->val==fast->val)//如果相等,就把值相等的节点释放
//然后重新链接
{
tail=fast;
fast=fast->next;
slow->next=fast;
free(tail);
}
else//如果不相等快指针和满指针同时走一步
{
slow=slow->next;
fast=fast->next;
}
}
return head;
}
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{
//含哨兵位的方法
struct ListNode newnode;
struct ListNode* head=&newnode;
head->val=0;
head->next=NULL;
struct ListNode* tail=head;
while(list1!=NULL && list2!=NULL)
{
if(list1->val>list2->val)//小的放下来,尾插到哨兵位后面
{
tail->next=list2;
tail=tail->next;
list2=list2->next;
}
else
{
tail->next=list1;
tail=tail->next;
list1=list1->next;
}
}
if(list1==NULL)//注意情况可能有一边判断完了,另一边还没判断完
{
tail->next=list2;
}
else if(list2==NULL)
{
tail->next=list1;
}
return head->next;
}
struct Node* Buynewnode()//申请节点
{
struct Node* ret =
(struct Node*)malloc(sizeof(struct Node));
if (ret == NULL)
{
printf("malloc fail\n");
exit(-1);
}
ret->val = 0;
ret->next = NULL;
ret->random = NULL;
return ret;
}
struct Node* copyRandomList(struct Node* head) {
if(head == NULL) return head;//链表可能为空的情况
struct Node* cur = head;
struct Node* tail = head;
struct Node* Copy = NULL;
struct Node* nnnhead = head;
while (cur)//每次在给定的链表后面复制一个相同的节点
{
Copy = Buynewnode();//每次复制时申请一个节点
Copy->val = cur->val;//把此时位置的数值复制给新申请的节点
Copy->next = cur->next;//先让申请的节点链接到旧链表此时位置的
//下一个节点
tail = cur->next;
cur->next = Copy;//让旧的链表此时的位置的节点的下一个节点
//链接到这个新节点
cur = tail;
}
cur = head;
tail = NULL;//追着cur->next看看tail是否在copy
while (cur)//每次要把随机指针指向复制后的跟旧链表相似的节点
{
tail = cur->next;
if (cur->random != NULL)
{
cur->next->random = cur->random->next;//因为当前指针的随机
//指针的下一个节点就是在前面复制过后的节点
}
else
{
cur->next->random = cur->random;
}
cur = cur->next->next;
}
tail = head;//保存前一个节点释放节点,
cur = head->next;
struct Node* newhead = head->next;
while (cur && cur->next )//分离复制后的链表,将复制后的
//链表重新链接
{
tail = cur->next;
cur->next = cur->next->next;
cur = cur->next;
}
return newhead;
}
struct ListNode* getIntersectionNode(struct ListNode* headA, struct ListNode* headB) {
struct ListNode* c1 = headA;
struct ListNode* c2 = headB;
int L1 = 0;
int L2 = 0;
while (c1)//判断相差的值
{
c1 = c1->next;
++L1;
}
while (c2)//判断相差的值
{
c2 = c2->next;
++L2;
}
int count = abs(L2 - L1);
//判断长短
struct ListNode* Short = headA;//假设法
struct ListNode* Long = headB;
if (L2 > L1)//判断长短,重新赋值
{
}
else
{
Long = headA;
Short = headB;
}
while (count--)//长的先走
{
Long = Long->next;
}
while (Short != Long)//等短的和长的走到一起时停止,我们相交
//之后链表后面的节点数量是一样的,而单链表相交只能指向一个地址
//不能指向两个地址
{
Long = Long->next;
Short = Short->next;
if (Short == NULL)
{
return NULL;
}
}
return Short;
}
带头双向链表
#pragma once
// 带头+双向+链表增删查改实现
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int LTDataType;
typedef struct ListNode
{
LTDataType _data;
struct ListNode* _next;
struct ListNode* _prev;
}ListNode;
// 创建返回链表的头结点.
ListNode* ListCreate();
ListNode* ListCreate()
{
ListNode* head = (ListNode*)malloc(sizeof(ListNode));
if (head == NULL)
{
printf("malloc fail\n");
exit(-1);
}
head->_next=head->_prev = NULL;
head->_data = -1;//哨兵位
return head;
}
// 双向链表销毁
void ListDestory(ListNode* pHead);
void ListDestory(ListNode* pHead)
{
//这里不用判断是否为空的情况,我们的哨兵位不可能为空
//因为如果为空,我们在创建哨兵位时就已经退出并报错了
ListNode* cur = pHead->_next;
ListNode* tail = pHead->_next;
while (cur)
{
tail = cur;
cur = cur->_next;
free(tail);
}
pHead->_next = NULL;
pHead->_prev = NULL;
}
// 双向链表打印
void ListPrint(ListNode* pHead);
void ListPrint(ListNode* pHead)
{
ListNode* cur = pHead->_next;//不要打印哨兵位的数据
while (cur)
{
printf("%d->", cur->_data);
cur = cur->_next;
}
printf("NULL\n");
}
// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x);//尾插
void ListPushBack(ListNode* pHead, LTDataType x)
{
ListNode* tail = pHead;//尾插的指针
ListNode* prev = pHead;//因为要链接前一个,每次遍历时,需要记录上一个节点
ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));//申请新节点
//链接到尾节点
if (newnode == NULL)
{
printf("malloc fail\n");
exit(-1);
}
newnode->_next = NULL;
newnode->_prev = NULL;
newnode->_data = x;//初始化
while (tail)
{
prev = tail;//为什么每次要记录tail经过的上一个节点
//因为我们这里是双向链表尾插的时候要链接前一个节点
//相当于我们是在两个节点中插入,
//左边是正常节点,右边是空,所以根据我的这个思路就用prev
//并且因为我们没用追随节点的话,tail走到空,
//当我们在插入的时候,
tail = tail->_next;
}
tail = newnode;
prev->_next = tail;
newnode->_prev = prev;
}
// 双向链表尾删
void ListPopBack(ListNode* pHead);//尾删
void ListPopBack(ListNode* pHead)
{
ListNode* tail = pHead;
//ListNode* prev = pHead;//记录前一个节点,给他的next置为空
while (tail->_next)
{
/*prev = tail;*/
tail = tail->_next;
}
if (tail == pHead)//没有结点的情况
{
;
}
else
{
tail->_prev ->_next = NULL;
free(tail);
/*prev->_next = NULL;*/
}
}
// 双向链表头插
void ListPushFront(ListNode* pHead, LTDataType x);//头插
void ListPushFront(ListNode* pHead, LTDataType x)
{
ListNode* head = pHead;//哨兵位
ListNode* cur = pHead->_next;
ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));//申请新节点
if (newnode == NULL)
{
printf("malloc fail\n");
exit(-1);
}
newnode->_next = NULL;
newnode->_prev = NULL;
newnode->_data = x;//初始化
newnode->_next = head->_next;//将新节点的next指向哨兵位的下一个节点
newnode->_prev = head;//将新节点的位置的prev指向哨兵位
head->_next = newnode;//哨兵位的next指向新节点
if (newnode->_next == NULL)//空节点
//因为我们如果是在两个节点中插入的话,当第二个节点为空时,
//我们就不能让他指向前一个节点
{
;
}
else
{
newnode->_next->_prev = newnode;//第二个节点不为空
}
}
// 双向链表头删
void ListPopFront(ListNode* pHead);
void ListPopFront(ListNode* pHead)
{
ListNode* cur = pHead->_next;
ListNode* tail = cur;
if (cur)//如果哨兵位后面此时节点为空时,就不要去释放
//会造成释放空指针
{
}
else if (cur->_next == NULL)//如果节点为1的话我们不用重新链接释放过后的节点
{
pHead->_next = cur->_next;//让他们指向空就行
free(cur);
}
else//节点不为1和0的情况
{
pHead->_next = cur->_next;
cur->_next->_prev = pHead;
free(cur);
}
}
// 双向链表查找
ListNode* ListFind(ListNode* pHead, LTDataType x);
ListNode* ListFind(ListNode* pHead, LTDataType x)
{
ListNode* cur = pHead->_next;
while (cur)
{
if (cur->_data == x)
{
return cur;
}
cur = cur->_next;
}
return NULL;
}
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x);
void ListInsert(ListNode* pos, LTDataType x)
{
assert(pos);
ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
if (newnode == NULL)
{
printf("malloc fail\n");
exit(-1);
}
newnode->_next = NULL;
newnode->_prev = NULL;
newnode->_data = x;
//链接前后两个节点,因为pos找不到的话(空节点也包括在内)会我们在前面就会判断并退出,所以我们不需要去判断有木有节点
newnode->_prev = pos->_prev; //将新节点的prev指向pos位置的前一个节点
newnode->_next = pos;//将新节点的next指向pos,
pos->_prev->_next = newnode;//将pos指向的前一个节点的next指向新节点
pos->_prev = newnode;//将pos的prev指向新节点
}
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos);
void ListErase(ListNode* pos)
{
assert(pos);
if (pos->_next == NULL)//如果pos的位置是在最后一个的话,我们就不需要去链接
//新节点,那是为什么呢,我们看第二个条件
{
pos->_prev->_next = NULL;
free(pos);
}
else
{
pos->_prev->_next = pos->_next;
pos->_next->_prev = pos->_prev;//如果最后一个节点的nxt指向空,那么
//pos->_next->_prev就对空指针解引用了
free(pos);
}
}
带头双向循环链表
//带头双向循环链表
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
typedef int LTDataType;
typedef struct ListNode
{
LTDataType _data;
struct ListNode* _next;
struct ListNode* _prev;
}ListNode;
// 创建返回链表的头结点.//这个不用改
ListNode* ListCreate();
ListNode* ListCreate()
{
ListNode* head = (ListNode*)malloc(sizeof(ListNode));
if (head == NULL)
{
printf("malloc fail\n");
exit(-1);
}
head->_next = head->_prev = head;
head->_data = -1;//哨兵位
return head;
}
// 双向链表销毁
void ListDestory(ListNode* pHead);
void ListDestory(ListNode* pHead)//不用改
{
ListNode* cur = pHead->_next;
ListNode* tail = pHead->_next;
while (cur && cur != pHead)
{
tail = cur;
cur = cur->_next;
free(tail);
}
pHead->_next = pHead;
pHead->_prev = pHead;
}
// 双向链表打印
void ListPrint(ListNode* pHead);
void ListPrint(ListNode* pHead)//
{
ListNode* cur = pHead->_next;
while (cur && cur != pHead)//我们停止条件是cur指向哨兵位时
{
printf("%d->", cur->_data);
cur = cur->_next;
}
printf("NULL\n");
}
// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x);//尾插
void ListPushBack(ListNode* pHead, LTDataType x)
{
//因为是带头循环的双向链表,我们在初始化时不需要去判断节点是否为空
ListNode* tail = pHead;//尾插的指针
ListNode* prev = pHead;//因为要链接前一个,每次遍历时,需要记录上一个节点
ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
if (newnode == NULL)
{
printf("malloc fail\n");
exit(-1);
}
newnode->_next = NULL;
newnode->_prev = NULL;
newnode->_data = x;
//对比双向链表,我们的链表为空时,哨兵位的next和prev都指向的是自己
//尾插过程
newnode->_prev = pHead->_prev;
newnode->_prev->_next = newnode;
newnode->_next = pHead;
pHead->_prev = newnode;
}
// 双向循环链表尾删
void ListPopBack(ListNode* pHead);//尾删
void ListPopBack(ListNode* pHead)
{
//不用判断链表节点是否为空
pHead->_prev->_prev->_next = pHead;//因为我们的哨兵位的prev
//指向的时尾节点
ListNode* cun = pHead->_prev;
pHead->_prev = pHead->_prev->_prev;
if (cun != pHead)
{
free(cun);
}
}
// 双向循环链表头插
void ListPushFront(ListNode* pHead, LTDataType x);//头插
void ListPushFront(ListNode* pHead, LTDataType x)
{
ListNode* head = pHead;//头插的指针
ListNode* cur = pHead->_next;
ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
if (newnode == NULL)
{
printf("malloc fail\n");
exit(-1);
}
newnode->_next = NULL;
newnode->_prev = NULL;
newnode->_data = x;
//头插的过程
newnode->_next =pHead->_next;
pHead->_next->_prev = newnode;
pHead->_next = newnode;
newnode->_prev = pHead;
}
// 双向链表头删
void ListPopFront(ListNode* pHead);
void ListPopFront(ListNode* pHead)
{
assert(pHead);
assert(pHead->_next != pHead);
ListNode* cur = pHead;
//记住如果不用cur,那我们得理清他的先后顺序
//因为顺序错了,可能节点就找不到了
cur = pHead->_next;
pHead->_next = pHead->_next->_next;
pHead->_next->_prev = pHead;
free(cur);
}
// 双向链表查找
ListNode* ListFind(ListNode* pHead, LTDataType x);
ListNode* ListFind(ListNode* pHead, LTDataType x)
{
ListNode* cur = pHead->_next;
while (cur && cur != pHead)
{
if (cur->_data == x)
{
return cur;
}
cur = cur->_next;
}
return NULL;
}
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x);
void ListInsert(ListNode* pos, LTDataType x)//不用改
{
assert(pos);
ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
if (newnode == NULL)
{
printf("malloc fail\n");
exit(-1);
}
newnode->_next = NULL;
newnode->_prev = NULL;
newnode->_data = x;
newnode->_prev = pos->_prev;
newnode->_next = pos;
pos->_prev->_next = newnode;
pos->_prev = newnode;
}
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos);
void ListErase(ListNode* pos)
{
assert(pos);
ListNode* cun = pos;
pos->_prev->_next = pos->_next;
pos->_next->_prev = pos->_prev;
free(cun);
}