数据结构与算法--顺序表--单链表
一 顺序表
- 需要指向存储位置的基地址
- 分配一段连续的内存
- 用length记录实际的元素的个数,也即顺序表的长度,因为顺序表是允许删除和插入元素的
- 不需要定义数组
1.1 普通结构体数组实现版本,实现白色的点以一定的步长移除画面,大量for循环,并且由于数组内部数据需要去除的点并不是连续的,就需要每次从0遍历到数组的结尾,但是实际上,已经消失的点可以不用再进行循环和判断
#include <iostream>
#include <exception>
#include <stdexcept>
#include "string"
#include <fstream>
#include<conio.h>
#include<Windows.h>
#include <graphics.h>#define SCREEN_WIDTH 654
#define SCREEN_HEIGHT 480
#define STAR_MAX_NUM 100
#define MAX_STEP 2
#define MAX_STAR_RADIUS 3
#define BOTTOM_MARGIN 100
#define IMG_SIZE 50enum STATUS {STOP=0,UP,DOWN,LEFT,RIGHT,RANDON
};struct STAR {int x;int y;unsigned radius;int step; //每次走的间隔int color;bool alive;enum STATUS stat;
}star[STAR_MAX_NUM];void initStar(int i) {//初始化星星star[i].x = rand() % SCREEN_WIDTH;star[i].y = rand() % (SCREEN_HEIGHT - IMG_SIZE);star[i].step = rand() % MAX_STEP + 1;int rgb = 0;rgb = rand() % 255;star[i].color = RGB(rgb, rgb, rgb);star[i].radius = rand() % MAX_STAR_RADIUS;setfillcolor(star[i].color);solidcircle(star[i].x, star[i].y, star[i].radius);star[i].alive = true;
}void eraseStar(int i) {for (int i = 0; i < STAR_MAX_NUM; i++) {//擦除原来的星星setfillcolor(BLACK);solidcircle(star[i].x, star[i].y, star[i].radius);if (star[i].alive && (star[i].y - star[i].step) >0) {star[i].y = star[i].y - star[i].step;setfillcolor(star[i].color);solidcircle(star[i].x, star[i].y, star[i].radius);}else {star[i].alive = false;}}
}//判断画面里面还有没有星星
bool hasStar() {for (int i = 0; i < STAR_MAX_NUM; i++) {if (star[i].alive == true) {return true;break;}}return false;
}int main() {initgraph(SCREEN_WIDTH, SCREEN_HEIGHT);IMAGE bg_img;loadimage(&bg_img, _T("y3.png"), IMG_SIZE, IMG_SIZE, true);putimage(int(SCREEN_WIDTH * 0.3), SCREEN_HEIGHT - IMG_SIZE, &bg_img);putimage(int(SCREEN_WIDTH * 0.7), SCREEN_HEIGHT - IMG_SIZE, &bg_img);//绘制星星for (int i = 0; i < STAR_MAX_NUM; i++) {initStar(i);}//消除星星,并不是直接擦除,是以一定的步长走出画面的int i = 0;while(hasStar()) {for (int i = 0; i < STAR_MAX_NUM; i++) {eraseStar(i);}Sleep(100);}system("pause");return 0;
}
1.2 顺序表实现
- 插入元素,插入位置不能小于0,也不能大于当前数组长度;还需要判断数组是不是满了,如果满了就不能再插入;从最后一个元素开移动
- 添加元素:判断空间有没有满即可
定义顺序:
- (1) 定义一个结构体,包含顺序表的首地址,内存大小,以及实际元素个数
typedef struct _OrderList Olist; //定义结构体的别名
struct _OrderList {int* firstElement; //顺序表的首地址int elemNum; //档期那表里的元素int size; //顺序表分配的空间,也就是连续内存的大小
};
- (2)为结构体分配内存空间
1.2.1 结构体别名问题 ,定义结构体的别名,可能有时候名字太长了typedef
typedef struct _OrderList Olist; //定义结构体的别名,可能有时候名字太长了struct _OrderList {int* firstElement; //顺序表的首地址int elemNum; //档期那表里的元素int size; //顺序表分配的空间,也就是连续内存的大小
};
typedef struct {int* firstElement; //顺序表的首地址int elemNum; //档期那表里的元素int size; //顺序表分配的空间,也就是连续内存的大小
}Olist;
1.2.2 顺序表可以直接list.elems[i]
来访问数组,数组名本质上是指向数组第一个元素的指针。因此,elems 作为 int* 类型,可以像数组一样使用下标操作符 [] 来访问元素。类似于函数形参,void print(int *array) 和 void print(int array[])
一样
elems[i] 等价于 *(elems + i),即通过指针算术运算访问第 i 个元素的值
void listPrint(Olist& list) {cout << "顺序表元素个数" << list.elemNum << ", 顺序表空间:" << list.size << endl;for (int i = 0; i < list.elemNum; i++) {cout << list.elems[i] << " ";}cout << endl;
}
1.2.3 连续输入数据 cout << "\n请输入要插入的位置和元素:"; cin >> pos >> e;
#include <iostream>
#include <exception>
#include <stdexcept>
#include "string"
#include <fstream>
#include<conio.h>
#include<Windows.h>
#include <graphics.h>using namespace std;
#define MAX_SIZE 20typedef struct _OrderList Olist; //定义结构体的别名
struct _OrderList {int* elems; //顺序表的首地址int elemNum; //表里的元素个数int size; //顺序表分配的空间,也就是连续内存的大小
};void listPrint(Olist& list) {cout << "\n顺序表元素个数" << list.elemNum << ", 顺序表空间:" << list.size << endl;for (int i = 0; i < list.elemNum; i++) {cout << list.elems[i] << " ";}cout << endl;
}bool init(Olist& list) {//初始是没有元素的,为首地址元素分配空间其实就是为顺序表分配空间list.elems = new int[MAX_SIZE];if (!list.elems) {return false;}list.elemNum = 0;list.size = MAX_SIZE;return true;
}bool appendList(Olist& list, int ele) {if (list.elemNum == list.size) {cout << "顺序表已经满了,不能再插入" << endl;return false;}list.elems[list.elemNum] = ele; //能这样做是因为地址是连续的list.elemNum++;return true;
}bool insertList(Olist& list, int position, int ele) {if (list.elemNum == list.size) {cout << "顺序表已经满了,不能再插入" << endl;return false;}if (position < 0 || position >= list.elemNum) {cout << "插入位置不合法" << endl;return false;}for (int i = list.elemNum - 1; i >= position; i--) {list.elems[i + 1] = list.elems[i];}list.elems[position] = ele;list.elemNum++;return true;
}bool deleteList(Olist& list, int position)
{if (list.elemNum == 0 || position < 0 || position >= list.elemNum) {cout << "删除位置不合法" << endl;return false;}list.elems[position] = -1;for (int i = position; i < list.elemNum-1; i++) {list.elems[i] = list.elems[i+1];}list.elemNum--;return true;
}void destroyList(Olist& list) {if (list.elems) delete[] list.elems;list.size = 0;list.elemNum = 0;
}int main() {Olist list;///cout << "初始化顺序表" << endl;if (!init(list)) {cout << "顺序表内存分配失败" << endl;return 0;}listPrint(list);///int count = 0;int e;cout << "请输入要添加的元素个数:";cin >> count;for (int i = 0; i < count; i++) {cout << "\n请输入要添加的元素:";cin >> e;appendList(list,e);}listPrint(list);/int pos;cout << "\n请输入要插入的位置和元素:";cin >> pos >> e; if (insertList(list, pos, e)){cout << "插入成功" << endl;}else {cout << "插入失败" << endl;}listPrint(list);///cout << "\n请输入要删除的位置";cin >> pos;if (deleteList(list, pos)){cout << "删除成功" << endl;}else {cout << "删除失败" << endl;}listPrint(list);destroyList(list);return 0;
}
1.3 顺序表优化星星消除。什么时候使用顺序表:频繁的遍历所有元素。顺序表存储数据都是相邻的。
知识点1:防止头文件重复包含
#ifndef _SATR_H_
#define _SATR_H_。。。。
#endif
知识点2:顺序表的数据类型可以任意定义,顺序表本质是一个结构体,给的是一个结构体首地址,然后初始化的时候分配内存空间。而当前案例里面,星星本身也是一个结构体,因此顺序表里面的数据类型变成了结构体,Olist starList; //初始化一个顺序表,对应是首地址,存放第一颗星星
,struct STAR star;
创建的只是一颗星星,当前案例是在starList
顺序表里面存放多颗星星,所以传入数据void eraseStar(Olist& list, int i)
是顺序表时,访问顺序表里面的每一颗星星,需要先通过顺序表访问每一个对象,再访问对象本身的属性list.elems[i].alive
//定义顺序表,存储多个星星
typedef struct _OrderList Olist; //定义结构体的别名
struct _OrderList {struct STAR* elems; //顺序表的首地址int elemNum; //表里的元素个数int size; //顺序表分配的空间,也就是连续内存的大小
};
知识点3:删除顺序表里面的元素的的时候,是在void eraseStar(Olist& list, int i)
函数里面调用了deleteList(list,i);
进行元素的删除,而 不是 直接在主函数里面做如下操作,因为每一次消除星星,并不是直接擦除,是以一定的步长走出画面的,如果做如下操作,逻辑不对,走出画面的星星才擦除,而不是直接擦除
int i = 0;while(starList.elemNum) {for (int i = 0; i < starList.elemNum; i++) {eraseStar(starList,i);deleteList(list,i);}Sleep(200);}
code
star.h
#pragma once
#ifndef _SATR_H_
#define _SATR_H_#define SCREEN_WIDTH 654
#define SCREEN_HEIGHT 480
#define STAR_MAX_NUM 100
#define MAX_STEP 2
#define MAX_STAR_RADIUS 3
#define BOTTOM_MARGIN 100
#define IMG_SIZE 50enum STATUS {STOP = 0,UP,DOWN,LEFT,RIGHT,RANDON
};//定义星星结构体对象,描述一颗星星
struct STAR {int x;int y;unsigned radius;int step; //每次走的间隔int color;bool alive;enum STATUS stat;
};//定义顺序表,存储多个星星
typedef struct _OrderList Olist; //定义结构体的别名
struct _OrderList {struct STAR* elems; //顺序表的首地址int elemNum; //表里的元素个数int size; //顺序表分配的空间,也就是连续内存的大小
};void listPrint(Olist& list);
bool init(Olist& list);
bool appendList(Olist& list, struct STAR ele);
bool deleteList(Olist& list, int position);
void destroyList(Olist& list);
#endif
star.cpp
#include "star.h"
#include <iostream>using namespace std;void listPrint(Olist& list) {cout << "\n顺序表元素个数" << list.elemNum << ", 顺序表空间:" << list.size << endl;
}bool init(Olist& list) {//初始是没有元素的,为首地址元素分配空间其实就是为顺序表分配空间list.elems = new struct STAR[STAR_MAX_NUM];if (!list.elems) {return false;}list.elemNum = 0;list.size = STAR_MAX_NUM;return true;
}bool appendList(Olist& list, struct STAR ele) {if (list.elemNum == list.size) {cout << "顺序表已经满了,不能再插入" << endl;return false;}list.elems[list.elemNum] = ele; //能这样做是因为地址是连续的list.elemNum++;return true;
}bool deleteList(Olist& list, int position)
{if (list.elemNum == 0 || position < 0 || position >= list.elemNum) {cout << "删除位置不合法" << endl;return false;}for (int i = position; i < list.elemNum - 1; i++) {list.elems[i] = list.elems[i + 1];}list.elemNum--;return true;
}void destroyList(Olist& list) {if (list.elems) delete[] list.elems;list.size = 0;list.elemNum = 0;
}
mian
#include <iostream>
#include <exception>
#include <stdexcept>
#include "string"
#include <fstream>
#include<conio.h>
#include<Windows.h>
#include <graphics.h>
#include "star.h"void initStar(struct STAR &star) {//初始化星星star.x = rand() % SCREEN_WIDTH;star.y = rand() % (SCREEN_HEIGHT - IMG_SIZE);star.step = rand() % MAX_STEP + 1;int rgb = 0;rgb = rand() % 255;star.color = RGB(rgb, rgb, rgb);star.radius = rand() % MAX_STAR_RADIUS;setfillcolor(star.color);solidcircle(star.x, star.y, star.radius);star.alive = true;
}void eraseStar(Olist& list, int i) {for (int i = 0; i < list.elemNum; i++) {//擦除原来的星星setfillcolor(BLACK);solidcircle(list.elems[i].x, list.elems[i].y, list.elems[i].radius);if (list.elems[i].alive && (list.elems[i].y - list.elems[i].step) > 0) {list.elems[i].y = list.elems[i].y - list.elems[i].step;setfillcolor(list.elems[i].color);solidcircle(list.elems[i].x, list.elems[i].y, list.elems[i].radius);}else {list.elems[i].alive = false;deleteList(list,i);}}
}int main() {initgraph(SCREEN_WIDTH, SCREEN_HEIGHT);IMAGE bg_img;loadimage(&bg_img, _T("y3.png"), IMG_SIZE, IMG_SIZE, true);putimage(int(SCREEN_WIDTH * 0.3), SCREEN_HEIGHT - IMG_SIZE, &bg_img);putimage(int(SCREEN_WIDTH * 0.7), SCREEN_HEIGHT - IMG_SIZE, &bg_img);Olist starList; //初始化一个顺序表,对应是首地址,存放第一颗星星struct STAR star;init(starList);//绘制星星for (int i = 0; i < STAR_MAX_NUM; i++) {initStar(star);appendList(starList, star);}//消除星星,并不是直接擦除,是以一定的步长走出画面的int i = 0;while(starList.elemNum) {for (int i = 0; i < starList.elemNum; i++) {eraseStar(starList,i);}Sleep(200);}system("pause");return 0;
}
1.4 企业应用案例:顺序表管理并剔除超时连接。
connect.h
#pragma once
#ifndef _CONNECT_H_
#define _CONNECT_H_#define SCREEN_WIDTH 654
#define SCREEN_HEIGHT 480
#define STAR_MAX_NUM 10
#define MAX_STEP 2
#define MAX_STAR_RADIUS 3
#define BOTTOM_MARGIN 100
#define IMG_SIZE 50struct ConnectOut {int fd; unsigned int timeout;
};//定义顺序表,存储多个超时连接
typedef struct _OrderList Olist; //定义结构体的别名
struct _OrderList {struct ConnectOut* elems; //顺序表的首地址int elemNum; //表里的元素个数int size; //顺序表分配的空间,也就是连续内存的大小
};void listPrint(Olist& list);
bool init(Olist& list);
bool appendList(Olist& list, struct ConnectOut ele);
bool deleteList(Olist& list, int position);
void destroyList(Olist& list);
#endif
connect.cpp
#include "connect.h"
#include <iostream>using namespace std;void listPrint(Olist& list) {cout << "\n顺序表元素个数" << list.elemNum << ", 顺序表空间:" << list.size << endl;for (int i = 0; i < list.elemNum; i++) {cout << "[" << list.elems[i].fd << "] = " << list.elems[i].timeout << endl;}
}bool init(Olist& list) {//初始是没有元素的,为首地址元素分配空间其实就是为顺序表分配空间list.elems = new struct ConnectOut[STAR_MAX_NUM];if (!list.elems) {return false;}list.elemNum = 0;list.size = STAR_MAX_NUM;return true;
}bool appendList(Olist& list, struct ConnectOut ele) {if (list.elemNum == list.size) {cout << "顺序表已经满了,不能再插入" << endl;return false;}list.elems[list.elemNum] = ele; //能这样做是因为地址是连续的list.elemNum++;return true;
}bool deleteList(Olist& list, int position)
{if (list.elemNum == 0 || position < 0 || position >= list.elemNum) {cout << "删除位置不合法" << endl;return false;}for (int i = position; i < list.elemNum - 1; i++) {list.elems[i] = list.elems[i + 1];}list.elemNum--;return true;
}void destroyList(Olist& list) {if (list.elems) delete[] list.elems;list.size = 0;list.elemNum = 0;
}
#include <iostream>
#include <exception>
#include <stdexcept>
#include "string"
#include <fstream>
#include<conio.h>
#include<Windows.h>
#include <graphics.h>
#include "connect.h"
#include <time.h>using namespace std;
void checkConnectOut(Olist &list, time_t now);int main() {time_t now, end, last_timeout;time(&now);end = now + 60;last_timeout = now;Olist list;struct ConnectOut ConOut;init(list);//随机模拟超时for (int i = 0; i < 10; i++) {ConOut.fd = i;ConOut.timeout = now + 5 + 2 * i;appendList(list, ConOut);}listPrint(list);do{//cout << "last_timeout = " << last_timeout << ", now = " << now << endl;//每隔一秒检查一次是否有超时,说明上一次到现在已经过去1秒了if (last_timeout + 0.999 < now) {checkConnectOut(list, now);last_timeout = now;}time(&now);} while (now < end); //检查指定时间内的超时连接destroyList(list);Sleep(10);system("pause");return 0;
}void checkConnectOut(Olist& list, time_t now) {cout << "超时检查。。。。。\n";for (int i = 0; i < list.elemNum; i++) {if (list.elems[i].timeout > now) {continue; // 直接进入下一次循环}cout << "[" << list.elems[i].fd << "] 超时,已关闭..." << endl;deleteList(list, i);i--;}
}
二 单链表:可以让删除和插入元素时,尽可能地移动较少的数据
- 顺序表存在的问题:如果数据太多,删除或移动靠前的数据,后面的所有的数据都需要移动
- LinkList用于表示首节点,LinkNode用于表示其余的节点
- 链表的核心理解:每个节点本身就占据一个地址,同时地址内存存了下一个节点的地址
- 单链表头节点一般不存数据,指针指向下一个元素,尾节点指针为NULL,链表只能通过上一个节点才能知道下一个节点,不像顺序表,顺序表可以根据索引直接推断出元素位置
2.1 头插法和尾插法,头插法,先进入的存在最后面,尾插入法,先进入的存在最里面
2.1.1 为什么传递链表的时候,传递的是LinkList*&
,传递指针本身已经能修改内容了:主要是为了在函数内部能够 修改指针本身的值list = new LinkList;
,而不仅仅是修改指针指向的内容。其他插入打印等函数可以只使用指针而不使用指针的引用
void init(LinkList* &list) { list = new LinkList;if (!list){cout << "初始化内存分配失败" << endl;return;}list->data = -1;list->next = NULL;
}```3
1```bash
void init(LinkList* list) {list = new LinkList; 修改的是局部副本,外部指针不变list->next = nullptr;
}int main() {LinkList* myList = nullptr;init(myList); myList 仍然是 nullptr,没有被初始化!// ...
}
2.1.2 主函数里面,LinkList* list = NULL;
只是初始化头节点为空指针,在插入的时候,没插入一个数据,都需要node = new LinkNode;
分配新的内存空间来存放数据
int main() {LinkList* list = NULL;LinkNode* node = NULL;init(list);int num;int number;cout << "请输入要插入的数据个数:";cin >> num;cout << " ------------ 头插法---------" << endl;for (int i = 0; i < num; i++) {node = new LinkNode;cout << "请输入第" << i+1 << "个元素:";cin >> node->data;insert_head(list, node);}printList(list);
2.2 任意位置插入元素
//p = list->next; 1 3 5 ,在第2个位置插入4 ,将会变成1 3 4 5p = list; 1 3 5 ,在第2个位置插入4 ,将会变成1 4 3 5
bool insert(LinkList*& list, LinkNode* node, int pos) {LinkNode* p = NULL;//p = list->next;p = list;int counter = 0;//循环遍历找到pos位置的节点while (p && counter < pos-1) {p = p->next;counter++;};//索引超出有效范围if (!p || counter > pos - 1) {cout << "插入位置超出有效范围" << endl;return false;}node->next = p->next;p->next = node;return true;
}
2.3 获取指定位置的元素
2.3.1 为什么下列调用,只有在函数里面能正确打印node的值,在主函数里面无法正确打印,而其他函数形参也是LinkNode* node
,却能实现数据插入链表bool insert(LinkList*& list, LinkNode* node, int pos)
。和前面的原因一样,因为bool getElem(LinkList*& list, int pos, LinkNode* node)
函数在函数内部对指针本身进行了修改, node = p->next;
,而insert
函数内部只是修改 node->next = p->next; p->next = node;
指针指向的值,而没有修改指针本身,要修改指针本身,就需要传递指针的引用 ,或者下面的方式
- 简单来说:函数形参传递指针,函数内部只能修改指针指向的值,而无法修改指针本身的地址,正确用法bool getElem(LinkList*& list, int pos, LinkNode* &node)
--------------------------主函数---------------------------cout << " ------------ 取指定位置元素---------" << endl;int pos;while (1) {node = new LinkNode;cout << "请输入要取的元素的位置";cin >> pos ;getElem(list, pos, node);printList(list);//cout << "位置" << pos << "处的元素是" << node->data << endl;}bool getElem(LinkList*& list, int pos, LinkNode* node) {if (!list || !list->next) {return false;}LinkNode* p = NULL;int counter = 1;p = list;while (p && counter < pos) {p = p->next;counter++;}//索引超出有效范围if (!p || counter > pos) {cout << "选取元素位置超出有效范围" << endl;return false;}node = p->next;return true;}
2.4 完整程序
#include <iostream>
#include <exception>
#include <stdexcept>
#include "string"
#include <fstream>
#include<conio.h>
#include<Windows.h>
#include <graphics.h>
#include <time.h>using namespace std;typedef struct LinkNode {int data;struct LinkNode* next; //指向下一个节点的指针
}LinkList,LinkNode; //LinkList表示初始节点void init(LinkList*& list);
bool insert_head(LinkList*& list, LinkNode* node);
bool insert_end(LinkList*& list, LinkNode* node);
bool insert(LinkList*& list, LinkNode* node, int pos);
void printList(LinkList*& list);
bool getElem(LinkList*& list,int pos, LinkNode* &node); //链表,取第几个元素,将值给node传出来
bool findElem(LinkList*& list, int elem, int &index); //按值查找,链表,查找元素
bool deleteElem(LinkList*& list,int pos);
void LinkDestroy(LinkList*& list);int main() {LinkList* list = NULL;LinkNode* node = NULL;init(list);int num;int number;cout << "请输入要插入的数据个数:";cin >> num;cout << " ------------ 头插法---------" << endl;for (int i = 0; i < num; i++) {node = new LinkNode;cout << "请输入第" << i+1 << "个元素:";cin >> node->data;insert_head(list, node);}printList(list);cout << " ------------ 尾插法---------" << endl;for (int i = 0; i < num; i++) {node = new LinkNode;cout << "请输入第" << i + 1 << "个元素:";cin >> node->data;insert_end(list, node);}printList(list);cout << " ------------ 指定位置插入---------" << endl;int pos;while (1) {node = new LinkNode;cout << "请输入要插入的位置和数据";cin >> pos >> node->data;insert(list, node, pos);printList(list);}cout << " ------------ 取指定位置元素---------" << endl;int pos;while (1) {node = new LinkNode;cout << "请输入要取的元素的位置";cin >> pos ;getElem(list, pos, node);printList(list);cout << "位置" << pos << "处的元素是" << node->data << endl;}cout << " ------------ 按值查元素,并返回位置---------" << endl;int value, index;while (1) {node = new LinkNode;cout << "请输入要查找的元素";cin >> value;printList(list);if (findElem(list, value, index)) {cout << value << "位置" << index << endl;}else {cout << "元素不存在" << endl;}}cout << " ------------ 删除元素---------" << endl;int index;while (1) {node = new LinkNode;cout << "请输入要删除的元素位置";cin >> index;printList(list);if (deleteElem(list, index)) {cout << index << "位置删除成公" << endl;printList(list);}else {cout << "元素不存在" << endl;}}LinkDestroy(list);printList(list);system("pause");return 0;
}bool deleteElem(LinkList*& list, int pos) {if (!list || !list->next) {cout << "链表为空" << endl;return false;}LinkNode* p = NULL;p = list;int counter = 0;while (p && counter < pos-1) {p = p->next;cout << p->data << " ";counter++;}if (!p || counter > pos-1) {cout << "删除位置不合法" << endl;return false;}LinkNode* temp = NULL; //用来存要删除的节点,最后要将其delete,因为在主函数里面是通过new建立的链表temp = p->next;p->next = temp->next;delete temp;return true;
}void LinkDestroy(LinkList*& L) {LinkNode* temp = NULL; //用于存放即将删除的节点temp = L;while (L) {L = L->next;delete temp;temp = L;}
}bool findElem(LinkList*& list, int elem, int& index) {if (!list || !list->next) {index = -1;return false;}LinkNode* p = NULL;int counter = 1;p = list->next;while (p && p->data != elem) {p = p->next;counter++;}if (!p) {return false;}index = counter;return true;
}bool getElem(LinkList*& list, int pos, LinkNode* &node) {if (!list || !list->next) {return false;}LinkNode* p = NULL;int counter = 1;p = list;while (p && counter < pos) {p = p->next;counter++;}//索引超出有效范围if (!p || counter > pos) {cout << "选取元素位置超出有效范围" << endl;return false;}node = p->next;return true;}void init(LinkList*& list) { list = new LinkList;if (!list){cout << "初始化内存分配失败" << endl;return;}list->data = -1;list->next = NULL;
}bool insert_head(LinkList*& list, LinkNode* node) {if (!list || !node) {cout << "内存分配失败" << endl;return false;}node->next = list->next;list->next = node;return true;
}void printList(LinkList*& list) {LinkNode* p = NULL;if (!list) {cout << "链表为空" << endl;return;}p = list->next;do {cout << p->data << " ";p = p->next;}while(p);cout << endl;
}bool insert_end(LinkList*& list, LinkNode* node) {if (!list || !node) {cout << "内存分配失败" << endl;return false;}LinkNode* p = NULL;p = list->next;while(p->next) {p = p->next;};node->next = NULL;p->next = node;return true;
}bool insert(LinkList*& list, LinkNode* node, int pos) {LinkNode* p = NULL;//p = list->next;p = list;int counter = 0;//循环遍历找到pos位置的节点while (p && counter < pos-1) {p = p->next;counter++;};//索引超出有效范围if (!p || counter > pos - 1) {cout << "插入位置超出有效范围" << endl;return false;}node->next = p->next;p->next = node;return true;
}
相关文章:
数据结构与算法--顺序表--单链表
一 顺序表 需要指向存储位置的基地址分配一段连续的内存用length记录实际的元素的个数,也即顺序表的长度,因为顺序表是允许删除和插入元素的不需要定义数组 1.1 普通结构体数组实现版本,实现白色的点以一定的步长移除画面,大量fo…...
MATLAB安装全攻略:常见问题与解决方案
MATLAB安装常见问题与解决方案 一、系统兼容性验证 安装前需确认操作系统满足MATLAB版本要求: Windows 10版本1903及以上(64位)macOS Monterey 12.6及以上Ubuntu 22.04 LTS及以上 验证命令示例: # Linux系统验证 lsb_release…...
constexpr 关键字的意义(入门)
author: hjjdebug date: 2025年 05月 15日 星期四 16:03:33 CST description: constexpr 关键字的意义(入门) constexpr 是c11 引入的一个关键字, 代表了一种属性. 文章目录 1. constexpr 修饰的变量, 在编译期间就可以得到其数值.2. constexpr 修饰的函数, 可以在编译期间被调…...
aptitude 深度教程:从基础到生产实践
目录 一、aptitude 基础:核心概念与环境准备 1.1 aptitude 是什么? 1.2 安装与环境配置 二、aptitude 核心操作:从命令行到交互式界面 2.1 命令行基础操作 2.2 交互式界面(TUI)入门 三、高级功能:依赖管理与版本控制 3.1 依赖冲突解决实战 3.2 版本锁定与降级 3…...
嵌入式开发学习日志(数据结构--双链表)Day21
一、双链表 1.定义 双向链表是在单链表的每个结点中,再设置一个指向其钱去节点的指针域。 2、声明文件 3、创建表头 4、头插 5、 遍历 6、尾插、 7、指定插 8、查找 9、修改 10.、删除 11、逆序 12、销毁链表 13、main.c 三、扩展:工程管理工具&#…...
抢购Python代码示例与技术解析
引言:抢购系统的技术挑战 在当今电子商务高度发达的时代,抢购活动已成为各大电商平台吸引用户的重要手段。然而,高并发、低延迟的抢购场景对系统设计提出了严峻挑战。本文将提供一个完整的Python抢购代码示例,并深入分析其技术实…...
undefined reference to CPUAllocatorSingleton::instance
它发生的原因是你声明了 CPUAllocatorSingleton 类中的 instance 变量,但没有提供它的定义。 这个错误是链接器无法找到 CPUAllocatorSingleton::instance 的定义。它发生的原因是你声明了 CPUAllocatorSingleton 类中的 instance 变量,但没有提供它的定…...
【c语言】动态内存分配
文章标题 一、为什么要进行动态内存管理二、malloc和free2.1. malloc2.2. free2.3. 举例 三、calloc和realloc3.1. calloc3.2. realloc 四、常见的动态内存错误4.1. 对NULL指针的解引用操作4.2. 对动态开辟空间的越界访问4.3. 对非动态开辟内存使用free释放4.4. 使用free释放⼀…...
深入理解JavaScript中的闭包:原理、应用与常见问题
引言 闭包(Closure)是JavaScript中一个既强大又容易让人困惑的概念。理解闭包对于成为一名优秀的JavaScript开发者至关重要。本文将深入探讨闭包的工作原理、实际应用场景以及常见问题,帮助你彻底掌握这一重要概念。 什么是闭包? 闭包是指那些能够访问…...
IPLOOK | 2025 MVNOs 世界大会:从Wi-Fi通话到卫星覆盖
2025 MVNOs 世界大会于5月12日至14日在奥地利维也纳举行,汇聚了来自50多个国家的550余位行业领袖,共同探讨移动虚拟网络运营商(MVNO)领域的变革趋势。本届大会聚焦数字化转型、技术创新与战略合作,其中IPLOOK凭借其创新…...
为什么elasticsearch配置文件JVM配置31G最佳
Elasticsearch的JVM堆内存配置为32GB被视为最佳实践,主要基于以下综合技术原理和性能优化考量: 1. JVM指针压缩机制优化内存效率 当堆内存≤32GB时,JVM启用对象指针压缩(Compressed Ordinary Object Pointers, COOP&#…...
单片机开发软件
目录 纯编码 vscode Ardunio Keil 1. 集成化开发环境(IDE) 2. 多架构芯片支持 3. 高效的代码生成与优化 4. 强大的调试与仿真功能 5. 丰富的库函数与生态系统 6. 教育与企业级适用性 典型应用场景 半编码半图形化 STM32CUBEIED 1. 图形化配置…...
Java随机生成邀请码 (包含字母大小写+数字)
前言: 目前我们生成的是6位包含数字和大小写字母的随机邀请码, 并且代码中已经有了处理冲突的机制确保了邀请码的唯一性如(①生成随机邀请码后会检查数据库中是否已存在②如果存在冲突,会尝试最多10次重新生成③如果多次尝试仍失败,会使用"U"用户ID派生的…...
mybatis-plus配置逻辑删除
在实体类中标记软删除字段使用注解 TableLogic 标记该字段为软删除字段 import com.baomidou.mybatisplus.annotation.*;public class YourEntity {// ...其他字段TableLogicprivate Integer isDeleted;// getter/setter }yml配置 # 逻辑已删除值 logicDeleteValue: 2 # 逻辑…...
第二十五天打卡
常见报错类型 try-except-else-finally 语句 首先执行try语句,若正确直接执行else语句 若try语句发生错误,则判断错误类型,执行错误类型对应的except语句,不执行else语句 finally语句无条件执行,多用于资源保存&…...
JESD204 ip核使用与例程分析(一)
JESD204 ip核使用与例程分析(一) JESD204理解JESD204 与JESD204 PHY成对使用原因JESD204B IP核JESD204B IP核特点JESD204B IP核配置第一页第二页第三页第四页JESD204 PHY IP核配置第一页第二页JESD204理解 JESD204B是一种针对ADC、DAC设计的传输接口协议。此协议包含四层, …...
Synchronized详解及高频面试问答
目录 JVM简述 Synchronized详解及面试高频问答 而synchronized是什么,可以解决什么问题? synchronized怎么使用? 锁升级升级了什么? 为什么要这样做锁升级? 锁升级的过程是怎样的?为什么会有偏向锁&…...
【LLIE专题】基于码本先验与生成式归一化流的低光照图像增强新方法
GLARE: Low Light Image Enhancement via Generative Latent Feature based Codebook Retrieval(2024,ECCV) 专题介绍一、研究背景二、GLARE方法阶段一:正常光照代码本学习(Normal-Light Codebook Learning)…...
26考研 | 王道 | 计算机组成原理 | 一、计算机系统概述
26考研 | 王道 | 计算机组成原理 | 一、计算机系统概述 文章目录 26考研 | 王道 | 计算机组成原理 | 一、计算机系统概述1.1 计算机的发展1.2 计算机硬件和软件1.2.1 计算机硬件的基本组成1.2.2 各个硬件的工作原理1.2.3 计算机软件1.2.4 计算机系统的层次结构1.2.5 计算机系统…...
Linux云计算训练营笔记day08(MySQL数据库)
Linux云计算训练营笔记day08(MySQL数据库) 目录 Linux云计算训练营笔记day08(MySQL数据库)数据准备修改更新update删除delete数据类型1.整数类型2.浮点数类型(小数)3.字符类型4.日期5.枚举: 表头的值必须在列举的值里选择拷贝表复…...
从基础到实习项目:C++后端开发学习指南
在当今技术快速迭代的背景下,后端开发作为软件工程的核心支柱持续发挥着关键作用。C凭借其卓越的性能表现和系统级控制能力,依然是构建高性能后端服务的首选语言之一。本文将系统性地解析现代C后端开发的核心技术体系,包括从语言特性精要到架…...
jedis+redis pipeline诡异的链接损坏、数据读取异常问题解决
文章目录 问题现象栈溢出(不断的重连)读取超时未知响应尝试读取损坏的链接读取到的数据和自己要读的无关,导致空指针、类型转换错误,数据读取错乱 问题写法问题分析修复注意点 问题现象 栈溢出(不断的重连)…...
十、HQL:排序、联合与 CTE 高级查询
作者:IvanCodes 日期:2025年5月15日 专栏:Hive教程 Apache Hive 作为大数据领域主流的数据仓库解决方案,其查询语言 HQL (Hive Query Language) 是数据分析师和工程师日常工作的核心。除了基础的 SELECT-FROM-WHERE,HQ…...
数据结构—排序(斐波那契数列,冒泡,选择,插入,快速,归并,图,广度优先算法)
目录 一 斐波那契数列(递归算法) 定义 原理 二 冒泡排序 定义 排序思路 函数原型 参数详解: 算法分析: 1. 使用函数库的qsort函数 2. 自定义冒泡排序 三 选择排序 定义 排序思路 四 插入排序 定义 排序思路 五 快速…...
NetSuite CSV导入Item Fulfillment的功能测试
上一篇我们说过如何通过CSV导入更新IF上的Department/Class信息,这篇是来测试一下如果SO在Pending Fulfillment的状态下通过CSV导入IF,这个新版本的一个功能,刚好将测试的过程与结果与大家分享~ 准备文件 External ID是外部ID; …...
网络原理 | 网络基础概念复习
目录 网络中的重要概念 IP地址 端口号 协议 五元组 协议分层 OSI七层网络模型 TCP/IP 五层(四层)模型 网络设备所在的分层 封装和分用 网络中的重要概念 IP地址 IP地址主要用于标识网络主机、其他网络设备的网络地址。在网络数据传输中&#…...
Vsan数据恢复——Vsan上虚拟机不可用,虚拟机组件信息破坏的数据恢复
Vsan数据恢复环境: 一台采用VsSAN分布式文件系统的存储设备由于未知原因关机重启。管理员发现上层的虚拟机不可用,存储内的数据丢失。 Vsan数据恢复过程: 1、将故障存储设备断电,将存储内的硬盘编号后取出。硬件工程师检测后没有发…...
V837s-LAN8720A网口phy芯片调试
目录 前言 一、LAN8720A 芯片概述 二、硬件连接 三、设备树配置 四、内核配置 五、网口调试 总结 前言 在嵌入式系统开发中,网络连接是至关重要的一部分。v837s开发板搭载了LAN8720A系列的网口PHY芯片,用于实现以太网连接。在开发过程中,对于网口的稳定性和性能的调试至…...
C++(12):using声明
目录 一、定义 二、核心用法示例 示例 1:单独引入 std::string 和 std::coun 示例 2:在局部作用域中使用 using 声明 三、对比 using namespace std(不推荐) 四、关键注意事项 1. 名称冲突问题 2. 作用域规则 3. 头文件中的陷阱 五、最佳实践总结 六、完整安全示…...
Xinference 命令大全:从模型部署到管理
Xinference 是一个高性能、分布式的模型推理框架,支持多种大语言模型(LLM)、嵌入模型(Embedding)和图像生成模型。本文将详细介绍 Xinference 的常用命令,涵盖模型启动、管理、监控及 API 调用,帮助你快速掌握其核心功能。 1. 安装与启动 Xinference 1.1 安装 Xinferen…...
如何在线免费压缩PDF文档?
PDF文件太大,通常是因为内部嵌入字体和图片。怎么才能将文件大小减减肥呢,主要有降低图片清晰度和去除相关字体两个方向来实现文档效果。接下来介绍三个免费压缩PDF实用工具。 (一)iLoveOFD在线转换工具 iLoveOFD在线转换工具&a…...
在Rocky Linux 9.5上部署MongoDB 8.0.9:从安装到认证的完整指南
mongodb 的部署 #安装依赖 yum -y install libcurl openssl #安装mongodb yum -y install https://repo.mongodb.org/yum/redhat/9/mongodb-org/8.0/x86_64/RPMS/mongodb-org-server-8.0.9-1.el9.x86_64.rpm #启动服务 systemctl start mongod.service && system…...
Unix Bourne Shell
本文来源 : 腾讯元宝 Unix Bourne Shell(简称sh)是Unix系统中最经典的命令行解释器(shell),由Stephen Bourne于1977年在贝尔实验室开发,并成为后续众多shell(如bash、ksh等ÿ…...
如何在 AWS 上构建支持 AVIF 的前端图片优化方案
一、为什么使用 AVIF 图片格式? 优势点 说明 高压缩率 在相似质量下,AVIF 文件比 JPEG/PNG/WebP 更小,能有效节省带宽和存储空间。 更高画质 即使在低码率下也能保持清晰细节,减少压缩带来的马赛克或模糊问题。 支持透明度 …...
Linux系统进行环境开发环境配置
一. 使用fishros(鱼香肉丝)配置开发环境 对于初学者来说,最难的关卡莫非是开发环境的的搭建,特别是在Ubuntu系统上ROS系统安装时后出现的各种报错以及失败,本篇博客讲述了ROS系统的一键安装过程,适用于18.04及以后的Ubuntu系统版本…...
前端npm的核心作用与使用详解
一、npm是什么? npm(Node Package Manager) 是 Node.js 的默认包管理工具,也是全球最大的开源代码库生态系统。虽然它最初是为 Node.js 后端服务设计的,但如今在前端开发中已成为不可或缺的基础设施。通过npm,开发者可以轻松安装、管理和共享代码模块。 特性: 依赖管理…...
软考软件评测师——软件工程之系统维护
一、系统质量属性 可维护性 衡量软件系统适应修改的难易程度,包括修复缺陷、扩展功能或调整规模的效率。计算公式为:系统可用时间占比 1/(1平均修复时间),其中平均修复时间(MTTR)指排除故障所需的平均耗时。 可靠性 vs 可用性 可靠性&…...
CSRF攻击 + 观测iframe加载时间利用时间响应差异侧信道攻击 -- reelfreaks DefCamp 2024
参考: https://0x90r00t.com/2024/09/30/3708/ 题目信息 有些事情最好还是保持低调。当然,除非你是个真正的怪胎。 注意:该网站通过HTTPS提供服务 标志格式:DCTF{}题目实现了一个类似视频网站的东西 在其提供的数据库中…...
火山RTC 8 SDK集成进项目中
一、SDK 集成预备工作 1、SDK下载 https://www.volcengine.com/docs/6348/75707 2、解压后 3、放在自己项目中的位置 1)、include 2)、lib 3)、dll 暂时,只需要VolcEngineRTC.dll RTCFFmpeg.dll openh264-4.dll, 放在intLive2…...
spring boot Controller 和 RestController 的区别
spring boot Controller 和 RestController 的区别 5.3.1常用注解 Spring MVC控制器中常使用的注解有如下几种。 Controller Controller 标记在类上。使用Controller 标记的类表示是Spring MVC的Controller对象。分发处理器将会扫描使用了该注解的类,并检测其中的…...
mavgenerate 在 win11 下环境搭建注意问题
开发随笔 mavgenerate 是mavlink配套的协议生成工具,mavgenerate 在 win11 下环境搭建注意问题: 1、Python 就使用文件包当中的版本,由于python 版本能与 future 及 pip 之间存在特定的组合关系,故不推荐下载使用最新版本 2、安…...
SSM项目集成redis、Linux服务器安装redis
在SSM(Spring Spring MVC MyBatis)项目中引入Redis主要分为以下步骤,确保配置正确并能在业务中灵活使用: 1. 添加Redis依赖 在Maven的pom.xml中添加Spring Data Redis和Jedis(或Lettuce)依赖&#…...
sqli-labs靶场第七关——文件导出注入
一:目标 通过sql注入将php代码写入网站目录,通过这个php文件执行命令 二:确认前置条件 %secure_file_priv% 首先我们需要Mysql是否允许导出文件 先尝试在网页中sql注入,检查导出权限 ?id1)) union select 1,secure_file_pr…...
python使用matplotlib无法显示中文字体报错
python使用matplotlib字体报错 当我们使用python使用matplotlib总是出现报错,图片中文变成方框 findfont: Font family WenQuanYi Micro Hei not found. findfont: Font family Heiti TC not found. findfont: Font family [SimHei] not found. Falling back to De…...
VTEP是什么
VTEP(VXLAN Tunnel Endpoint,VXLAN 隧道端点)是 VXLAN(Virtual Extensible LAN)网络中的关键组件,用于处理 VXLAN 流量的封装和解封装。以下以可读的 Markdown 格式详细解释 VTEP 的定义、功能、实现方式以…...
React Native简介
React Native 是由 Meta(原 Facebook)开源的跨平台移动应用开发框架,基于 React 和 JavaScript,允许开发者使用同一套代码库构建 iOS 和 Android 原生应用。通过 JavaScript 调用原生组件实现高性能渲染。 跨平台开发 共享 80%-9…...
边缘计算模块
本文来源 :腾讯元宝 边缘计算模块是一种部署在网络边缘(靠近数据源)的集成化硬件/软件设备,用于实时处理本地数据,减少云端依赖,提升响应速度与安全性。以下是其核心要点: 1. 核心组成 …...
策略模式-枚举实现
策略模式的实现方法有很多,可以通过策略类if,else实现。下面是用枚举类实现策略模式的方法。 定义一个枚举类,枚举类有抽象方法,每个枚举都实现抽象方法。这个策略,实现方法是工具类的很实现,代码简单好理解 枚举实现…...
C++算法(22):二维数组参数传递,从内存模型到高效实践
引言 在C程序设计中,二维数组的参数传递是许多开发者面临的棘手问题。不同于一维数组的相对简单性,二维数组在内存结构、类型系统和参数传递机制上都存在独特特性。本文将深入探讨静态数组、动态数组以及STL容器三种实现方式,通过底层原理分…...
LeetCode LCR 015. 找到字符串中所有字母异位词 (Java)
LCR 015. 找到字符串中所有字母异位词 题目描述 给定两个字符串 s 和 p,要求找到 s 中所有是 p 的变位词(字母相同但排列不同)的子串,并返回这些子串的起始索引。例如: 输入 s "cbaebabacd", p "a…...