上篇博客中,我们学习了单链表,为了更加熟练掌握这一知识点,就让我们将单链表的应用操练起来吧!
203. 移除链表元素 - 力扣(LeetCode)
思路一:遍历原链表,将值为val的节点释放掉。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct ListNode Listnode;
struct ListNode* removeElements(struct ListNode* head, int val) {
Listnode* newHead,*newTail;
newHead=newTail=NULL;
//遍历原链表
while(pcur)
{
//找值不为val的值,插入到新链表中
if(pcur->val!=val)
{
//链表为空
if(bewHead==NULL)
{
newHead=newTail=pcur;
}
else{
//链表不为空
newTail->next=pcur;
newTail=newTail->next; }
}
pcur=pcur->next;
}
if(newTail){
newTail->next=NULL;
}
return newHead;
}
LCR 024. 反转链表 - 力扣(LeetCode)
思路一:遍历原链表,将原链表的节点头插。
思路二:
创建三个指针,完成链表的翻转
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct ListNode ListNode;
struct ListNode* reverseList(struct ListNode* head){
//判断是否为空
if(head==NULL)
{
return head;
}
ListNode*n1,*n2,*n3;//定义三个指针
n1=NULL,n2=head,n3=head->next;
while(n2)
{
n2->next=n1;
n1=n2;
n2=n3;
if(n3)
{
n3=n3->next;
}
}
return n1;
}
876. 链表的中间结点 - 力扣(LeetCode)
思路一:直接返回node/2
思路二:快慢指针,slow每次走一步,fast每次走两步
21. 合并两个有序链表 - 力扣(LeetCode)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
if(list1==NULL)
{
return list2;//返回空链表
}
if(list2==NULL)
{
return list1;
}
ListNode*l1=list1;
ListNode*l2=list2;
//创建新的链表
ListNode*newHead,*newTail;
newHead=newTail=(ListNode*)malloc(sizeof(ListNode));
while(l1&&l2)
{
if(l1->val&&l2->val)
{
if(newHead==NULL)
{
newHead=newTail=l1;
}
else
{
newTail->next=l2;
newTail->next=newTail;
}
l2=l2->next;
}
}
if(l2)
{
newTail->next=l2;
}
if(l1)
{
newTail->next=l1;
}
(ListNode*)ret=newHead->next;
free(newHead);
return ret;//newHead里面没有存储值
}
存在重复代码,如何优化呢?
我们可以定义一个头结点,也就是哨兵位。这个链表实际叫作带头链表。
环形链表的约瑟夫问题_牛客题霸_牛客网 (nowcoder.com)
第一步 创建带环链表
第二部 遍历带环链表
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param n int整型
* @param m int整型
* @return int整型
*/
typedef struct ListNode ListNode ;
ListNode* buyNode(int x)
{
ListNode*node=(ListNode*)malloc(sizeof(ListNode));
if(node==NULL)
{
exit(1);
}
node->val=x;
node->next=NULL;
return node;
}
ListNode* creatCirle(int n)
{
ListNode*phead=buyNode(1);
ListNode*ptail=phead;
for(int i=2;i<=n;i++)
{
ptail->next=buyNode(i);
ptail=ptail->next;
}
//首位相连,链接成环
ptail->next=phead;
return ptail;
}
int ysf(int n, int m ) {
// write code here
ListNode*prev=creatCirle(n);
ListNode*pcur=prev->next;
int count=1;
while(pcur->next!=pcur)
{
if(count==m)//销毁pcur节点
{
prev->next=pcur->next;
free(pcur);
pcur=prev->next;
count=1;//重新报数,count重新记为初始值
}
else {//不需要销毁节点
prev=pcur;
pcur=pcur->next;
count++;
}
}
//当链表中只有一个节点的情况跳出循环
return pcur->val;
}
面试题 02.04. 分割链表 - 力扣(LeetCode)
思路一:在原链表上修改
若pcur的节点小于x,往后走
若pcur的节点大于或等于x,尾插在原链表后,删除旧节点
思路二:创建新链表,遍历原链表。若pcur的节点小于x,让它头插在新链表中。
若pcur的节点值大于或等于x,尾插。
思路三:创建新链表,小链表和大链表。
将小链表的尾结点和大链表的第一个有效节点首位相连。
typedef struct ListNode ListNode;
struct ListNode* partition(struct ListNode* head, int x){
if(head==NULL)
{
return NULL;
}
ListNode*lessHead,*lessTail;
ListNode*greaterHead,*greaterTail;
lessHead=lessTail=(ListNode*)malloc(sizeof(ListNode));
greaterHead=greaterTail=(ListNode*)malloc(sizeof(ListNode));
//遍历原链表,将原链表中的节点尾插到大小链表中
ListNode*pcur=head;
while(pcur)
{
if(pcur->val<x)
{
//尾插到小链表中
lessTail->next=pcur;
lessTail=lessTail->next;
}
else
{
//尾插到大链表中
greaterTail->next=pcur;
greaterTail=greaterTail->next;
}
pcur=pcur->next;
}
//小链表的尾结点和大链表的头结点相连
greaterHead->next=NULL;//若不写这一行,则代码出现死循环+next指针初始化
lessTail->next=greaterHead->next;
ListNode*ret=lessHead->next;
free(lessHead);
free(lessTail);
lessHead=lessTail=NULL;
return ret;
}
链表的分类
带头:是指链表带有哨兵位,即为头结点。
尾结点的next指针是否为空。
单链表:不带头单向不循环
双向链表:带头双向循环