8月26日学习了数据结构的前几章,学习到链表时对于C语言的结构体与链表时,决定先回顾一下c++中的结构体与链表。

c++中可以用两种方式说明结构体:

struct Student{}stu1,*stu2;  //stu2是Student类型的指针变量
//或者
struct Student{};Student stu1,*stu2;

访问结构时可以用结构变量名.数据成员的格式。如果是指针变量用*(指针变量).数据成员或者(指针变量)->数据成员的格式。当结构类型变量作为函数参数,也可选择作为传值参数、指针参数或引用参数。和c不同,c++允许在结构体内部加入成员函数。

除去普通的结构变量、结构指针,c++中还提供了结构数组。结构数组可以用在有许多同一结构的对象时,方便批量储存管理信息。下面看一个职工登记表,按薪资排序:

#include <iostream>
using namespace std;
struct person
{char name[10];unsigned int id;double salary;
};
void Input(person[], const int);
void Sort(person* [], const int);
void Output(person* [], const int);
int main()
{person allone[100]; //说明结构数组person* index[100]; //说明索引数组int total;for (int i = 0; i < 100; i++)  //索引数组元素值初始化为结构数组元素地址index[i] = allone + i;cout << "输入职工人数:" ;cin >> total;cout << "输入职工信息:" << endl;Input(allone, total);cout << "以工资为关键字排序:" << endl;Sort(index, total);Output(index, total);
}
void Input(person all[], const int n)
{int i;for (i = 0; i < n; i++){cout << i << ":姓名:";cin >> all[i].name;cout << "编号:";cin >> all[i].id;cout << "工资:";cin >> all[i].salary;}
}
void Sort(person* pi[], const int n)
{int i, j;person* temp;for (i = 1; i < n; i++){for(j=0;j<n-i-1;j++)if (pi[j]->salary > pi[j + 1]->salary){temp = pi[j];pi[j] = pi[j + 1];pi[j + 1] = temp;}}
}
void Output(person* pi[], const int n)
{for (int i = 0; i < n; i++)cout << pi[i]->name << '\t' << pi[i]->id << '\t' << pi[i]->salary << endl;
}

在上面的程序中,先定义了person结构体,并且用该结构体说明一个数组和一个指针数组。让指针数组的每个指针都指向对应的数组元素。加这个指针数组的原因是,在sort函数内排序时,如果直接对结构体数组allone进行排序,会造成较大的数据开销。而对指针索引进行顺序调整更加简便。并且在sort函数中,结构体指针数组作为指针参数传入函数,实现对实际参数的操纵。最终输出结果:

输入职工人数:3
输入职工信息:
0:姓名:zzy
编号:001
工资:3000
1:姓名:zhb
编号:002
工资:6000
2:姓名:zht
编号:003
工资:5000
以工资为关键字排序:
zzy     1       3000
zht     3       5000
zhb     2       6000

c++链表:创建链表

struct Node
{char name[20];double salary;Node *next;  //next是自身结构类型的指针,但上面的数据成员不能是自身结构的变量
};

创建单向链表:

struct Node
{int data;Node *next;  //next是自身结构类型的指针,但上面的数据成员不能是自身结构的变量
};
void CreatList(Node* & head)  //引用表头指针
{Node *s,*p;s=new Node;cin>>s->data;while(s->data!=0){if(head==NULL)head=s;    //如果原来没有表头,那么s就是表头elsep=s;s=new Node;cin>>s->data; p->next=s; //如果已有表头,那么建立s的后继结点p,给s开辟新空间并赋值,之后让p的结点指针指向s}
}

插入结点:分三种情况:

表头插入:生成新结点,赋值,新结点的下一跳指针指向原表头结点,并修改表头指针。
*p后插入与表头插入类似。
*p前插入:需要先找到*p之前的结点*q。也可避免重新搜索其前驱:
s->next=p->next;  //后插
p->next=s;
temp=p->data;
p->data=p->next->data;
p->next->data=temp; //交换数据域

删除结点:也分三种情况,不再赘述。

经典问题“猴子选大王”:让 N 只候选猴子围成一圈(最多 100 只猴子),从某位置起顺序编号为 1 ~ N 号。从第 1 号开始报数,每轮从 1 报到 3 ,凡报到 3 的猴子即退出圈子,接着又从紧邻的下一只猴子开始同样的报数。如此不断循环,最后剩下的一只猴子就选为猴王。

下面记录一个“猴子选大王”的链表解法:

#include<iostream>
#include<iomanip>
using namespace std;
struct Jonse
{int code;Jonse* next;
};
Jonse* Create(int n)
{Jonse *h, *p;h = new Jonse;p = h;for (int i=1; i <= n; i++){p->code = i;  //每个结点顺序if (i < n){p->next = new Jonse;p = p->next;}}p->next = h;  //形成闭环return h;
}
void ShowList(Jonse* h)
{Jonse* p;p = h;cout << "the list is:";do{cout << p->code << '\t';p = p->next;} while (p != h);cout << endl;
}
void Out(Jonse* h, int i, int d)
{Jonse* p, * q;int k;p = h;  //让p指向初始结点for (q = h; q->next != h; q = q->next);  //让q指向最后一个结点for (k = 1; k < i; k++) //从第i个开始计,把指针移到该位置{q = p;p = p->next; }while (p != p->next)  //记到d进行处理,处理链环直至只剩一个结点{for (k = 1; k < d; k++){q = p;p = p->next;}cout << p->code << '\t';  //输出报到d的结点q->next = p->next;  //删除该结点delete p; p = NULL;p = q->next;}cout << p->code << endl;  //处理最后一个结点delete p;p = NULL;
}
​
int main()
{Jonse *head;int total, begin, num;cout << "put total:" << endl;cin >> total;head = Create(total);ShowList(head);cout << "put strat number:" << endl;cin >> begin;cout << "put interval of counting:" << endl;cin >> num;Out(head, begin, num);
}

结果测试:

put total:
3
the list is:1   2       3
put strat number:
1
put interval of counting:
2
2       1       3

当然,还提供了一种数组解法:

#include <iostream>
using namespace std;
int out(int,int,int);
int main()
{int total,begin,num, b;cout << "input total number:" << endl;cin >> total;cout << "input start number:" << endl;cin >> begin;cout << "input interval of counting:" << endl;cin >> num;b = out(total,begin,num);cout << "最终留下第" << b + 1 <<"个" << endl;return 0;
}
int out(int total,int begin,int num)
{int *a=new int[total];int i, j = 0;int t = begin-2;  //-1是因为第一只猴子对应a[0];另一个-1因为从第一只已经开始计数了,抵消下面的计数+1for (i = 0; i < total; i++)a[i] = 1;for (i = 0; i < total; i++)  //total-1次循环最终留下一个大王{j = 1;  //淘汰计数while (j <= num)  //如果没到淘汰计数{t = (t + 1) % total;  //指向下一只猴子if (a[t] == 1)j++;    //淘汰计数+1}a[t] = 0;  //淘汰该猴子}return t;
}

测试结果:

input total number:
3
input start number:
1
input interval of counting:
2
最终留下第3个

c语言链表,参考自《数据结构与算法c语言版》

先看一下typedef在c中的用法

typedef struct Student
{
int a;
}Stu;   //于是声明变量时可以Stu stu1,如果没有typedef就必须用struct Student stu1来声明//在c++中如果加了typedef,那么Stu将是一个结构体类型,声明变量还要Stu stu1,但不加typedef则Stu本身就是变量//如果有
typedef struct {}a,b,c;那么a,b,c都是结构体别名,a stu1和b stu1 是一样的。

再来看链表的类型声明

struct Node;   //声明Node结构体
typedef struct Node* PtrToNode; //typedef定义新类型,名字叫做PtrToNode,它的类型是指向Node结构体的指针
typedef PtrToNode List;    //相当于typedef struct Node* List,和后面那句一起,给 PtrToNode起了两个别名
typedef PtrToNode Position;List MakeEmpty(List L);  //变量L的类型相当于typedef struct Node* List;List L;生成的,指向Node结构体的指针变量
int InEmpty(List L);
int IsLast(Position P, List L);
Position Find(ElementType X, List L);
void Delete(ElementType X, List L);
Position FindPrevious(ElementType X, List L);
void insert(ElementType X, List L, Position P);struct Node
{ElementType Element;Position Next;
};

功能函数具体编写:

int InEmpty(List L); {return L->Next == NULL;}int IsLast(Position P, List L); {return P->Next == NULL;}Position Find(ElementType X, List L)
{Position P;P=L->Next;while(P!= NULL && P->Element != X)P=P->Next;return P;
}void Delete(ElementType X, List L);
{Position P,Tmpcell;P=FindPrevious(X,L);  //找到P的前驱元素if(!LsLast(P,L)){TempCell=P->Next;P->Next=TempCell->Next;free(Tmpcell);}
}Position FindPrevious(ElementType X, List L);
{Position P;P=L;  //让结构指针P先指向表头while(P->Next!= NULL && P->Next->Element!= X){P=P->Next;}return P;
}void insert(ElementType X, List L, Position P);
{Position TempCell;TempCell=malloc(sizeof(struct Node));  //定义一个Node结构体指针,指针名为TempCell,指向一个Node结构体,并为这个结构体分配了Node大小的内存空间if(TempCell == Null)FatalError("out of space!");TempCell->Element = X;TempCell->Next = P->Next;P->Next = TempCell;    //P后插
}

如何而知是否要用malloc获取一个新单元?---声明指向一个结构的指针并不会创建该结构,而只给出足够的空间容纳结构可能会使用的地址。创建尚未被声明过的记录的唯一方法是用malloc库函数。malloc是系统创建一个新的结构并返回指向该结构的指针。但如果仅仅想用一个指针变量沿着一个表进行,那么没必要创建新的结构,此时不宜使用malloc。

当空间不再需要,可以用free命令收回。free(P)时,P指向的地址没变,但该地址处数据被清空。

在用完一个链表,为了释放储存空间我们去删除它时,一种错误的思路是

void DeleteList(List L)
{Position P;P=L->Next;L->Next=NULL;while(P!=NULL){free(P);P=P->Next;}
}

因为一旦free(P)释放了这个单元,就不再能引用它, P=P->Next也就无法实现.正确方法应如下:

void DeleteList(List L)
{Position P,Tmp;P=L->Next;L->Next=NULL;while(P!=NULL){Tmp=P->Next;free(P);p=Tmp;}
}

数据结构学习日记1---链表(附结构体)相关推荐

  1. swift学习笔记(9)-结构体和类

    结构体和类对比 Swift 中类和结构体有很多共同点.共同处在于: * 定义属性用于存储值 * 定义方法用于提供功能 * 定义下标操作使得可以通过下标语法来访问实例所包含的值 * 定义构造器用于生成初 ...

  2. 关于数据结构(c语言)中结构体声明的typedef struct LNode, *LinkList的思考

    在数据结构的链表,表示中 typedef struct Node * PtrToNode 和 typerdef struct List的表示说明 typedef struct Node * PtrTo ...

  3. go struct 静态函数_Go语言学习笔记(四)结构体struct 接口Interface 反射reflect...

    加 Golang学习 QQ群共同学习进步成家立业工作 ^-^ 群号:96933959 结构体struct struct 用来自定义复杂数据结构,可以包含多个字段(属性),可以嵌套: go中的struc ...

  4. go的优势--链表与结构体使用

    一.go语言的优势 1 可以使用脚本和可执行两种方式 1.这种方式用脚本执行 go run test.go 2.这种方式编译可执行 go build test.go 2 跨平台不依赖运行库 3.脚本方 ...

  5. 【FFmpeg学习】FFmpeg常见的结构体

    音视频播放的原理主要分为:解协议->解封装->解码->音视频同步->播放. 那 FFmpeg 的解码流程结构体也可以由以上流程进行分类: 解协议(http,rtsp,rtmp, ...

  6. C语言数据结构预备知识模块二:结构体

    继上面的基础模块知识之指针之后,我们对数据结构的预备知识--结构体进行记录学习. 在学习 Java之后,我们对面向对象的编程方法更为习惯,因为类Class的出现,让我们对"万事万物皆对象&q ...

  7. java 链表放置结构体_结构体和它在链表中的使用

    一.结构体 由不同类型的数据组合成一个整体,以便引用,这些组合在一个整体中的数据是互相联系的. 1.1如何声明结构体呢? struct 结构体名  //结构体名字用作结构体类型的标志 {成员列表}; ...

  8. Go 学习笔记(14)— 结构体定义、实例化、初始化、匿名结构体、结构体访问、结构体作为形参、结构体指针

    Go 语言中没有 "类" 的概念,也不支持 "类" 的继承等面向对象的概念.Go 语言不仅认为结构体能拥有方法,且每种自定义类型也可以拥有自己的方法. 1. 结 ...

  9. c++结构体嵌套结构体_Go学习每日一问(13)-结构体嵌套

    每次学习并整理一个Golang的知识点,每天进步一点点.今天学习一个go结构体嵌套的知识点. 日省吾身 1.下面这段代码的输出结果? func main() { a := -7 b := +7 fmt ...

最新文章

  1. System_Recovery_21.0.3_62137_Multilingual_Product
  2. python免费试听-线上儿童编程免费试听-品质保障
  3. Page.ClientScript.RegisterStartupScript() 方法与Page.ClientScript.RegisterClientScriptBlock() 方法...
  4. P3700 [CQOI2017]小Q的表格(反演、分块)
  5. 使用Guava的AbstractInvocationHandler正确完成代理
  6. docker: Error response from daemon: driver failed programming external connectivity
  7. 留个坑,不知道为什么sqlite3要求组权限才能执行db:migrate,而可以直接执行db:......
  8. 免费数据集 公开数据集下载 网站
  9. Linux软链接的创建,删除,修改
  10. 路由器桥接LAN接LAN口(改DHCP以及详细避坑教程)
  11. kaldi的vad计算
  12. 微软打补丁出现“此更新不适用于您的计算机”
  13. 远程桌面从服务器拷文件出错
  14. Effect C++ 学习笔记三:资源管理
  15. Mysql 四舍五入 取整
  16. 新堂NUC505开发板第一炮-启动篇
  17. 视频硬字幕提取方法(可完全离线),开发个小工具辅助一下
  18. apache hop 搭建_server端
  19. Java周记(第二周)
  20. 【STM32F429的DSP教程】第9章 Matlab的串口通信实现

热门文章

  1. (a1,a2,a3,...,an-2,an-1,an)排列成(a1,an,a2,an-1,a3,an-2)
  2. 抖音短视频系统开发自定义弹框
  3. 什么品牌的显示器支架好用
  4. FAQ-MT6250/MT6250D平台,FM外放时耳机无声
  5. java referrer_referrer策略和meta标签的问题
  6. android中多个usb接口吗,手机USB接口那么多 你真的全认识吗?
  7. 欢(nan)乐(shou)纪中培训(Day 0~Day 1)
  8. linux及mac环境下多次调用vsnprintf崩溃的问题
  9. 创新小程序项目介绍:音乐推荐小程序
  10. Gitlab搭建教程详解