c语言结构体链表
原文链接:http://zhina123.blog.163.com/blog/static/417895782012106036289/
引用自身的结构体,一个结构体中有一个或多个成员的基类型就是本结构体类型时,说明这个结构体可以引用自己,所以称作引用自身的结构体。
例如下面的结构体:
struct link{ char ch; struct link *p} a;
p是一个可以指向struct link类型变量的指针成员,这样,a.p=&a就是合法的表达式。那么,这有什么意义呢?
这样的意义就是我们可以把分散存储的数据项,用一个结构体成员链接起来(当然这也耗费了那个存储指针的内存空间)看下面的程序
#include <stdio.h>
struct node{
int data;
struct node *next;
};
main(){
struct node a,b,c,*p;//我们假设,这样声明的结构体变量a 、b、c在内存中并不是相临的
a.data=; b.data=; c.data=; a.next=&b; b.next=&c; c.next='\0';
p=&a;
//结构体变量a地址赋给p
while(p){
printf(" %d ",p->data);
//每输出一个值后,p自动指向本项的链接项
/*这样有了一个单独保持链接的成员就把不相临的存储单元在逻辑上存储在了一起*/ p=p->next;
}
printf("\n");
}
这样的相链的数据存储形式称为链表!上面形成链表的方法是人为定义的,在程序执行过程中,不会生成新的存储单元,所以也称为“静态链表”
下面看一种更方法使用的“动态链表”
前面的日志中提到了C语言动态存储分配提供了“按需分配内存”的实现方法,有一个问题是,如果多次动态分配存储单元,各存储单元的地址不是一定是连续的,而所需要处理的批量数据往往是一个整体,各数据之间存在着顺序关系,这样,我们可以利用上面的链表把动态得到的存储单元在逻辑上(而不是在物理上)连接起来,就可以实现我们需要的顺序关系了。这时,是把链表技术与动态存储分配结合了起来,所以这里我们给了链表一个新的名词叫做“动态链表”
很自然,我们上面例子中的链表只有一个指向后面数据项的指针,如果有两个呢?一个指后,一个指前,这样就会出现“双向链表”与“单向链表”的区别
下面我们主要看单向链表
事实上,单身链表中的每个存储单元的数据(也就是结构体)的格式类型是相同的(包括数据成员和指针成员)
如下:
struct abc{int data,……struct abc *next;};
与单向链表有关的算法有以下几类:
建立链表 输出结点数据 插入结点数据 删除结点数据
下面这个程序是示例
#include <stdio.h>
#include <stdlib.h>
struct slist{ int data; struct slist *next;};
typedef struct slist SLIST; SLIST *creat_slist(){
/*该函数的作用是创建动态链表,函数的返回值是结构体指针变量,也就是新创建的动态链表的头结点,需要注意的是,这里的头结点没有数据data,只有指针next指向动态链表的第一个结点*/
int c; /*用来临时存储结构体中的data*/
SLIST *h,*s,*r; /*声明工作指针*/
h=(SLIST *)malloc(sizeof(SLIST));
/*动态获取一个结构体的存储空间*/
r=h; /*结构体指针r用来在下面的循环中使用h指针不变*/
scanf("%d",&c); /*得到一个结构体成员int data数据*/
while(c!=-){
/*如果上面得到的int data数据不为-1就进入循环 */
s=(SLIST *)malloc(sizeof(SLIST));
/*循环中用结构体指针s获取结点*/
s->data=c;
/*s成员data为c注意第一次进入循环时,这个c是在循环外部上面输入的*/
r->next=s;
/*r指针本来与h相同,r的成员next在进入循环前是没有指向的现在进入了循环得到了一个结点,就把r的next指向新的结点,这样就使h头结点指向了s*/
r=s;
/*r依次与最新的结点相同,为了依次用最新的存储空间的next指向下一个获得的结点*/
scanf("%d",&c);
}
r->next='\0';
/*退出循环后,r指向最后一个结点,而这个最后结点的成员next要指向'\0'*/
return h;
/*返回动态链表的头结点指针*/
}
void print_slist(SLIST *head){
/*该函数是依次输出动态链表的结点,参数是结构体指针变量,也就是
动态链表的头结点*/
SLIST *p;
/*声明一个工作指针,因为head不能自己往后依次移动,所以用指针
p实现*/
p=head->next;
if(p=='\0')printf("Linklist is null!\n");/*空链表*/
else{printf("head");/*非空链表*/
do{ printf("->%d",p->data);
p=p->next;}while(p!='\0');
printf("->end\n");
} } SLIST *insert_snode(SLIST *head,int x,int y){
/*该函数实现在链表值为x的结点前面插入一个结点,值为y参数有三个链表头结点,值x,y*/
SLIST *s,*p,*q;
/*定义工作指针*/
s=(SLIST *)malloc(sizeof(SLIST));
s->data=y;
/*上面这两句先获取了一个结构体动态存储空间,并给其成员data赋值为y,但此时该空间并未成为链表的一个结点*/
q=head;
p=head->next;
/*上面两句初始化工作指针,就是把工作指针q与head相同,p指向head的next*/
while((p!='\0')&&(p->data!=x)){
/*这个循环是供查找到值为x的结点所在位置的,需要注意的是这里的并的两个条件位置不能变,因为只有在p指向不为空的时候才能讨论其data成员值是否为x,否则如果p的指向是空,程序确要先判断p指向的data是不是x这样会发生地址访问错误,因为p本不指向结点,也就无从谈成员data,所以判断p指向的data是不是x是不对的*/
q=p;p=p->next;
/*满足循环条件的话,p与q依次后移直到找到值为x的结点或到了链表的尾部*/
}
s->next=p;
/*在p指向的结点前面插入,所以新的结点的next指向p*/
q->next=s;
/*q-next本指向p结点,现在令其指向s结点,实现了插入*/ return head;/*头指针并未变化,返回即可*/
} SLIST *insert_bnode(SLIST *head,int x,int y){
/*该函数实现在链表值为x的结点后面插入一个结点,值为y参数有三个链表头结点,值x,y*/
SLIST *s,*p,*q;
/*定义工作指针*/
s=(SLIST *)malloc(sizeof(SLIST));
s->data=y;
/*上面这两句先获取了一个结构体动态存储空间,并给其成员data赋值为y,但此时该空间并未成为链表的一个结点*/
q=head;
p=head->next;
/*上面两句初始化工作指针,就是把工作指针q与head相同,p指向head的next*/
while((p!='\0')&&(p->data!=x)){
/*这个循环是供查找到值为x的结点所在位置的,需要注意的是这里的并的两个条件位置不能变,因为只有在p指向不为空的时候才能讨论其data成员值是否为x,否则如果p的指向是空,程序确要先判断p指向的data是不是x这样会发生地址访问错误,因为p本不指向结点,也就无从谈成员data,所以判断p指向的data是不是x是不对的*/
q=p;p=p->next;
/*满足循环条件的话,p与q依次后移直到找到值为x的结点或到了链表的尾部*/
}
s->next=p->next;
/*在p指向的结点后面插入,所以新的结点的next指向p*/
p->next=s;
/*p-next本指向p后面的结点,现在令其指向s结点,实现了后插入*/ return head;/*头指针并未变化,返回即可*/
} SLIST *del_node(SLIST *head,int x){
/*该函数实现删除链表值为x的结点,参数有两个链表头结点,值x */
SLIST *s,*p,*q;
/*定义工作指针*/
q=head;
p=head->next;
/*上面两句初始化工作指针,就是把工作指针q与head相同, p指向head的next*/
while((p!='\0')&&(p->data!=x)){
/*这个循环是供查找到值为x的结点所在位置的,需要注意的是这里的并的两个条件位置不能变,因为只有在p指向不为空的时候才能讨论其data成员值是否为x,否则如果p的指向是空,程序确要先判断p指向的data是不是x这样会发生地址访问错误,因为p本不指向结点,也就无从谈成员data,所以判断p指向的data是不是x是不对的*/
q=p;p=p->next;
/*满足循环条件的话,p与q依次后移直到找到值为x的结点或到了链表的尾部*/
}
q->next=p->next;
/*把q->next置成p->next,*/
free(p);
/*释放p的存储空间,实现删除*/
return head; /*头指针并未变化,返回即可*/
} main(){
SLIST *head; int x,y;
head=creat_slist();//创建链表函数
print_slist(head);
printf("please input x\n"); scanf("%d",&x);
printf("please input y\n"); scanf("%d",&y);
head=insert_snode(head,x,y);//结点前插入函数
print_slist(head);
printf("please input x\n"); scanf("%d",&x);
printf("please input y\n"); scanf("%d",&y);
head=insert_bnode(head,x,y);//结点后插入函数
print_slist(head);
printf("please input x\n"); scanf("%d",&x);
head=del_node(head,x);//删除结点函数 print_slist(head);
}
c语言结构体链表的更多相关文章
- Go 语言 结构体链表
@ 目录 1. 什么是链表 2. 单项链表的基本操作 3. 使用 struct 定义单链表 4. 尾部添加节点 5. 头部插入节点 6. 指定节点后添加新节点 7. 删除节点 1. 什么是链表 链表是 ...
- Linux C语言结构体-学习笔记
Linux C语言结构体简介 前面学习了c语言的基本语法特性,本节进行更深入的学习. 预处理程序. 编译指令: 预处理, 宏定义, 建立自己的数据类型:结构体,联合体,动态数据结构 c语言表达式工具 ...
- 06. Go 语言结构体
Go语言结构体(struct) Go 语言通过用自定义的方式形成新的类型,结构体是类型中带有成员的复合类型.Go 语言使用结构体和结构体成员来描述真实世界的实体和实体对应的各种属性. Go 语言中的类 ...
- 漫谈C语言结构体struct、公用体union空间占用
先用代码说话: #include<stdio.h> union union_data0{ int a ;//本身占用4个字节 char b ;//本身占用1个字节 int c ; }; u ...
- 解析C语言结构体对齐(内存对齐问题)
C语言结构体对齐也是老生常谈的话题了.基本上是面试题的必考题.内容虽然很基础,但一不小心就会弄错.写出一个struct,然后sizeof,你会不会经常对结果感到奇怪?sizeof的结果往往都比你声明的 ...
- 不可或缺 Windows Native (8) - C 语言: 结构体,共用体,枚举,类型定义符
[源码下载] 不可或缺 Windows Native (8) - C 语言: 结构体,共用体,枚举,类型定义符 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 结构体 ...
- Go语言结构体(struct)
Go 语言结构体 Go 语言中数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型. 结构体是由一系列具有相同类型或不同类型的数据构成的数据集合. 结构体表示一项记录,比如保存图 ...
- C语言结构体定义的几种方法
什么是结构体? 在C语言中,结构体(struct)指的是一种数据结构,是C语言中聚合数据类型(aggregate data type)的一类.结构体可以被声明为变量.指针或数组等,用以实现较复杂的数据 ...
- 对嵌入式开发C语言结构体的一点总结
今天冬至居然不上班,公司的良心啊!这回有心情写博客和日志了,好了,废话不多说.直接看下文: 鉴于嵌入式开发过程中,C语言结构体的使用当然是必不可少.话说,基础什么的比你会更牛逼的算法更重要,基础不牢, ...
随机推荐
- CALL transaction 的用法-传内表
使用memory (这个方法和第二种方式的区别是可以传输复选框的值) data: wfbomcom type rc29n. move-corresponding bom_key to wfbomc ...
- bean生命周期_Junit测试使用factory模式
在面试某互联网_保险 公司, 被问到了spring中bean的生命周期,不禁联想到我们之前作 junit测试时,使用了Factory模式,而没有用Mock.
- matlab函数拟合
1 函数拟合 函数拟合在工程(如采样校正)和数据分析(如隶属函数确定)中都是非常有用的工具.我这里将函数拟合分为三类:分别是多项式拟合,已知函数类型的拟合和未知函数类型的拟合.matlab中关于函数的 ...
- (轉)EasyUI - DataGrid 去右边空白滚动条列
熟悉 EasyUI - DataGrid 的童鞋应该会注意到这样一个情景: 想去掉这块,找了下资料,发现也有人同样纠结:http://www.cnblogs.com/hantianwei/p/3440 ...
- javascript 高级程序设计 八
function 类型: 1.ECMAscript中函数和类C语言的函数有这很多不同.其中之一就是js的函数没有重载.并且多次定义一个同名的函数,当调用这个函数的时候, 会调用最后一次定义的函数. 2 ...
- C++连接MySQL(Windows)
一般来说,VS下采用微软自身的SQL Server是比较常见的做法,但SQL Server只适合学习,不适合真正应用.在此,我们选择MySQL作为后台数据库.C++语言本身并没有提供访问数据库的东西, ...
- Partition Equal Subset Sum
Given a non-empty array containing only positive integers, find if the array can be partitioned into ...
- tolua杂记
1 字符串调用luaFunc :DoString public class CallLuaFunction : MonoBehaviour { private string script = @&q ...
- mysql Error_code: 1593
mysql slave_IO_running no 查看data目录下的.err文件提示:mysql Error_code: 1593 解决方法: 1.检查 data目录下auto.cnf 文件中 ...
- Twitter 相关APP开发
首先要获取 Consumer Key (API Key), Consumer Secret (API Secret):最好申请Access Token 和Access Token Secret,不然验 ...