链表(增删改查)
记录
初次理解。。。有些偏差
我的链表https://blog.csdn.net/qq_43763494/article/details/101068960链表理解
代码片
.
#include<iostream>
#include<cstdlib>
using namespace std;
//宏定义参数内容
#define DATA_SIZE 200
#define EXTEND_DATA_SIZE 50
#define NO 0
#define OK 1
#define ERROR -1
//基本数据类型别名
typedef int Status;
typedef char Excelelem;
typedef int Numelem;
//链表数据结构
typedef struct Node ///三条斜杠的为我个人的理解 ///类型定义 Node结构体 起别名为Liststruct
{
Excelelem book; ///char类型变量book 链表里存的值(们)
struct Node *next; ///结构体指针 Node (就是指向结构体的指针?)
}Liststruct;
//链表表头信息
typedef struct
{
Excelelem book[1024]; ///char类型数组?
Liststruct *next; ///这个和Liststruct *newNode 的区别是?
Numelem Length; ///int类型变量Length
}ListHead; ///直接命名结构体ListHead
//初始化链表
Liststruct * init(int *i) ///初始链表
{
Liststruct *Head,*p,*q; ///Liststruct类型头指针,前一结点指针q,后一结点指针p
Excelelem ch; ///char类型变量ch
Head=q=NULL; ///头指针等于前指针等于空值
cout << "请输入顺序表Head的内容:" << endl;
while((ch=getchar())!='\n'){ ///每次while循环接收一个字符,直到换行符(回车)为止
p=(Liststruct *)malloc(sizeof(Liststruct)); ///分配内存--百度
p->book=ch; ///将接收的值赋值给该结点的book
if(!(*i)){ ///这个(*i)还没搞懂...
Head=q=p;
(*i)++;
}
else{
q->next=p; ///前指针q的next指向p
q=p; ///后指针p变为前指针q
(*i)++;
}
}//注意*q++和(*q)++有区别!
if(q){
q->next=NULL; ///初始化链表后将q的next指向NULL(空) (应该是备用)
}
return Head; ///返回头指针的地址
}
ListHead * Headinit() ///头结点
{
ListHead *Head; ///声明一个ListHead类型的指针
Head=(ListHead *)malloc(sizeof(ListHead)); ///分配内存
Head->Length=0; ///将表头的Length赋值为0
Head->next=init(&Head->Length); ///头结点的next指向初始化链表函数 参数为(Head->Length)的地址
return Head; ///返回头指针的地址
}
//打印表中数据内容
void DATA_cout(ListHead *Head) ///定义void类型函数 参数是ListHead类型的指针*Head;
{
Liststruct *p=Head->next; ///定义Liststruct类型的结构体指针,并指向Head->next;此时p相当于Head;
while(p!=NULL){ ///当p->next不为空(也就是不是最后一个结点)时,循环
cout << p->book; ///输出对应的结点中的值
p=p->next; ///将p所指向的结点地址赋值给p(p变为下一个结点)
}
cout << endl; ///换行
return ; ///这个return可以不返回任何值的么? (void的不需要返回值,这句话应该可以不写)
}
//打印表中local位置元素内容
void Local(ListHead* Head,int local) ///定义void类型函数 参数是结构体指针Head和int类型变量local
{
if(Head->Length<local || local<1){ ///如果链表的长度小于所输入的位置(即变量local的值)
cout << "警告!不存在" << local << "位置的元素!" << endl; ///或者local的值小于1,输出警告
return ;
}
Liststruct *p=Head->next; ///定义Liststruct类型的结构体指针,并指向Head->next;
int i=1; ///定义i,赋初值1
while(p && i++!=local){ ///当p不为空(NULL)且没有找到local位置(i与local不相等)时,循环
p=p->next; ///将p所指向的结点地址赋值给p
}
cout << p->book << endl; ///输出p此时所在结点的内容(book值)
return ;
}
//找到表中出现字符ch的位置
void DATA_find(ListHead* Head,char ch) ///定义void类型函数 参数是结构体指针Head和char类型变量ch
{
int i=1,flag=0,count=1; ///定义flag判断是否发现匹配元素
Liststruct *p=Head->next; ///定义Liststruct类型的结构体指针,并指向Head->next;
while(p){ ///当p存在时,就是在链表内
if(p->book==ch){ ///判断当前结点内book是否与要查找的ch匹配
flag=1; ///如果匹配,flag值变为1
cout << count++ << ".在第" << i << "个位置发现元素" << ch << endl;
}
i++;
p=p->next; ///将p所指向的结点地址赋值给p
}
if(!flag){ ///如果flag值为0则说明未在链表内找到对应字符
cout << "未找到出现'" << ch << "'元素的位置!" << endl;
}
return ;
}
//在第K个元素前插入一个元素
void DATA_Insert(ListHead *Head,int k,Excelelem ch) ///定义void类型函数 参数是结构体指针Head和Excelelem类型变量ch
{ ///ch即(要插入的字符),以及int型变量k(即要插入的位置)
if(k<1 || Head->Length<k){ ///首先判断链表中有无这个位置
cout << "警告!不存在第" << k << "位置元素" << endl;
return ;
}
Liststruct *p=Head->next,*q,*t; ///一如既往的定义指针 指针p,前指针t,后指针q
int i=1;
while(p && i++!=k){ ///一如既往的寻找k这个位置所对应的结点
t=p; ///将上一个结点保留在t
p=p->next; ///一如既往的将p变成下一个结点
}
q=(Liststruct *)malloc(sizeof(Liststruct)); ///创建新结点并分配空间(这个结点就是用来插入字符的)
q->book=ch; ///将q的book赋值为ch(将字符放入结点内)
if(k==1){ ///这个if else实际上是可以不加的(我认为上一个while循环已经包含了这个k==1的情况)
Head->next=q; ///这一步其实就是插入结点
q->next=p;
}
else{
t->next=q; ///将前一个结点的指针域的指针指向q的地址
q->next=p; ///将q的指针域指向下一个结点的地址(从中间接入一个结点,字符插入完成)
}
Head->Length++; ///别忘了将链表的总长度加1哦
return ;
}
//删除第k个元素
void DATA_Delete(ListHead *Head,int k) ///定义void类型函数 参数是结构体指针Head和int类型变量k(位置)
{
if(k<1 || Head->Length<k){ ///同样首先判断链表中有无这个位置
cout << "警告!不存在第" << k << "位置元素" << endl;
return ;
}
Liststruct *p=Head->next,*t; ///一如既往的定义指针 指针p,前指针t
int i=1;
while(p && i++!=k){ ///一如既往的寻找k这个位置所对应的结点
t=p; ///将上一个结点保留在t
p=p->next; ///一如既往的将p变成下一个结点
}
if(k==1){ ///这个是将结点删除(其实是将该结点跳过)
Head->next=p->next;
}
else{
t->next=p->next; ///将t的指针域的指针指向p的指针所指向的(将p结点跳过)
}
free(p); ///跳过后将p释放,就是将该结点删除了
Head->Length--; ///记得将链表总长度减1哦
return ;
}
//逆置链表
void DATA_UN(ListHead *Head) ///定义void类型函数 参数是结构体指针Head
{
Liststruct *p,*q; ///一如既往的定义指针 指针p,q
p=Head->next; ///将p赋值为Head的next(指针域),和*p=Head->next的区别是?
Head->next=NULL; ///将Head的next置空
while(p!=NULL){
q=p; ///将p赋值给q(p代表的到底是结点还是什么?)
p=p->next; /// 将p所指向的结点地址赋值给p
q->next=Head->next; ///将Head的next赋值给q的next
Head->next=q; ///将q赋值给Head的next(这个赋值的是q结点的首地址?)
}
return ;
}
//返还内存
void List_FREE(ListHead *Head) ///定义void类型函数 参数是结构体指针Head
{
Liststruct *p=Head->next,*q; ///定义Liststruct类型的结构体指针,并指向Head->next;指针q
free(Head); ///释放Head
while(p){
q=p; ///...
p=p->next; ///p的next赋值给p
free(q); ///将q释放
}
return ;
}
int main()
{
ListHead *Head; ///创建一个头结点 头指针 首元结点(还没搞清楚)
Numelem i; ///定义int型变量i
Excelelem ch; ///定义char型变量ch
puts(""); ///输出一个空字符串?
puts("******等待链表Head初始化!******");
Head=Headinit(); ///调用函数初始化一个链表
puts("******链表Head初始化完成!******");
cout << "链表中的内容为:" << endl;
DATA_cout(Head); ///调用函数输出链表
cout << "链表Head的长度为:" << endl;
cout << Head->Length << endl; ///输出链表长度
///cin >> i;
//cout << "链表第" << i=2 << "个元素是:" << endl; ///这个i可以用输入流控制值
i=2;
cout << "链表第" << i << "个元素是:" << endl; ///上面的出问题了,不知道为什么
Local(Head,i); ///调用函数找到元素
///cin >> ch;
//cout << "链表中出现" << ch='6' << "元素的位置分别是:" << endl; ///同i
ch='6';
cout << "链表中出现" << ch << "元素的位置分别是:" << endl; ///上面的出问题了,不知道为什么
DATA_find(Head,ch); ///调用函数找到位置
///cin >> i >> ch;
//cout << "在链表的第" << i=4 << "个元素之前插上" << ch='9' << endl; ///同i,ch
i=4;
ch='9';
cout << "在链表的第" << i << "个元素之前插上" << ch << endl; ///上面的出问题了,不知道为什么
DATA_Insert(Head,i,ch); ///调用函数传递参数执行 添加元素
cout << "链表中的内容为:" << endl;
DATA_cout(Head); ///调用函数输出链表
///cin >> i;
//cout << "将链表中第" << i=3 <<"个元素删除" << endl; ///同上
i=3;
cout << "将链表中第" << i <<"个元素删除" << endl; ///上面的出问题了,不知道为什么
DATA_Delete(Head,i); ///调用函数删除元素
cout << "链表中的内容为:" << endl;
DATA_cout(Head); ///调用函数输出链表
cout << "将链表所有元素逆置,请稍后..." << endl << endl; //多种方法
DATA_UN(Head); ///调用函数逆置链表
cout << "链表中的内容为:" << endl;
DATA_cout(Head); ///调用函数输出链表
puts("******链表Head使用完毕!******\n");
List_FREE(Head); ///调用函数释放链表
return 0;
}
代码源自
https://blog.csdn.net/calculate23/article/details/79758845
仅以此博客记录我学习数据结构链表时对链表代码的理解
暂时还没能力独自编写链表…
记在博客上方便随时看
注释多为我个人理解
链表-4
这是链表的第四次练习了,代码有一些问题
就是判断空的时候判断不了
#include<iostream>
#include<cstdlib>
using namespace std;
//指针就是它所指向的那个变量的地址
//链表,第一步 定义结构体,结点类型,结点实际上就是一个一个结构体
typedef struct LinkList {
char book;
struct LinkList *next;
}LinkList;
//表头
typedef struct {
int book[100];
LinkList *next;
int Length;
}ListHead;
//第二步,初始化链表
LinkList *init(int *i) { //*i 链表长度
LinkList *Head,*p,*q;
char ch;
Head = q = NULL;
cout << "请输入链表的内容:" << endl;
//system("pause");
getchar(); //让系统暂停一下
while((ch = getchar()) != '\n') {
p = (LinkList *)malloc(sizeof(LinkList));
p->book = ch;
if(!(*i)) {
Head = q = p;
(*i)++;
}
else {
q->next = p;
q = p; //p有新分配的空间,而q只是个指针,让指向哪就指向哪
(*i)++;
}
}
if(q) q->next = NULL; //要不然指向的是q本身
system("pause");
return Head; //返回值类型和函数类型一样,可以理解为是LinkList *类型,也可以理解为LinkList类型的指针,一个意思
}
ListHead *Headinit() {
ListHead *Head;
Head = (ListHead *)malloc(sizeof(ListHead));
Head->Length = 0;
Head->next = init(&Head->Length); //借助地址返回
return Head;
}
//打印表
void Data_cout(ListHead *Head) { //包括以下函数都是利用头结点找到链表
LinkList *p = Head->next;
while(p != NULL) {
cout << p->book << " ";
p = p->next;
}
cout << endl;
return ; //可以不写
}
//定位位置元素
void Data_position(ListHead *Head,int local) {
if(local < 1 || local > Head->Length) { //规定位置从1开始
cout << "ERROR! NOT FOUND LOCAL!" << endl;
return ; //这个不能省,不写的话程序就继续执行了
}
LinkList *p = Head->next;
/*for(int i = 0;i < Head->Length;i++) { //条件换成p也行
if(p && i+1 == local) {
cout << local << "位置元素为:" << p->book << endl;
break;
}
p = p->next;
}试一试 用for循环的方法*/
int i = 1;
while(p && i++ != local)
p = p->next;
cout << local << "位置元素为:" << p->book << endl;
return ; //可以省,后面的只要不说就是可以省略的
}
//定位元素位置
void Data_find(ListHead *Head,char ch) {
LinkList *p = Head->next;
int i = 1,flag = 0,count = 1;
/*for(i = 0;i < Head->Length;i++) {
if(p && p->book == ch) {
flag = 1;
cout << p->book << "元素在第:" << i+1 << "位置" << endl;
break;
}
p = p->next;
}*/
while(p) {
if(p->book == ch) {
flag = 1;
cout << count++ << "." << p->book << "元素出现在第:" << i << "位置" << endl;
}
p = p->next;
i++;
}
if(!flag) {
cout << "ERROR! NOT FOUND " << ch << endl;
}
return ;
}
//插入元素
void Data_insert(ListHead *Head,int k,char ch) {
if(k < 1 || k > Head->Length) {
cout << "WARNING! NOT FOUND " << k << endl;
return ; //不能省
}
LinkList *p = Head->next,*q,*t;
/*for(i = 0;p;i++) {
t = p;
p = p->next;
if(k == 1) {
Head->next = q;
q->next = p;
}
else if(p && i+1 == k) {
q->next = p;
t->next = q;
}
p = p->next;
}用for和用while没多大差别。。。*/
int i = 1;
while(p && i++ != k) {
t = p;
p = p->next;
}
q = (LinkList *)malloc(sizeof(LinkList));
q->book = ch;
if(k == 1) {
Head->next = q;
q->next = p;
}
else {
q->next = p;
t->next = q;
}
Head->Length++;
return ;
}
//删除元素
void Data_delete(ListHead *Head,int k) {
if(k < 1 || k > Head->Length) {
cout << "WARNING! NOT FOUND " << k << endl;
return ; //不能省
}
int i = 1;
LinkList *p = Head->next,*q;
while(p && i++ != k) {
q = p;
p = p->next;
}
if(k == 1) {
Head->next = p->next;
}
else {
q->next = p->next;
}
free(p);
Head->Length--;
return ;
}
//逆置表
void Data_un(ListHead *Head) {
LinkList *p = Head->next,*q;
Head->next = NULL;
while(p != NULL) {
q = p;
p = p->next;
q->next = Head->next;
Head->next = q;
}
return ;
}
//返还内存
void List_free(ListHead *Head) {
LinkList *p = Head->next,*q;
free(Head);
while(p) {
q = p;
p = p->next;
free(q); //要是直接释放p的话,然后就没有然后了
q = NULL;
}
}
void Menu() {
cout << "*** 1.---初始化链表 ***" << endl;
cout << "*** 2.---打印表 ***" << endl;
cout << "*** 3.---定位位置元素 ***" << endl;
cout << "*** 4.---定位元素位置 ***" << endl;
cout << "*** 5.---插入元素 ***" << endl;
cout << "*** 6.---删除元素 ***" << endl;
cout << "*** 7.---逆置表 ***" << endl;
cout << "*** 8.---返还内存 ***" << endl;
cout << "*** 0.---退出 ***" << endl;
cout << endl;
}
int main()
{
int i;
char ch;
puts("");
int mark = 1;
Menu();
while(mark) {
//system("cls"); //清屏
cout << "enter:" << " ";
int select;
cin >> select;
switch(select) {
case 1:
ListHead *Head;
puts("******等待链表Head初始化!******");
Head = Headinit();
puts("******链表Head初始化完成!******");
break;
case 2:
puts("******链表中的内容为: ******");
Data_cout(Head);
puts("******链表Head的长度为: ******");
cout << Head->Length << endl;
break;
case 3:
puts("******请输入位置(i): ******");
cin >> i;
cout << "链表第" << i << "个元素是: ";
Data_position(Head,i);
break;
case 4:
puts("******请输入元素(ch): ******");
cin >> ch;
cout << "链表中出现" << ch << "元素的位置分别是: " << endl;
Data_find(Head,ch);
break;
case 5:
puts("******请输入要插入位置(i): ******");
cin >> i;
puts("******请输入要插入元素(ch): ******");
cin >> ch;
Data_insert(Head,i,ch);
puts("******插入完成!******");
break;
case 6:
puts("******请输入删除位置(i): ******");
cin >> i;
Data_delete(Head,i);
puts("******删除完成!******");
break;
case 7:
Data_un(Head);
puts("******逆置完成!******");
break;
case 8:
List_free(Head);
puts("******释放完毕!******");
break;
case 0:
mark = 0;
break;
}
}
}
反复强调!!!一定要看啊啊啊!!!老是没时间看写过的博客,这可不行。。。
运行结果:
最初的单链表
最原始的那个
书上代码有一些错误,主要是理解链表函数
#include<iostream>
#include<cstdlib>
#include<cstring>
using namespace std;
struct Node {
int data;
struct Node *next;
};
typedef struct Node Node;
typedef struct Node * Link;
char menu();
void create(Link);
void show(Link);
int find(Link,int);
void insert(Link,int,int);
void del(Link,int);
int main()
{
int leave =0;
Link head = (Link)malloc(sizeof(Node));
create(head);
do {
int num,index;
char n = menu();
switch(n) {
case '1':
cout << "请输入要插入的数值:";
cin >> num;
cout << "请输入要插入的位置:";
cin >> index;
insert(head,index,num);
show(head);
break;
case '2':
cout << "请输入要删除的位置:";
cin >> index;
del(head,index);
show(head);
break;
case '3':
cout << "请输入要查找的数值;";
cin >> num;
find(head,num);
break;
case '4':
show(head);
break;
case '5':
leave = 1;
break;
}
}while(leave == 0);
return 0;
}
char menu() {
char select[100];
cout << "*** 单链表 ***" << endl;
cout << "*** 1.插入结点 ***" << endl;
cout << "*** 2.删除结点 ***" << endl;
cout << "*** 3.查找结点 ***" << endl;
cout << "*** 4.显示链表 ***" << endl;
cout << "*** 5.退出系统 ***" << endl;
cout << "请选择:" << endl;
do {
fflush(stdin); //???
gets(select);
if(strlen(select) == 1) {
if(strcmp(select,"1") == 0 || strcmp(select,"2") == 0 || strcmp(select,"3") == 0 || strcmp(select,"4") == 0 || strcmp(select,"5") == 0) {
return select[0];
} //这是啥???
}
cout << "输入有误!" << endl;
}while(1);
}
//创建
void create(Link head) {
int i = 0;
Link q = head;
while(i < 5) { //共输入5个结点
Link p = (Link)malloc(sizeof(Node)); //p指向下一个结点
p->data = (i+1) * 10;
p->next = NULL; //先让p的next指向NULL是什么操作?就可以循环输入了
p->next = q->next; //这句话书上是不是少了?
q->next = p;
q = p;
i++;
}
}
//遍历输出
void show(Link head) {
Link p = head->next;
while(p != NULL) {
cout << p->data << " ";
p = p->next;
}
cout << endl;
}
//定位元素位置
int find(Link head,int num) {
int i = 1;
Link p = head->next;
while(p != NULL) {
if(p->data == num) {
cout << "第" << i << "个结点!" << endl;
return i;
}
i++;
p = p->next;
}
cout << "没找到!" << endl;
return 0;
}
//插入
void insert(Link head,int index,int num) {
int i = 1;
Link p = head;
Link pnew = (Link)malloc(sizeof(Node)); //pnew指向新结点
pnew->data = num;
pnew->next = NULL;
if(index < 0) {
cout << "插入位置有误!" << endl;
return;
}
while(p != NULL) {
if(i == index) {
break;
}
p = p->next;
i++;
}
if(p == NULL) {
cout << "插入位置有误!" << endl;
return;
}
pnew->next = p->next;
p->next = pnew;
}
//删除
void del(Link head,int index) {
int i = 1;
Link q = head;
Link p = q->next;
if(index <= 0) {
cout << "删除位置有误!" << endl;
return;
}
while(p != NULL) {
if(i == index) {
break;
}
q = p;
p = p->next;
i++;
}
if(p == NULL) { //这是循环到了最后一个结点的后面
cout << "插入位置有误!" << endl;
return;
}
q->next = p->next;
free(p);
}