LeetCode刷题总结 -- 链表篇
【摘要】
因为去学别的东西,也就两个月没刷题,结果该忘记的不该忘记的都忘记了。 思来想去,还是做个总结要来的好些。 不涉及那些奇思妙想的题目,就纪录最基本的东西。
文章目录
本篇将重点讲链表的基本操作(增删查改)public.hmy_list.c 概览创建节点新增节点指定位置插入节点删除节点问题代码1:问题代码2得出经验翻转链表关于链表成环的处理办法
...
因为去学别的东西,也就两个月没刷题,结果该忘记的不该忘记的都忘记了。
思来想去,还是做个总结要来的好些。
不涉及那些奇思妙想的题目,就纪录最基本的东西。
本篇将重点讲链表的基本操作(增删查改)
做链表的题目,总会遇到各种各样莫名其妙的问题,刚刚又解决一个卡了一下午的,原因是用于插入的节点是在循环之外分配空间的(为了省空间),之后没做清理,导致问题,而我的聚焦点却一直在:为什么使用了
temp = head;
···
temp = temp->next;
···
return head;
- 1
- 2
- 3
- 4
- 5
之后,head居然也跟着偏了?不应该啊。
一切的一切,都源于对基础的把控不够。
所以,本篇我将致力于尽可能的剖析 “增删查改” 这几个基础到尘埃的函数。
如果觉得自己已经深刻领悟了这些操作的小伙伴,可以先去干别的事情了。
public.h
//这是一个通用链表基本操作的头文件
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <memory.h>
#include <assert.h>
//节点数据结构体
typedef struct test
{ char name[12]; //名字
char pwd[8]; //密码
int number; //编号
int flag; //区分管理员和用户 // 0 超级管理员 1 管理员 2 普通用户 3 屏蔽用户
int money; //仅用户有存款,初始500
} TEST_T;
//如果不多来一个数据域,怎么能体现出通用链表的优势
typedef struct reported
{
int amount;//交易金额
int rflag; //交易方式 1、存款 2、取款 3、转账转出 4、转账转入
int lastmoney;//余额
int lastmoney2;//收款者的余额
int number1;//付款账户
int number2;//入款账户
char time[12];//操作时间
} REPORT_T;
//节点描述结构体
typedef struct point
{
void *pData; //指向数据域
struct point *next; //指向下一个节点
} POINT_T;
POINT_T * head ;
extern POINT_T * head;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
my_list.c 概览
//创建结点/
POINT_T * creat(void *data ) //创建一个属于结构体point的函数,
//传入结构体test的指针便可以用以操作test变量,
{ //并返回一个point的指针用以操作point函数
POINT_T *p=NULL; p=(POINT_T *)malloc(sizeof(POINT_T));
if(p==NULL)
{
gotoxy(36,14); printf("申请内存失败");
exit(-1);
}
memset(p,0,sizeof(POINT_T)); p->pData=data;
p->next=NULL;
return p;
}
/新增节点///
void add(POINT_T * the_head,void *data ) //这里的data不会和上面那个冲突吗?
{
POINT_T * pNode=the_head;
POINT_T *ls=creat(data);
//后面再接上一个
while (pNode->next != NULL) //遍历链表,找到最后一个节点
{
pNode=pNode->next;
}
pNode->next=ls; //ls 临时
}
删除节点/
void Del (POINT_T * the_head, int index)
{
POINT_T *pFree=NULL; POINT_T *pNode=the_head;
int flag=0;
while (pNode->next!=NULL)
{
if(flag==index-1)
{ pFree=pNode->next; //再指向数据域就爆了 pNode->next=pNode->next->next; free(pFree->pData); free(pFree); break;
}
pNode=pNode->next;
flag++;
}
}
///计算节点数
int Count(POINT_T * the_head)
{
int count=0;
POINT_T *pNode1=the_head;
while (pNode1->next!=NULL)
{
if(pNode1->next!=NULL)
{ pNode1=pNode1->next; count++;
} }
return count;
}
/查找固定节点数据//
POINT_T * find(POINT_T *the_head,int index)
{
int f=0;
POINT_T *pNode=NULL;
int count=0;
pNode=the_head; count=Count(the_head); if(count<index) printf("find nothing"); while(pNode->next!=NULL)
{
if(index==f) return pNode;
pNode=pNode->next;
f++; }
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
创建节点
//创建结点/
POINT_T * creat(void *data ) //创建一个属于结构体point的函数, //传入结构体test的指针便可以用以操作test变量,
{ //并返回一个point的指针用以操作point函数
POINT_T *p=NULL; //每一个新节点都要置为空
p=(POINT_T *)malloc(sizeof(POINT_T));//为新节点开辟空间
if(p==NULL)
{
printf("申请内存失败");
exit(-1);
}
memset(p,0,sizeof(POINT_T));//再次确保新节点清理干净了 p->pData=data; //再为新节点赋值
p->next=NULL; //将新节点置为无后
return p; //返回此节点
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
新增节点
/新增节点///
void add(POINT_T * the_head,void *data ) //这里的data不会和上面那个冲突吗?
{
POINT_T * pNode=the_head; //pNode和head指向同一块内存地址,但是pNode和head是互相独立的
POINT_T *ls=creat(data);
//后面再接上一个
while (pNode->next != NULL) //遍历链表,找到最后一个节点
{
pNode=pNode->next; //pNode和head是互相独立的,所以此举并不会对head指向的位置进行修改
}
pNode->next=ls; //ls 临时
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
指定位置插入节点
/插入节点///
void add(POINT_T * the_head,int index,void *data ) //这里的data不会和上面那个冲突吗?
{
POINT_T * pNode=the_head; //pNode和head指向同一块内存地址,但是pNode和head是互相独立的
POINT_T *ls=creat(data);
//后面再接上一个
int i = 0;
while (pNode->next != NULL && i<index)
{
pNode=pNode->next; //pNode和head是互相独立的,所以此举并不会对head指向的位置进行修改
}
ls->next = pNode->next; //先将链表后部分接到新节点后面
pNode->next=ls; //再往链表前部分接上新节点
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
删除节点
删除节点/
void Del (POINT_T * the_head, int index)
{
POINT_T *pFree=NULL; POINT_T *pNode=the_head;
int flag=0;
while (pNode->next!=NULL)
{
if(flag==index-1)
{ pFree=pNode->next; //再指向数据域就爆了 pNode->next=pNode->next->next; free(pFree->pData); //释放数据域 free(pFree); //释放指针域 break;
}
pNode=pNode->next;
flag++;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
将这些函数一个一个分开写就不容易出错,但是合在一起的时候,问题就要出来了:
问题代码1:
struct ListNode { int val; ListNode* next; ListNode(int x) : val(x), next(NULL) {} };
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) { //传进来的参数不为空 ListNode* temp1 = list1; ListNode* temp2 = list2; //ListNode* temp3 = new ListNode(0); 这要是放这里了问题就大了 while (temp1->next != NULL && temp2!= NULL) { if (temp1->next->val >= temp2->val) { ListNode* temp3 = new ListNode(0); //这个要放在这里,新插入的节点一定要是新鲜的 temp3->val = temp2->val; //这里要注意,对新指针赋值,一定要只赋值给单指针,不要把后面一串全弄过去,会出现环状链表 temp3->next = temp1->next; temp1->next = temp3; temp2 = temp2->next; } temp1 = temp1->next; } if (temp2!= NULL) { temp1->next = temp2; } return list1;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
问题代码2
这就是一个典型的成环链表。
//ListNode* reverseList(ListNode* head)
//{
// ListNode* node_temp;
// ListNode* new_head;
//
// node_temp = head;
// //遍历一个节点,就把它拿下来放到头去
// while (head->next != NULL)
// {
// //先考虑只又两个节点的情况
// head = head->next;
// new_head = head;
// new_head->next = node_temp;
// node_temp = new_head;
// }
// return new_head;
//}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
得出经验
链表的题目吧,可以把上面那些拆分好的函数直接拿去用,将复杂的逻辑拆解之后就没那么烦了。
没必要非要挤在一块儿写
翻转链表
ListNode* reverseList(ListNode* head)
{ ListNode* node_temp = NULL; //这里设为NULL ListNode* new_head = NULL; //链栈的头 //遍历一个节点,就把它拿下来放到头去 while (head != NULL) { node_temp = head; //先将节点取出 //先考虑只又两个节点的情况 head = head->next; //这个不放这里又成环了 node_temp->next = new_head;
//刚开始相当于是置空的,因为前面并没有分配空间,而是NULL,这也是这个算法不成环的保证 new_head= node_temp; } return new_head;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
关于链表成环的处理办法
文章来源: lion-wu.blog.csdn.net,作者:看,未来,版权归原作者所有,如需转载,请联系作者。
原文链接:lion-wu.blog.csdn.net/article/details/107235196
【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)