【数据结构-初阶】详解线性表(3)---双链表

【数据结构-初阶】详解线性表(3)---双链表

🎈主页传送门:良木生香

🔥个人专栏:《C语言》 《数据结构-初阶》 《程序设计》

🌟人为善,福随未至,祸已远行;人为恶,祸虽未至,福已远离


目录

1、双链表的概念

2、双链表的基本实现

2.1、双向链表节点的创建

2.2、双向链表的初始化

2.3、双向链表长度的计算

2.4、双向链表的插入操作:

2.4.1、头部插入:

2.4.2、尾部插入:

2.4.3、查找pos位置的元素:

2.4.4、pos位置插入:

2.4.4.1、pos位置之前插入:

2.4.4.2、pos位置之后插入:

2.5、双向链表的删除操作:

2.5.1、头部删除:

2.5.2、尾部删除:

2.5.3、pos位置删除:

2.6、双向链表的元素查找:

2.7、双向链表的修改:

2.8、双向链表的打印:

2.9、双向链表的销毁:

3、代码总和:


上期回顾:在上一篇文章中,我们了解了链表是由一个一个节点通过指针连接在一起而组成的,每个节点是由数据域和指针域组成的.基于这个基础,我们实现了单链表(单向不带头结点不循环链表)的增删查改四个基本操作.

那么今天我们来实现一下另外一个链表---双向带头结点循环链表(双链表)

1、双链表的概念

双链表,根据类比单链表得出,双链表是由两个指针的,因为单链表只有一个指针嘛,嘻嘻。确实,双链表的结构与单链表极其的相似,双链表同样由数据域和指针域组成,只不过在指针域中,双链表有两个指针,一个指针是指向有一个节点,一个指针是指向前一个节点,如下图:

因为今天要讲的是双向带头结点循环链表,所以整个链表的就应该为下图所示:

头结点相当于哨兵位,不会因为链表的操作而改变,有了这些前备知识之后,我们就可以开始对双链表进行实现了~~~

2、双链表的基本实现

2.1、双向链表节点的创建

双向链表节点的创建与单链表的相似,都是先向内存申请一个节点的空间,然后对立面的元素先进行初始化,但因为双向链表里面有两个指针,所以在指针的指向上会有所不同

下面是图示:

在初始化指针指向时候,要将两个指针指向自己,下面是具体的代码:

DListNode* Buy_Node(Elemtype data) { DListNode* newNode = (DListNode*)malloc(sizeof(DListNode)); if (newNode == NULL) { printf("新节点创建失败...\n"); return NULL; } newNode->next = newNode; newNode->data = data; newNode->front = newNode; return newNode; } 

2.2、双向链表的初始化

今天我们要讲的是带头节点的双向链表,那么就不用像不带头结点的单链表那样子对第一个节点初始化,所以我们只用对哨兵位进行初始化,即创建一个空节点,随便给节点进行赋值,在这里我将哨兵位赋值上-1,代码如下:

DListNode* Init_DListNode() { DListNode* phead = Buy_Node(-1); //现在是创建头节点 if (phead == NULL) { printf("头节点创建失败...\n"); return NULL; } return phead; } 

2.3、双向链表长度的计算

计算双向链表的长度,只用遍历一遍链表并用计数器技术即可,下面是代码

int Get_DListlength(DListNode* phead) { DListNode* pcur = phead; int count = 0; if (pcur->next == phead) { return 0; } while (pcur->next != phead) { pcur = pcur->next; count++; } return count; } 

我们将用于遍历的指针放在头节点(哨兵位)之后,即正式节点的位置,这样就不会将哨兵位计算进去

2.4、双向链表的插入操作:

与之前的链表一样,插入都可以分为头插,尾插,pos位置插入

2.4.1、头部插入:

对于头部插入,我们是将新节点插入到哨兵位与第一个正式节点之间的,下面图是示意图:

下面是具体实现的代码:

void Push_Front(DListNode* phead, Elemtype data) { assert(phead); //先创建新节点 DListNode* newNode = Buy_Node(data); if (newNode == NULL) { printf("新的头插节点创建失败...\n"); return; } //phead newNode phead->next newNode->next = phead->next; newNode->front = phead; phead->next->front = newNode; phead->next = newNode; }
在写代码的时候,要注意先将新节点的next与front指针与旧节点进行连接,再断开旧节点之间的连接

2.4.2、尾部插入:

尾部插入就是在双向链表中的最后一个节点与头结点之间插入新的节点,在单链表中,我们要遍历整个链表才能找到尾结点,但是在循环链表中就不用这么麻烦,因为哨兵位与尾结点是相连接的,我们可以通过哨兵位的front指针直接找到尾结点,这样一来就显得非常简单了,其实图示可以参考头部插入的图示,只用将哨兵位改成尾结点,第一个正式节点改成哨兵位即可,现在我们直接上代码:

void Push_Back(DListNode* phead, Elemtype data) { assert(phead); DListNode* newNode = Buy_Node(data); if (newNode == NULL) { printf("尾插节点创建失败...\n"); return; } //这时候就要创建尾巴节点,用于指向最后一个节点 DListNode* ptail = phead->front; //ptail newNode phead // newNode->front = ptail; newNode->next = phead; ptail->next = newNode; phead->front = newNode; }
要注意的依旧是,要优先处理新节点的两个指针与旧节点的关系,再将旧节点的相关指针指向新节点

2.4.3、查找pos位置的元素:

在进行写一个操作之前,我们要先做一个铺垫,先用一个函数来查找pos位置上的元素,看看pos位置上是否存在元素.这里我们用遍历的方法进行查找:

DListNode* Search_elem_for_pos(DListNode* phead, int pos) { assert(phead); int len = Get_DListlength(phead); if (pos<1 || pos>len) { printf("pos值不合法...\n"); return NULL; } DListNode* pcur = phead->next; for (int i = 1; i < pos; i++) { if (pcur->next == phead) { printf("pos位置没有元素...\n"); return NULL; } pcur = pcur->next; } return pcur; } 
这里我们将返回的值设计为指针类型,也就是如果找到了,可以直接获得这个元素的指针,以便后续操作的开展

2.4.4、pos位置插入:

2.4.4.1、pos位置之前插入:

在进行pos位置的相关操作之前,我们都是要进行一遍老步骤:判断pos值,判断pos位置是不是存在元素,如果存在元素,那就么pos位置之前插入就相当于头插,示意图与头插几乎一样,所以我们直接上代码:

void Push_pos_Front(DListNode* phead, Elemtype data, int pos) { assert(phead); int len = Get_DListlength(phead); if (pos<1 || pos>len) { printf("pos值不合法...\n"); return; } if (pos == 1) { Push_Front(phead, data); return; } DListNode* ppos = Search_elem_for_pos(phead, pos); if (ppos == NULL) { //Push_Front(phead, data); return; } //ppos->front newNode ppos else { DListNode* newNode = Buy_Node(data); if (newNode == NULL) return; newNode->next = ppos; newNode->front = ppos->front; ppos->front->next = newNode; ppos->front = newNode; } } 
要注意的是,如果pos值为1,那么就相当于头插,直接调用头插的函数即可

2.4.4.2、pos位置之后插入:

步骤与pos位置之前插入相同,如果pos位置存在元素,那么示意图就与尾尾插相似,那就直接上代码吧~~~~

void Push_pos_Back(DListNode* phead, Elemtype data, int pos) { assert(phead); int len = Get_DListlength(phead); if (pos<1 || pos>len) { printf("pos值不合法...\n"); return; } if (pos == 1) { Push_Back(phead, data); return; } DListNode* newNode = Buy_Node(data); if (newNode == NULL) { return; } DListNode* ppos = Search_elem_for_pos(phead, pos); if (ppos == NULL) { //Push_Back(phead, data); return; } //ppos newNode ppos->next newNode->next = ppos->next; newNode->front = ppos; ppos->next->front = newNode; ppos->next = newNode; }
如果pos值为1,那么就相当于尾插,像pos位置之前一样,直接调用尾插函数即可.

2.5、双向链表的删除操作:

删除操作与插入操作也一样,依旧是分头删,尾删,pos位置删除

2.5.1、头部删除:

头部删除指的是删除第一个正式节点,让哨兵位与第二个正式节点相连接,下面是是示意图:

在了解了示意图之后,我们直接上代码:

void Pop_Front(DListNode* phead) { assert(phead); int len = Get_DListlength(phead); if (len == 0) { printf("链表为空,无法删除...\n"); return; } //phead phead->next phead->next->next DListNode* delet = phead->next; phead->next = phead->next->next; phead->next->next->front = phead; free(delet); delet = NULL; }
要注意的是,在删除时对于指针的操作与增加时有所不同,在删除时是要先将不删除的两个节点先相连接,再free掉要删除的节点,最后要记得将delet指针置为NULL哦~~~

2.5.2、尾部删除:

与头部删除相类似,依旧是处理被删除节点与不删除节点之间的关系,我们直接上代码:

void Pop_Back(DListNode* phead) { assert(phead); int len = Get_DListlength(phead); if (len == 0) { printf("链表为空,无法删除...\n"); return; } DListNode* delet = phead->front; //delet->front delet phead; delet->front->next = phead; phead->front = delet->front; free(delet); delet = NULL; }
再三提醒,再free掉delet指针的内容后,要将delet指针置为NULL才行,不然会成为野指针

2.5.3、pos位置删除:

对链表而言,就没有pos之前或者之后删除了,直接就是指定的pos位置删除,删除的方式与头删尾删一样,无非就是为位置的不同罢了,话不多说,我们直接上代码:

void Pop_Pos(DListNode* phead, int pos) { assert(phead); int len = Get_DListlength(phead); if (pos<1 || pos>len) { printf("pos值不合法...\n"); return; } if (pos == 1) { Pop_Front(phead); return; } if (pos == len) { Pop_Back(phead); return; } //pos->front pos pos->next DListNode* delet = Search_elem_for_pos(phead, pos); if (delet == NULL) { return; } delet->front->next = delet->next; delet->next->front = delet->front; free(delet); delet = NULL; }
要注意的是,pos系列的操作一定要记得对pos值进行判断,以及特殊情况的处理,像pos==1或者pos==尾结点,这就要直接调用头删或者尾删了

2.6、双向链表的元素查找:

想要查找链表里面的元素,就要先求出当前链表的长度,看看长度是否为0,然后再用第一个正式节点开始遍历,查找链表中是否存在这个元素,有的话就输出"找到了",没有就输出"没找到",下面上代码:

void Search_elem(DListNode* phead, Elemtype data) { assert(phead); int len = Get_DListlength(phead); if (len == 0) { printf("当前链表为0,没有元素可以查找...\n"); return; } DListNode* pcur = phead->next; int pos = 1; while (pcur != phead) { if (pcur->data == data) { printf("找到了!!!\n"); return; } pcur = pcur->next; pos++; } printf("找不到...\n"); return; }

2.7、双向链表的修改:

想要修改某个位置的元素的值,就要先输入想修改的位置,记忆修改之后的数值,所以参数藜麦那就要含有pos以及data两个参数,然后再判断pos位置是否存在元素,不存在则无法进行修改:

void Change_elem(DListNode* phead, Elemtype data, int pos) { assert(phead); int len = Get_DListlength(phead); if (pos<1 || pos>len) { printf("pos值不合法...\n"); return; } DListNode* ppos = Search_elem_for_pos(phead, pos); if (ppos == NULL) { printf("想要修改的元素不存在\n"); return; } ppos->data = data; }

如果存在,直接修改就行.

2.8、双向链表的打印:

打印就更加简单了,直接遍历打印:

//现在是打印双向带头结点循环链表 void my_printf(DListNode* phead) { DListNode* pcur = phead->next; if (pcur == phead) { printf("当前链表内容为空...\n"); return; } while (pcur != phead) { printf("%d ", pcur->data); pcur = pcur->next; } } 

2.9、双向链表的销毁:

在做完一系列的操作之后,肯定是要对链表进行销毁的,我们就采用与打印相同的方法---遍历,逐个节点逐个节点进行销毁:

//现在是销毁链表 void Destory_list(DListNode* phead) { DListNode* pcur = phead->next; while (pcur != phead) { DListNode* delet = pcur; pcur = pcur->next; free(delet); delet = NULL; } free(phead); phead = NULL; } 

要注意的是,销毁完所有的节点之后,要记得将遍历的指针和哨兵位置为NULL.

以上就是关于带头循环双向链表基本操作的详解了,下面是所有代码的综合,有兴趣的朋友们可以看看~~~~~~

3、代码总和:

话不多说,直接上代码:

#define _CRT_SECURE_NO_WARNINGS 520 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #include<windows.h> #include<assert.h> //现在说的双向链表指的是双向带头循环链表 typedef int Elemtype; //现在定义双链表结构体 typedef struct DListNode { Elemtype data; //数据域 struct DListNode* front; struct DListNode* next; //指针域 }DListNode; //现在实现双向链表的基本操作: DListNode* Init_DListNode(DListNode* phead); int Get_DListlength(DListNode* phead); void Push_Front(DListNode* phead, Elemtype data); void Push_Back(DListNode* phead, Elemtype data); void Push_pos_Front(DListNode* phead, Elemtype data, int pos); void Push_pos_Back(DListNode* phead, Elemtype data, int pos); void Pop_Front(DListNode* phead); void Pop_Back(DListNode* phead); void Pop_Pos(DListNode* phead, int pos); DListNode* Search_elem_for_pos(DListNode* phead, int pos); void Search_elem(DListNode* phead, Elemtype data); void Change_elem(DListNode* phead, Elemtype data, int pos); //计算链表长度 int Get_DListlength(DListNode* phead) { DListNode* pcur = phead; int count = 0; if (pcur->next == phead) { return 0; } while (pcur->next != phead) { pcur = pcur->next; count++; } return count; } DListNode* Buy_Node(Elemtype data) { DListNode* newNode = (DListNode*)malloc(sizeof(DListNode)); if (newNode == NULL) { printf("新节点创建失败...\n"); return NULL; } newNode->next = newNode; newNode->data = data; newNode->front = newNode; return newNode; } DListNode* Init_DListNode() { DListNode* phead = Buy_Node(-1); //现在是创建头节点 if (phead == NULL) { printf("头节点创建失败...\n"); return NULL; } return phead; } void Push_Front(DListNode* phead, Elemtype data) { assert(phead); //先创建新节点 DListNode* newNode = Buy_Node(data); if (newNode == NULL) { printf("新的头插节点创建失败...\n"); return; } //phead newNode phead->next newNode->next = phead->next; newNode->front = phead; phead->next->front = newNode; phead->next = newNode; } void Push_Back(DListNode* phead, Elemtype data) { assert(phead); DListNode* newNode = Buy_Node(data); if (newNode == NULL) { printf("尾插节点创建失败...\n"); return; } //这时候就要创建尾巴节点,用于指向最后一个节点 DListNode* ptail = phead->front; //ptail newNode phead // newNode->front = ptail; newNode->next = phead; ptail->next = newNode; phead->front = newNode; } DListNode* Search_elem_for_pos(DListNode* phead, int pos) { assert(phead); int len = Get_DListlength(phead); if (pos<1 || pos>len) { printf("pos值不合法...\n"); return NULL; } DListNode* pcur = phead->next; for (int i = 1; i < pos; i++) { if (pcur->next == phead) { printf("pos位置没有元素...\n"); return NULL; } pcur = pcur->next; } return pcur; } void Push_pos_Front(DListNode* phead, Elemtype data, int pos) { assert(phead); int len = Get_DListlength(phead); if (pos<1 || pos>len) { printf("pos值不合法...\n"); return; } if (pos == 1) { Push_Front(phead, data); return; } DListNode* ppos = Search_elem_for_pos(phead, pos); if (ppos == NULL) { //Push_Front(phead, data); return; } //ppos->front newNode ppos else { DListNode* newNode = Buy_Node(data); if (newNode == NULL) return; newNode->next = ppos; newNode->front = ppos->front; ppos->front->next = newNode; ppos->front = newNode; } } void Push_pos_Back(DListNode* phead, Elemtype data, int pos) { assert(phead); int len = Get_DListlength(phead); if (pos<1 || pos>len) { printf("pos值不合法...\n"); return; } if (pos == 1) { Push_Back(phead, data); return; } DListNode* newNode = Buy_Node(data); if (newNode == NULL) { return; } DListNode* ppos = Search_elem_for_pos(phead, pos); if (ppos == NULL) { //Push_Back(phead, data); return; } //ppos newNode ppos->next newNode->next = ppos->next; newNode->front = ppos; ppos->next->front = newNode; ppos->next = newNode; } void Pop_Front(DListNode* phead) { assert(phead); int len = Get_DListlength(phead); if (len == 0) { printf("链表为空,无法删除...\n"); return; } //phead phead->next phead->next->next DListNode* delet = phead->next; phead->next = phead->next->next; phead->next->next->front = phead; free(delet); delet = NULL; } void Pop_Back(DListNode* phead) { assert(phead); int len = Get_DListlength(phead); if (len == 0) { printf("链表为空,无法删除...\n"); return; } DListNode* delet = phead->front; //delet->front delet phead; delet->front->next = phead; phead->front = delet->front; free(delet); delet = NULL; } void Pop_Pos(DListNode* phead, int pos) { assert(phead); int len = Get_DListlength(phead); if (pos<1 || pos>len) { printf("pos值不合法...\n"); return; } if (pos == 1) { Pop_Front(phead); return; } if (pos == len) { Pop_Back(phead); return; } //pos->front pos pos->next DListNode* delet = Search_elem_for_pos(phead, pos); if (delet == NULL) { return; } delet->front->next = delet->next; delet->next->front = delet->front; free(delet); delet = NULL; } void Change_elem(DListNode* phead, Elemtype data, int pos) { assert(phead); int len = Get_DListlength(phead); if (pos<1 || pos>len) { printf("pos值不合法...\n"); return; } DListNode* ppos = Search_elem_for_pos(phead, pos); if (ppos == NULL) { printf("想要修改的元素不存在\n"); return; } ppos->data = data; } //现在是打印菜单 void printf_menu() { printf("================================================================\n"); printf(" ***带头节点双向循环链表*** \n"); printf("插入:\n"); printf("1.头插 2.尾插 3.Pos位置之前插入 4.pos位置之后插入\n"); printf("删除:\n"); printf("5.头删 6.尾删 7.pos位置删除\n"); printf("其他:\n"); printf("8.查找 9.修改\n"); printf("================================================================\n"); printf("\n"); } void Search_elem(DListNode* phead, Elemtype data) { assert(phead); int len = Get_DListlength(phead); if (len == 0) { printf("当前链表为0,没有元素可以查找...\n"); return; } DListNode* pcur = phead->next; int pos = 1; while (pcur != phead) { if (pcur->data == data) { printf("找到了!!!\n"); return; } pcur = pcur->next; pos++; } printf("找不到...\n"); return; } //现在是打印双向带头结点循环链表 void my_printf(DListNode* phead) { DListNode* pcur = phead->next; if (pcur == phead) { printf("当前链表内容为空...\n"); return; } while (pcur != phead) { printf("%d ", pcur->data); pcur = pcur->next; } } //现在是销毁链表 void Destory_list(DListNode* phead) { DListNode* pcur = phead->next; while (pcur != phead) { DListNode* delet = pcur; pcur = pcur->next; free(delet); delet = NULL; } free(phead); phead = NULL; } int main() { //DListNode head; DListNode* phead = Init_DListNode(); int choose = 0; do { system("cls"); printf_menu(); printf("当前的链表为:\n"); my_printf(phead); printf("\n"); printf("请输入你的选择(按-1结束程序):\n"); scanf("%d", &choose); switch (choose) { case 1: { printf("请输入你想输入元素的个数:\n"); int num = 0; Elemtype data = 0; scanf("%d", &num); printf("请输入你想输入的元素:\n"); for (int i = 0; i < num; i++) { scanf("%d", &data); Push_Front(phead, data); } Sleep(1000); printf("插入成功!!!\n"); Sleep(2000); break; } case 2: { printf("请输入你想输入元素的个数:\n"); int num = 0; Elemtype data = 0; scanf("%d", &num); printf("请输入你想输入的元素:\n"); for (int i = 0; i < num; i++) { scanf("%d", &data); Push_Back(phead, data); } Sleep(1000); printf("插入成功!!!\n"); Sleep(2000); break; } case 3: { printf("请输入pos:\n"); int pos = 0; scanf("%d", &pos); Elemtype data = 0; printf("请输入你想输入的元素:\n"); scanf("%d", &data); Push_pos_Front(phead, data, pos); Sleep(1000); printf("插入成功!!!\n"); Sleep(2000); break; } case 4: { printf("请输入pos:\n"); int pos = 0; scanf("%d", &pos); Elemtype data = 0; printf("请输入你想输入的元素:\n"); scanf("%d", &data); Push_pos_Back(phead, data, pos); Sleep(1000); printf("插入成功!!!\n"); Sleep(2000); break; } case 5: { Pop_Front(phead); printf("删除成功!\n"); Sleep(2000); break; } case 6: { Pop_Back(phead); printf("删除成功!\n"); Sleep(2000); break; } case 7: { printf("请输入你想删除的位置:\n"); int pos = 0; scanf("%d", &pos); Pop_Pos(phead, pos); printf("删除成功!\n"); Sleep(2000); break; } case 8: { printf("请输入你想查找的元素:\n"); Elemtype data = 0; scanf("%d", &data); Search_elem(phead, data); Sleep(2000); break; } case 9: { printf("请输入你向修改之后的元素:\n"); Elemtype data = 0; scanf("%d", &data); printf("请输入你想修改的位置:\n"); int pos = 0; scanf("%d", &pos); Change_elem(phead, data, pos); printf("修改成功!\n"); Sleep(2000); break; } case -1: { printf("正在退出程序...\n"); Sleep(2000); printf("退出成功!!!\n"); Sleep(2000); break; } } } while (choose != -1); Destory_list(phead); return 0; }

以上就是我对单链表所有内容的分享了,感谢大佬们的阅读~~~

文章是自己写的哈,有啥描述不对的、不恰当的地方,恳请大佬指正,看到后会第一时间修改,感谢您的阅读。

Read more

排序(数据结构)

排序(数据结构)

一. 排序概念及运用 排序在数据结构中是非常重要的一部分,所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。 在生活中也有很多的应用,比如当我们搜索一款产品时候,我们可以选择按销量多少的顺序来给我们推荐产品,也可以按照价格高低来给我们推荐产品,所以排序在生活中也是很常见的。 1.1插入排序 (1)直接插入排序 上面就是一些常见的排序算法,首先我们来认识一下插入排序,插入排序又分为直接插入排序和希尔排序,直接插入排序是比较好理解的,比如我们日常生活中的扑克牌游戏,当我们拿到牌的时候我们会习惯性的直接将牌按我们想要的顺序排列,如下:   那么希尔排序又是怎么回事呢? 我还是用一张清晰的思路图来向大家展示: void InitSort(int* arr, int n) { for (int i = 0; i < n-1; i++) { int end = i; int tmp = arr[end + 1]; while (end >

By Ne0inhk
2026 前端 / 后端 / 算法岗 AI 技能清单,直接对标大厂

2026 前端 / 后端 / 算法岗 AI 技能清单,直接对标大厂

2026 大厂前端岗 AI 技能清单 核心基础技能 * 大模型前端适配能力:掌握大模型上下文管理,实现对话历史的高效存储与加载,适配流式输出的前端渲染逻辑。 * AI 组件开发:熟练开发基于大模型的智能组件,如代码补全、智能问答、内容生成类组件,支持参数化配置与多模型切换。 * 向量数据库集成:掌握 Pinecone、Weaviate 等向量数据库的前端调用方法,实现语义搜索、相似内容推荐等功能。 进阶实践技能 * 大模型微调适配:理解大模型微调原理,能够基于前端业务场景,将微调后的模型部署至前端环境,实现模型轻量化调用。 * 多模态交互开发:支持文本、图像、音频等多模态输入的前端处理,对接多模态大模型 API 实现智能交互。 * AI 性能优化:实现大模型请求的批量处理、缓存复用与增量更新,降低前端请求延迟与资源消耗。 实战代码示例 以下为基于 OpenAI API 实现的流式对话前端组件,使用 React 18 开发:

By Ne0inhk
基于阿基米德算法的AOA - LSSVM回归预测:提升LSSVM准确率新思路

基于阿基米德算法的AOA - LSSVM回归预测:提升LSSVM准确率新思路

基于阿基米德算法的LSSVM回归预测AOA-LSSVM 其他优化算法可私信定制 为了提高最小二乘支持向量机(lssvm)的回归预测准确率,对lssvm中的惩罚参数和核惩罚参数利用麻雀搜索算法进行优化。 Matlab 代码 在机器学习的领域中,最小二乘支持向量机(LSSVM)一直是回归预测的有力工具。然而,为了进一步挖掘其潜力,提升回归预测的准确率,对LSSVM中的惩罚参数和核惩罚参数的优化就显得尤为重要。今天咱们就来聊聊基于阿基米德算法的AOA - LSSVM,并且看看怎么用麻雀搜索算法来优化相关参数。 为什么要优化LSSVM参数 LSSVM的性能很大程度上依赖于惩罚参数(通常用$C$表示)和核惩罚参数(比如高斯核函数中的$\sigma$ )。不合适的参数会导致模型要么过拟合(对训练数据拟合得太好,对新数据泛化能力差),要么欠拟合(无法很好捕捉数据中的规律)。所以,找到一组最优的参数至关重要。 麻雀搜索算法优化LSSVM参数 麻雀搜索算法是一种受麻雀觅食行为启发的智能优化算法。它模拟了麻雀在觅食过程中的发现者 - 追随者机制以及警戒机制。通过这种方式,在参数空间中搜索能使

By Ne0inhk
【优选算法必刷100题】第39-40题(模拟):替换所有问号,提莫攻击

【优选算法必刷100题】第39-40题(模拟):替换所有问号,提莫攻击

🔥个人主页:Cx330🌸 ❄️个人专栏:《C语言》《LeetCode刷题集》《数据结构-初阶》《C++知识分享》 《优选算法指南-必刷经典100题》《Linux操作系统》:从入门到入魔 《Git深度解析》:版本管理实战全解 🌟心向往之行必能至 🎥Cx330🌸的简介: 目录 前言: 39.替换所有问号 算法原理(模拟): 思路: 模拟解法代码(C++): 博主手记(字体还请见谅哈): 40.提莫攻击 解法(模拟+分情况讨论): 算法思路: C++算法代码: 博主手记(字体还请见谅哈): 总结: 前言: 聚焦算法题实战,系统讲解三大核心板块:“精准定位最优解”——优选算法,“简化逻辑表达,系统性探索与剪枝优化”——递归与回溯,“以局部最优换全局高效”——贪心算法,讲解思路与代码实现,帮助大家快速提升代码能力

By Ne0inhk