手撕单链表(单向,不循环,不带头结点)的基本操作

news2024/12/28 19:02:35

𝙉𝙞𝙘𝙚!!👏🏻‧✧̣̥̇‧✦👏🏻‧✧̣̥̇‧✦ 👏🏻‧✧̣̥̇:Solitary-walk

      ⸝⋆   ━━━┓
     - 个性标签 - :来于“云”的“羽球人”。 Talk is cheap. Show me the code
┗━━━━━━━  ➴ ⷯ

本人座右铭 :   欲达高峰,必忍其痛;欲戴王冠,必承其重。

👑💎💎👑💎💎👑 
💎💎💎自💎💎💎
💎💎💎信💎💎💎
👑💎💎 💎💎👑    希望在看完我的此篇博客后可以对你有帮助哟

👑👑💎💎💎👑👑   此外,希望各位大佬们在看完后,可以互赞互关一下,看到必回
👑👑👑💎👑👑👑

 目录:

前言:对于单链表的基本操作重在考验大家对C语言指针的底子

一:传值传参区别

二:尾插

三:头插

四:尾删

五:头删

六:指定数据的查找

七:指定位置之前的删除

八:指定位置之后的删除

九:任意位置之前的插入

十:任意位置之后的插入

结语


 一:传值传参区别

这里就拿一个比较经典的问题来引入吧!

   写一个函数实现2个数 的交换

 

对于刚刚接触编程的铁子们,对这个结果 可能存在很大的疑惑

不慌不忙,接下来我慢慢给大家解释 

int a = 1, b = 2;
    int* p = &a;
    *p = 3;

想必大家对这个代码应该不会很陌生吧。

此时我们对指针p进行解引用拿到的就是变量 a 

也就是说,此时我们通过借助指针实现了对a   的改变

同理,这里我在调用Swap( )这个函数的时候,是不是进行传地址就可以实现对2个数的交换?

话不多说,接下来我们代码实现

 

 是滴,此时确实实现了2个数的交换

分析:

1)传参的本质:形参是对实参的一份临时拷贝,对形参的临时修改不会影响实参

2)所以说:当需要对变量进行改变的时候,我们就需要传对应的地址就可以

如何理解“ 传对应的地址”

比如说:

      改变int 类型的变量,这时就需要传int*的指针(地址)    

     改变int *类型的变量,这时就需要传int**的指针(地址)    

     改变结构体类型的变量,这时就需要传结构体的指针(地址)

 二:尾插

分析:

1)首先为要插入进来的数据开辟结点

2)链表不为空的时候:注意此时要改变的是结构体

         首先 先找到尾结点( 链表最后一个结点的next为空)

         其次进行尾插

3)链表为空:注意此时改变的是结构体类型的指针(头节点为空)

         直接进行插入即可

草图如下:

对非空的链表插入前:

 插入后:

   接下来可是重头戏,好好看,一不仔细,就错失了,那可就不好理解了,避免这个“瓜”没有吃到,反而懊恼不已

 1)开辟结点为插入的数据:
因为之后插入需要频繁开辟结点,所以这里写成了一个函数
SLNode* BuyNode(DataType x)
{
	SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));
	if (newnode == NULL)
	{
		perror("malloc fail\n");
		return NULL;
	}
	// 对开辟的结点进行初始化
	newnode->data = x;
	newnode->next = NULL;
	return newnode;
}
2)找尾结点:这里就依次遍历即可

注意啦:看看这样写对不???

SLNode* ptail = phead;
    while (ptail)
    {
        ptail = ptail->next;
    }
    ptail->next = newnode;

NO,NO,NO

乍一看,看不出啥问题,这就是“码图”结合了

这里以逻辑结构(人类的思维,为了形象化的理解)来解释

逻辑图:

 

   当ptail这个指针指向3这个结点的时候,是不为空的,所以就继续进入我的循环里,此时的尾结点就变成了NULL这个对应当结点,下面在进行插入自然也是不能把新的结点和我原来链表进行有效的连接起来

找尾结点的正确代码:

 while (ptail->next)
    {
        ptail = ptail->next;
    }
    ptail->next = newnode;

 3)当链表为空的时候我们发现以上代码不可取:

因为此时实参plist  传给我的phead这个形参就是一份临时拷贝,我对phead(结构体指针)改变不影响plist(结构体指针)的变化

有了前面那个传值传参的引入,想必大家此时应该有了见解了吧

没错!

就是实参传结构体指针的地址,形参用二级指针

 对应完整代码:

void SLPushBack(SLNode* *phead, DataType x)
{
	/*
	1:开辟结点
	2:判读是否为空的链表
	3:非空:找到尾结点;此时改变的是结构体,需要传结构体的地址
	4:为空:直接插入:  因为改变的是结构体类型的指针,所有需要传结构体类型的指针的地址,涉及到二级指针
	*/
	SLNode* newnode = BuyNode(x);
	if (*phead == NULL)  //为空
	{
		newnode->next = *phead;// 对*phead解引用 就是plist这个实参
		*phead = newnode;
		return;
	}
	//非空
	/*  找尾结点:err
	SLNode* ptail = phead;
	while (ptail)
	{
		ptail = ptail->next;
	}
	ptail->next = newnode;

	*/
	SLNode* ptail = *phead;
	while (ptail->next)  //找尾结点
	{
		ptail = ptail->next;
	}
	ptail->next = newnode;
	/*
	当链表为空的时候,以上代码有问题
	为空的时候需要对头节点进行改变,注意头节点是结构体类型指针所以需要传地址
	*/

}

 三:头插

分析:

1) 首先为插入数据开辟结点

2)因为此时改变的是结构体指针(plist),所以需要传入结构体指针的地址

void SLPushFront(SLNode** phead, DataType x)
{
	/*
	1:为x开辟结点
	2:更新头节点
	3:因为改变的是结构体类型的指针,所有需要传结构体类型的指针的地址
	传参的本质是:拷贝:形参是对实参的一份临时拷贝,对形参的修改不会影响我实参的变化
	*/
	SLNode* newnode = BuyNode(x);
	newnode->next = *phead;// 对*phead解引用 就是plist这个实参
	*phead = newnode;
}

四:尾删

分析:

1)首先判断链表是否为空;为空不需删除

2)其次:判断链表是否为一个结点;因为此时改变的头节点(结构体指针);那就涉及到了传结构体指针的地址

3)最后就是多个结点的情况:

      先找尾结点

       删除尾结点

 1)先从正常情况说起(多个结点)

 找尾结点:这里需要找到尾结点的前一个结点,避免free(ptail)时找不到新的尾结点

 尾删后:

SLNode* ptail = *phead;
	SLNode* pre =* phead;
	while (ptail->next)  //找尾结点
	{
		pre = ptail;//保存尾结点的前一个结点
		ptail = ptail->next;
	}
	free(ptail);
	ptail = pre;//尾结点更新
	ptail->next = NULL;//不要忘了置空
2)只有一个结点

注意这里需要传入结构体指针的地址

if ((*phead)->next == NULL)  //一个结点,注意*与->优先级
	{
		free(*phead);
		*phead = NULL;
		return;
	}
 3)判空

直接暴力检查即可:

assert(*phead);

 对应完整代码:

void SLPopBack(SLNode** phead)
{
	/*
	1:判断是否为空
	2:判断是否为一个结点:因为此时改变的是头节点(结构体指针)
	3:找到尾结点,此时尾结点的前一个结点成为新的结点
	4:  *phead 就是头指针  plist
	*/
	//为空:
	assert(*phead);
	
	if ((*phead)->next == NULL)  //一个结点,注意*与->优先级
	{
		free(*phead);
		*phead = NULL;
		return;
	}
	// 非空
	SLNode* ptail = *phead;
	SLNode* pre =* phead;
	while (ptail->next)  //找尾结点
	{
		pre = ptail;//保存尾结点的前一个结点
		ptail = ptail->next;
	}
	free(ptail);
	ptail = pre;//尾结点更新
	ptail->next = NULL;//不要忘了置空


}

五:头删

相信有了前面的尾删,我们对头删那便是轻轻松拿捏了

1)判空

2)非空

 1)判空

assert(*phead);  //直接暴力检查

2)非空:  删除头节点之前需要保存一下

对应完整代码:

void SLPopFront(SLNode** phead)
{
	/*
	1:判是否为空 
	2:非空:删除头节点之前需要保存一下第二个结点
	*/
	assert(*phead);//为空
	SLNode* psec = (*phead)->next;//保存第二个结点
	free(*phead);
	*phead = psec;//更新


}
六:指定数据查找

1:若是当前数据存在,则返回对应的结点;否则返回NULL

2:依次遍历

相信有了前面的基础,我们对这个区区查找的代码轻轻松拿下

SLNode* SLFind(SLNode* phead, DataType x)
{
	/*
	若是找到返回该节点
	循环遍历
	*/
	SLNode* pcur = phead;
	while (pcur)
	{
		if (pcur->data == x)
			return pcur;//返回节点
		else
			pcur = pcur->next;//更新
	}
	return NULL;
}
七:指定位置之前的删除 

分析:

假设对pos这个位置之前的进行删除

1:pos若是为头节点,则不需要删除

2:pos为第二个结点,其实就是进行头删的操作,注意此时改变的是头节点(结构体指针),所以需要传二级指针

3:正常情况:找到pos前一个结点

 1:pos为头节点

直接暴力断言,就像当你作业还没有写完,但你依然再玩游戏此时你的父亲突然过来问你,作业写完了吗,你回答到:没有。你父亲直接就是一顿说,此时你就乖乖去写作业了

assert(*phead != pos);

2:pos 为第二个结点

if ((*phead)->next == pos)//pos为第二个结点
    {
        free(*phead);
        *phead = pos;//pos是新的头节点
    }

3:正常情况
SLNode* pre = *phead;
		while (pre->next->next != pos)
		{
			pre = pre->next;
		}
		free(pre->next);
		pre->next = pos;

对应完整代码: 

void SLEarseBefore(SLNode** phead, SLNode* pos)
{
	/*
	1:pos为头节点是不可以删除的
	2:pos为第二个结点,此时要删除的是头节点,改变的是结构体指针(phead),需要二级指针
	3:正常情况,找到pos前一个结点
	*/
	assert(pos != *phead);//保证pos不为头节点
	if ((*phead)->next == pos)//pos为第二个结点
	{
		free(*phead);
		*phead = pos;//pos是新的头节点
	}
	else
	{
		SLNode* pre = *phead;
		while (pre->next->next != pos)
		{
			pre = pre->next;
		}
		free(pre->next);
		pre->next = pos;
	}
}
八:指定位置之后的删除

分析:假设要删除的位置是pos

    1:pos为最后一个结点;没有必要删除
    2:pos不为最后一个结点

对应代码:

void SLEarseAfter(SLNode** phead, SLNode* pos)
{
	/*
	1:pos为最后一个结点;没有必要删除
	2:pos不为最后一个结点
	*/
	assert(pos->next != NULL);//暴力判断是否为最后一个
	SLNode* del = pos->next;
	pos->next = del->next;
	free(del);
	del = NULL;
}
九:任意位置之前的插入

假设任意位置为pos

1:pos为头节点:可以借助头插的函数进行,注意此时改变的是头节点(结构体指针),要传结构体指针的地址

2:pos不是头节点:需要找到pos的前一个结点

3:为要插入的数据开辟结点

 对应代码:

void SLInsertBefore(SLNode** phead, SLNode* pos, DataType x)
{
	/*
	*1:开辟结点
	2:找到pos前面的结点(pos不是头节点)
	3:pos是头节点此时变成头插
	*/
	SLNode* newnode = BuyNode(x);
	if (pos == *phead)
	{
		SLPushFront(phead, x);
		return;
	}
	else
	{
		SLNode* pre = *phead;
		while (pre->next != pos)
		{
			pre = pre->next;
		}
		//插入
		pre->next = newnode;
		newnode->next = pos;
	}
}
十:任意位置之后的插入

分析:假设此位置是pos

1:开辟结点

2:保存pos后面的那个结点SLNode* p =  pos->next

3: 直接插入

void SLInsertAfter(SLNode* phead, SLNode* pos, DataType x)
{
	/*
	1:开辟结点
	2:保存一下pos后面的那结点(否则会连不上)
	3:直接插入
	*/
	SLNode* newnode = BuyNode(x);
	SLNode* p = pos->next;//保存pos后的结点
	//插入
	pos->next = newnode;
	newnode->next = p;
}

 整个单链表完整代码:

SList.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

typedef int DataType;
typedef struct SListNode
{
	DataType data;//数据域
	struct SListNode* next;//指针域
}SLNode;

void SLPrint(SLNode* phead);
void SLPushFront(SLNode** phead, DataType x);
void SLPushBack(SLNode** phead, DataType x);
void SLPopBack(SLNode** phead);
void SLPopFront(SLNode** phead); 
SLNode* SLFind(SLNode* phead, DataType x);//对指定数据进行查找
void SLModify(SLNode* phead, SLNode*pos,DataType x);

void SLInsertBefore(SLNode** phead, SLNode* pos, DataType x);//在指定数据之前插入
void SLInsertAfter(SLNode* phead, SLNode* pos, DataType x);//在指定数据之前插入

void SLEarseBefore(SLNode** phead, SLNode* pos);//任意位置之前的删除
void SLEarseAfter(SLNode** phead, SLNode* pos);//任意位置之后的删除


SList.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"SList.h"

void SLPrint(SLNode* phead)
{
	SLNode* pcur = phead;
	while (pcur)
	{
		printf("%d->", pcur->data);
		pcur = pcur->next;//更新
	}
	printf("NULL\n");
}
SLNode* BuyNode(DataType x)
{
	SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));
	if (newnode == NULL)
	{
		perror("malloc fail\n");
		return NULL;
	}
	// 对开辟的结点进行初始化
	newnode->data = x;
	newnode->next = NULL;
	return newnode;
}
void SLPushFront(SLNode** phead, DataType x)
{
	/*
	1:为x开辟结点
	2:更新头节点
	3:因为改变的是结构体类型的指针,所有需要传结构体类型的指针的地址
	传参的本质是:拷贝:形参是对实参的一份临时拷贝,对形参的修改不会影响我实参的变化
	*/
	SLNode* newnode = BuyNode(x);
	newnode->next = *phead;// 对*phead解引用 就是plist这个实参
	*phead = newnode;
}
void SLPushBack(SLNode* *phead, DataType x)
{
	/*
	1:开辟结点
	2:判读是否为空的链表
	3:非空:找到尾结点;此时改变的是结构体,需要传结构体的地址
	4:为空:直接插入:  因为改变的是结构体类型的指针,所有需要传结构体类型的指针的地址,涉及到二级指针
	*/
	SLNode* newnode = BuyNode(x);
	if (*phead == NULL)  //为空
	{
		newnode->next = *phead;// 对*phead解引用 就是plist这个实参
		*phead = newnode;
		return;
	}
	//非空
	/*  找尾结点:err
	SLNode* ptail = phead;
	while (ptail)
	{
		ptail = ptail->next;
	}
	ptail->next = newnode;

	*/
	SLNode* ptail = *phead;
	while (ptail->next)  //找尾结点
	{
		ptail = ptail->next;
	}
	ptail->next = newnode;
	/*
	当链表为空的时候,以上代码有问题
	为空的时候需要对头节点进行改变,注意头节点是结构体类型指针所以需要传地址
	*/

}
void SLPopBack(SLNode** phead)
{
	/*
	1:判断是否为空
	2:判断是否为一个结点:因为此时改变的是头节点(结构体指针)
	3:找到尾结点,此时尾结点的前一个结点成为新的结点
	4:  *phead 就是头指针  plist
	*/
	//为空:
	assert(*phead);
	
	if ((*phead)->next == NULL)  //一个结点,注意*与->优先级
	{
		free(*phead);
		*phead = NULL;
		return;
	}
	// 非空
	SLNode* ptail = *phead;
	SLNode* pre =* phead;
	while (ptail->next)  //找尾结点
	{
		pre = ptail;//保存尾结点的前一个结点
		ptail = ptail->next;
	}
	free(ptail);
	ptail = pre;//尾结点更新
	ptail->next = NULL;//不用忘了置空
	
	//对一个与多个节点的操作可以合并
	//只要找到倒数第二个结点就可以
	/*SLNode* ptail = *phead;

	while (ptail->next->next)
	{
		ptail = ptail->next;
	}
	free(ptail->next);
	ptail->next = NULL;*/

}
void SLPopFront(SLNode** phead)
{
	/*
	1:判是否为空 
	2:非空:删除头节点之前需要保存一下第二个结点
	*/
	assert(*phead);//为空
	SLNode* psec = (*phead)->next;//保存第二个结点
	free(*phead);
	*phead = psec;//更新
}
SLNode* SLFind(SLNode* phead, DataType x)
{
	/*
	若是找到返回该节点
	循环遍历
	*/
	SLNode* pcur = phead;
	while (pcur)
	{
		if (pcur->data == x)
			return pcur;//返回节点
		else
			pcur = pcur->next;//更新
	}
	return NULL;
}
void SLInsertBefore(SLNode** phead, SLNode* pos, DataType x)
{
	/*
	*1:开辟结点
	2:找到pos前面的结点(pos不是头节点)
	3:pos是头节点此时变成头插
	*/
	SLNode* newnode = BuyNode(x);
	if (pos == *phead)
	{
		SLPushFront(phead, x);
		return;
	}
	else
	{
		SLNode* pre = *phead;
		while (pre->next != pos)
		{
			pre = pre->next;
		}
		//插入
		pre->next = newnode;
		newnode->next = pos;
	}
}
void SLInsertAfter(SLNode* phead, SLNode* pos, DataType x)
{
	/*
	1:开辟结点
	2:保存一下pos后面的那结点(否则会连不上)
	3:直接插入
	*/
	SLNode* newnode = BuyNode(x);
	SLNode* p = pos->next;//保存pos后的结点
	//插入
	pos->next = newnode;
	newnode->next = p;
}
void SLEarseBefore(SLNode** phead, SLNode* pos)
{
	/*
	1:pos为头节点是不可以删除的
	2:pos为第二个结点,此时要删除的是头节点,改变的是结构体指针(phead),需要二级指针
	3:正常情况,找到pos前一个结点
	*/
	assert(pos != *phead);//保证pos不为头节点
	if ((*phead)->next == pos)//pos为第二个结点
	{
		free(*phead);
		*phead = pos;//pos是新的头节点
	}
	else
	{
		SLNode* pre = *phead;
		while (pre->next->next != pos)
		{
			pre = pre->next;
		}
		free(pre->next);
		pre->next = pos;
		SLNode* pre = *phead;
		while (pre->next->next != pos)
		{
			pre = pre->next;
		}
		free(pre->next);
		pre->next = pos;
	}
}
void SLEarseAfter(SLNode** phead, SLNode* pos)
{
	/*
	1:pos为最后一个结点;没有必要删除
	2:pos不为最后一个结点
	*/
	assert(pos->next != NULL);//暴力判断是否为最后一个
	SLNode* del = pos->next;
	pos->next = del->next;
	free(del);
	del = NULL;
}
void SLModify(SLNode* phead, SLNode* pos, DataType x)
{
	assert(phead);
	pos->data = x;

}


test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"SList.h"

void TestPush()
{
	SLNode* plist = NULL;
	//SLPushFront(&plist,1);
	//SLPushFront(&plist,2);
	//SLPushFront(&plist,3);
	//SLPrint(plist);
	SLPushBack(&plist, 4);
	SLPushBack(&plist, 5);
	SLPrint(plist);

}
void TestPop()
{
	SLNode* plist = NULL;
	SLPushBack(&plist, 4);
	SLPushBack(&plist, 5);
	SLPushBack(&plist, 6);
	SLPushBack(&plist, 7);
	SLPrint(plist);
	SLNode* pos = SLFind(plist, 7);
	if(pos)//避免pos为空
		SLInsertAfter(plist, pos, 44);
	SLPrint(plist);

	/*SLPopBack(&plist);
	SLPrint(plist);

	SLPopBack(&plist);*/
	/*SLPopFront(&plist);
	SLPrint(plist);

	SLPopFront(&plist);
	SLPrint(plist);*/


}
void TestEarse()
{
	SLNode* plist = NULL;
	SLPushBack(&plist, 4);
	SLPushBack(&plist, 5);
	SLPushBack(&plist, 6);
	SLPushBack(&plist, 7);
	SLPrint(plist);
	SLNode* pos = SLFind(plist, 7);
	if (pos)//避免pos为空
		//SLEarseAfter(&plist, pos);
		SLModify(plist, pos, 77);
	SLPrint(plist);
}

void Swap(int *x, int* y)
{
	int tmp = *x;//中间变量
	*x = *y;
	*y = tmp;
}
int main()
{
	TestEarse();
	
	return 0;
	/*
	总结:
	1:是指针不一定必须断言,是否断言取决于你的操作
	2:在函数外面改变变量,需要传地址,想改变谁,就传对应类型的地址
	3:对于链表这块一定注意自己要改变的是结构体还是结构体指针???因为这决定了传的地址类型不一样
	4:找
	*/
}

结语:

对于初学单链表的小白来讲(比如我本人,哈哈哈),这个理解起来确实不是那么顺手,其实重点在指针和结构体的掌握。当然自己也需要反复的体会其中的奥妙,

都看到这里了,屏幕前的你,咱一波关注走起呗,你的支持是我不懈的动力,蟹蟹

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1372355.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

5,sharding-jdbc入门-sharding-jdbc广播表

执行sql #在数据库 user_db、order_db_1、order_db_2中均要建表 CREATE TABLE t_dict (dict_id BIGINT (20) NOT NULL COMMENT 字典id,type VARCHAR (50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 字典类型,code VARCHAR (50) CHARACTER SET utf8 COLLAT…

windows和liunx对比及Linux分类

windows一定比liunx差吗&#xff0c;这绝对是天大误解&#xff0c;不是说你常用的开始是liunx就代表windows差 windows和liunx对比 有人说Linux性能远高于Windows&#xff0c;这个笔者是不认可的&#xff0c;给Linux套上一个图形界面&#xff0c;你再使劲美化一下&#xff0c…

【论文精读】A Survey on Large Language Model based Autonomous Agents

A Survey on Large Language Model based Autonomous Agents 前言Abstract1 Introduction2 LLM-based Autonomous Agent Construction2.1 Agent Architecture Design2.1.1 Profiling Module2.1.2 Memory ModuleMemory StructuresMemory FormatsMemory Operations 2.1.3 Plannin…

Android Canvas图层saveLayer剪切clipPath原图addCircle绘制对应圆形区域并放大,Kotlin(3)

Android Canvas图层saveLayer剪切clipPath原图addCircle绘制对应圆形区域并放大&#xff0c;Kotlin&#xff08;3&#xff09; 在文章2 Android Canvas图层saveLayer剪切clipPath原图addCircle绘制对应圆形区域&#xff0c;Kotlin&#xff08;2&#xff09;-CSDN博客 的基础上&…

上海雏鸟科技无人机灯光秀跨年表演点亮三国五地夜空

2023年12月31日晚&#xff0c;五场别开生面的无人机灯光秀跨年表演在新加坡圣淘沙、印尼雅加达、中国江苏无锡、浙江衢州、陕西西安等五地同步举行。据悉&#xff0c;这5场表演背后均出自上海的一家无人机企业之手——上海雏鸟科技。 在新加坡圣淘沙西乐索海滩&#xff0c;500架…

【Python学习】Python学习11-元组

目录 【Python学习】Python学习11-元组 前言创建语法创建语法特殊形式访问元组操作元组元组运算符元组内置函数Python列表函数&方法参考 文章所属专区 Python学习 前言 本章节主要说明Python的Python 的元组与列表类似&#xff0c;不同之处在于元组的元素不能修改。通过小…

我的 AI 成长星球,邀请你加入

大家好啊&#xff0c;我是董董灿。 2023年终总结时我这个小白坚持写作一整年&#xff0c;赚了多少&#xff1f;提到了一点&#xff0c;2024希望自己创建一个免费星球。 其实一直就想弄一个高质量的 AI 知识交流平台&#xff0c;方便大家一起交流和学习&#xff0c;同时提高对 …

Python虚拟环境轻松配置:Jupyter Notebook中的内核管理指南

问题 在Python开发中&#xff0c;一些人在服务器上使用Jupyter Notebook中进行开发。一般是创建虚拟环境后&#xff0c;向Jupyter notebook中添加虚拟环境中的Kernel&#xff0c;后续新建Notebook中在该Kernel中进行开发&#xff0c;这里记录一下如何创建Python虚拟环境以及添…

关于Vue前端接口对接的思考

关于Vue前端接口对接的思考 目录概述需求&#xff1a; 设计思路实现思路分析1.vue 组件分类和获取数值的方式2.http 通信方式 分类 如何对接3.vue 组件分类和赋值方式&#xff0c; 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your p…

C/C++调用matlab

C/C调用matlab matlab虽然可以生成C/C的程序&#xff0c;但其能力很有限&#xff0c;很多操作无法生成C/C程序&#xff0c;比如函数求解、优化、拟合等。为了解决这个问题&#xff0c;可以采用matlab和C/C联合编程的方式进行。使用matlab将关键操作打包成dll环境&#xff0c;再…

仿蓝奏云网盘 /file/list SQL注入漏洞复现

0x01 产品简介 仿蓝奏网盘是一种类似于百度网盘的文件存储和共享解决方案。它为用户提供了一个便捷的平台,可以上传、存储和分享各种类型的文件,方便用户在不同设备之间进行文件传输和访问。 0x02 漏洞概述 仿蓝奏云网盘 /file/list接口处存在SQL注入漏洞,登录后台的攻击…

代码随想录day20 开始二叉搜索树

654.最大二叉树 题目 给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下&#xff1a; 二叉树的根是数组中的最大元素。左子树是通过数组中最大值左边部分构造出的最大二叉树。右子树是通过数组中最大值右边部分构造出的最大二叉树。 通过给定的数组构…

零基础学习数学建模——(二)数学建模的步骤

本篇博客将详细介绍数学建模的步骤。 文章目录 引例&#xff1a;年夜饭的准备第一步&#xff1a;模型准备第二步&#xff1a;模型假设第三步&#xff1a;模型建立第四步&#xff1a;模型求解第五步&#xff1a;结果分析第六步&#xff1a;模型检验第七步&#xff1a;模型应用及…

Kubernets(K8S)启动和运行01 快速入门

简介 Kubernetes is an open source orchestrator for deploying containerized applications. It was originally developed by Google, inspired by a decade of experience deploying scalable, reliable systems in containers via application-oriented APIs. Kubernete…

C语言基础语法跟练 day2

题源&#xff1a;牛客网 16、BoBo写了一个十六进制整数ABCDEF&#xff0c;他问KiKi对应的十进制整数是多少。 #include <stdio.h>int main() { //创建变量char arr[] "ABCDEF";int i;int sum0,c; //依次转换十六进制为十进制for(i0; arr[i]!\0; i){char b …

SENet实现遥感影像场景分类

今天我们分享SENet实现遥感影像场景分类。 数据集 本次实验我们使用的是NWPU-RESISC45 Dataset。NWPU Dataset 是一个遥感影像数据集&#xff0c;其中 NWPU-RESISC45 Dataset 是由西北工业大学创建的遥感图像场景分类可用基准&#xff0c;该数据集包含像素大小为 256*256 共计 …

CentOS本地部署SQL Server数据库无公网ip环境实现远程访问

文章目录 前言1.安装GeoServer2. windows 安装 cpolar3. 创建公网访问地址4. 公网访问Geo Servcer服务5. 固定公网HTTP地址 前言 GeoServer是OGC Web服务器规范的J2EE实现&#xff0c;利用GeoServer可以方便地发布地图数据&#xff0c;允许用户对要素数据进行更新、删除、插入…

23种设计模式精讲,配套23道编程题目 ,支持 C++、Java、Python、Go

关于设计模式的学习&#xff0c;大家应该还是看书或者看博客&#xff0c;但却没有一个边学边练的学习环境。 学完了一种设计模式 是不是应该去练一练&#xff1f; 所以卡码网 针对 23种设计&#xff0c;推出了 23道编程题目&#xff0c;来帮助大家练习设计模式&#xff0c;地…

oracle基本用户管理和权限分配

1.用户与模式的关系&#xff0c;一一对应的关系 2.创建与管理用户 2.1创建用户语法 CREATE user wdf IDENTIFIED by tiger--创建用户wdf,密码tiger DEFAULT tablespace users--用户的默认表空间 quota 10M on users;--在表空间的占用最大空间 注意&#xff1a;用户创建以后…

C练习——N个水手分椰子

题目&#xff1a; 五个水手在岛上发现一堆椰子&#xff0c;先由第1个水手把椰子分为等量的5堆&#xff0c;还剩下1个给了猴子&#xff0c;自己藏起1堆。然后&#xff0c;第2个水手把剩下的4堆混合后重新分为等量的5堆&#xff0c;还剩下1个给了猴子&#xff0c;自己藏起1堆。以…