算法/C语言-结构体与链表
一、 结构体
1. 结构体一般定义格式
(1)类型说明时,定义变量
struct 类型名{
…
}变量名;
struct student{
int num;
char name[5];
}stu;
(2)先定义类型,再说明变量
struct 类型名{
…
};
struct 类型名 变量名;
struct student{
int num;
char name[5];
}
struct student stu;
(3)没有类型名,直接定义变量
注意:这种方法在实际编程中用得很少,但是选择题会考到
struct {
…
}变量名;
struct {
int num;
char name[5];
}stu;
2. 把typedef用户自定义数据类型名称用在结构体
typedef可以用来为结构体起一个新别名,例如
struct student{
int num;
char name[5];
};
typedef struct student STU;
这里的STU就是struct student的别名了
(struct student a;) 等价于 (STU a;)
通常也可以将typedef与结构体写在一起,即
typedef struct student{
int num;
char name[5];
}STU;
结构中可以包含指向它的指针
typedef struct student{
int num;
struct student *p;
}STU;
但是,注意!!!
typedef struct student{
int num;
STU *p;
}STU;
这里把struct student *p
改为了STU *p
,编译器会报错
我们利用typedef为struct student建立别名STU,但在结构体类型本身没有建立完成时,这个别名STU还不存在,编译器不认识STU,所以会报错。
因此,我们可以先typedef,再struct。
typedef struct student;
struct student{
int num;
STU *p;
}STU;
虽然这样操作可以,但不规范,还是推荐用
struct student *p;
3. 结构体成员的引用
这里定义一个结构体
typedef struct student{
int num;
char name[5];
}STU;
(1)普通变量
用 . 来引用,例如
STU x;
x.num = 4;
(2)指针变量
指针名->成员 或者 (*指针名).成员
*注意这里 . 的运算优先级高,应该把(指针名)括起来
STU *p;
p->num=5;
//or
(*p).num = 5;
(3)数组变量
数组名[下标].成员
STU a[4];
a[2].num=6;
二、链表
链表由数据域和指针域(下一个数据的地址)组成,这里地址域是指针,这个指针是整个数据类型
typedef struct node{
int s; //数据域,类型可以是int double char
struct node *next; //指针域,类型是struct node * ,即整个数据类型
}NODE; //有了typedef,这里的NODE相当于struct node的别名,一般要大写以区分。
1. 建立链表
NODE * createlist(int a[]){ //此函数类型必须是NODE*,因为要返回指针h。外部传进来一个数组,长度为N
NODE *h,*p,*q; //h是这个链表的头结点,指向链表开头。
int i=0;
h = p = (NODE*)malloc(sizeof(NODE)); //开辟内存。(NODE*)是强制转换类型;malloc()是分配内存;malloc(sizeof(NODE))是开辟结构体NODE大小的内存空间
p->s = 0; //为头结点为空 0
while(i<N){
q = (NODE*)malloc(sizeof(NODE)); //新开内存创建结点,原理同上
q->s = a[i++]; //为q所在地址的s成员赋值为a[i] ,i再自增
p->next = q; //把q的地址给p的地址域
p=q; //p再移到q的位置
}
p->next = NULL; //链表结束,最后一个地址域是NULL 空
return h; //返回链表头的地址
}
2. 输出链表
void outlist(NODE *h) //外部传入链表的起始地址
{
NODE *p;
p = h;//这样做会输出头结点的值(0)
//p=h->next; 从首元结点开始输出,不输出头结点
while (p){ //等价于 while(p!=0)
printf("%d ",p->s);
p=p->next;
}
}
3. 插入一个数据
现在有a b d e f 五个结点,要把c结点插入b d之间。
分析:原先b的地址域指向d的地址,只需要把c地址域指向d,b地址域指向c就行了。
代码实现
void insert(NODE *h){
NODE *p=h,*q;
int i,add=2; //add是插入位置,这里是指在在第二个结点之后插入
int data = 5; //假定这是要插入的数据
for(i=0;i<add;i++)
p=p->next; //循环add次后结束,即p到了结点b
q=(NODE*)malloc(sizeof(NODE)); //为结点c开辟空间
q->s = data; //给结点c的数据域赋值
q->next=p->next; //从结点b的地址域拿到d的地址,让结点c的地址域指向结点d
p->next=q;//把结点c的地址给结点b的地址域
}
4. 删除链表中的数据
现在有a b c d e f六个结点,要删除d结点
分析:原先b结点指向c,c结点指向d,只需要用一个临时变量temp保存c结点中存的d结点的地址,再把temp赋值给b结点的地址域。
代码实现
void del(NODE *h){
NODE *p=h,*temp;
int i,rmv=3; //rmv是需要删除位置的上一个结点
for(i=0;i<rmv;i++)
p=p->next; //循环rmv次后结束,即p到了结点c
temp=p->next; //暂存删除位置的结点
p->next=p->next->next; //把结点e的地址赋值给结点c的地址域
free(temp); //释放被删除的结点,防止内存泄漏
}
5. 完整代码实现
#include <stdio.h>
#include <stdlib.h>
#define N 5
typedef struct node{
int s;
struct node *next;
}NODE;
NODE * createlist(int a[]);
void outlist(NODE *h);
void insert(NODE *h);
void del(NODE *h);
int main(){
int a[N]={1,3,5,7,9};
NODE *h;
h = createlist(a);
printf("原始链表:");
outlist(h);
insert(h);
printf("插入:");
outlist(h);
del(h);
printf("删除:");
outlist(h);
}
NODE * createlist(int a[]){
NODE *h,*p,*q;
int i=0;
h = p = (NODE*)malloc(sizeof(NODE));
p->s = 0;
while(i<N){
q = (NODE*)malloc(sizeof(NODE));
q->s = a[i];
i++;
p->next = q;
p=q;
}
p->next = NULL;
return h;
}
void outlist(NODE *h){
NODE *p;
p = h->next;
while (p){
printf("%d ",p->s);
p=p->next;
}
printf("\n\n");
}
void insert(NODE *h){
NODE *p=h,*q,*temp;
int i,add=2;
int data = 6;
for(i=0;i<add;i++)
p=p->next;
q=(NODE*)malloc(sizeof(NODE));
q->s = data;
q->next=p->next;
p->next=q;
}
void del(NODE *h){
NODE *p=h,*temp;
int i,rmv=3;
for(i=0;i<rmv;i++)
p=p->next;
temp=p->next;
p->next=p->next->next;
free(temp);
}
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 VR小杰
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果