LeetCode刷题总结 -- 链表篇
时间:2022-07-23
本文章向大家介绍LeetCode刷题总结 -- 链表篇,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
本篇将重点讲链表的基本操作(增删查改)
做链表的题目,总会遇到各种各样莫名其妙的问题,刚刚又解决一个卡了一下午的,原因是用于插入的节点是在循环之外分配空间的(为了省空间),之后没做清理,导致问题,而我的聚焦点却一直在:为什么使用了
temp = head;
···
temp = temp->next;
···
return head;
之后,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;
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++;
}
}
创建节点
//创建结点/
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; //返回此节点
}
新增节点
/新增节点///
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 临时
}
指定位置插入节点
/插入节点///
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; //再往链表前部分接上新节点
}
删除节点
删除节点/
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:
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;
}
问题代码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;
//}
得出经验
链表的题目吧,可以把上面那些拆分好的函数直接拿去用,将复杂的逻辑拆解之后就没那么烦了。
没必要非要挤在一块儿写
翻转链表
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;
}
关于链表成环的处理办法
- asp.net中几种页面元素的比较
- Flash/Flex学习笔记(19):颜色合成与分解的基本原理
- Flash/Flex学习笔记(18):画线及三角函数的基本使用
- Mapx自带的工具的理解
- 水晶报表的推模式
- Flash/Flex学习笔记(17):按键捕获
- 温故而知新:c#中的特性(attribute)
- 温故而知新:new与override的差异以及virtual方法与abstract方法的区别
- malloc函数及用法
- Centos下安装破解confluence6.3的操作记录
- 也谈如何用技术手段引导用户放弃IE 6
- 手把手教你用vue2.0写个弹窗组件
- FluorineFx:视频录制及回放(Flash/AS3环境)
- VB实现半透明或者部分透明窗体
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 蓝牙芯片----BK3431开发笔记------RW stack中添加自定义服务教程(4)
- 图像简单处理
- 蓝牙---BLE GATT介绍
- Access数据库密码破解 C#
- 没啥用,更换注册表信息使webbrower选择适合的版本
- linux下分割和合并压缩包
- 编译.net .net Core程序 代码,仅做备份
- js删除数组对象中符合条件的数据
- .net core webapi jwt 更为清爽的认证 ,续期很简单(2)
- 手把手教你写一个windows服务 【基于.net】 附实用小工具{注册服务/开启服务/停止服务/删除服务}
- 一网打尽枚举操作 .net core
- Jenkins 发布.net core 程序,服务端无法下载nuget包的解决方法 error NU1102: 找不到版本为 (>= 3.1.6) 的包
- NET Core Kestrel部署HTTPS 一个服务器绑一个证书 一个服务器绑多个证书
- .net core webapi jwt 更为清爽的认证 ,续期很简单(1)
- 用flask来在线管理你的iptables