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=10;  b.data=20; c.data=30; 

 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!=-1){
 /*如果上面得到的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);
}
时间: 2024-08-06 20:48:49

c语言结构体链表的相关文章

学习C/C++语言:结构体,动态链表

//*************************************************************** //结构体:简单的静态链表 #include<stdio.h> #include<string.h> #define NULL 0 #define SIZE 10 struct student { char num[SIZE]; float score; struct student *next; }; void main() { struct stu

C语言 结构体指针赋值 incompatible types when assigning to type &#39;char[20]&#39; from type &#39;char *&#39;

strcpy(pstudent->name, "guo zhao wei "); 为什么错误,该怎么写,(红色行) 追问 为什么不能直接赋值啊, 追答 用char nnnn[20]定义的,用strcpy 用char *ppp定义的,用=来赋值 C语言 结构体指针赋值 incompatible types when assigning to type 'char[20]' from type 'char *'

漫谈C语言结构体struct、公用体union空间占用

先用代码说话: #include<stdio.h> union union_data0{ int a ;//本身占用4个字节 char b ;//本身占用1个字节 int c ; }; union union_data1{ short a;//本身占用2个字节 char b[13];//本身占用13个字节 int c ;//本身占用4个字节 }; struct struct_data{ int a ;//int本身占用4个字节,偏移量为0 char b ;//char本身占用1个字节,偏移量为

C语言结构体,C语言结构体指针,java对象引用,传值,传地址,传引用

C语言结构体,C语言结构体指针,java对象引用,传值,传地址,传引用 传值 把实参的值赋值给行参 那么对行参的修改,不会影响实参的值 传地址 传值的一种特殊方式,只是他传递的是地址,不是普通的如int 那么传地址以后,实参和行参都指向同一个对象 传引用 真正的以地址的方式传递参数 传递以后,行参和实参都是同一个对象,只是他们名字不同而已 对行参的修改将影响实参的值 所谓变量是内存地址的一个抽象名字,在静态编译的程序中,所有变量名都会在编译时转换成内存地址,机器不知道变量名,只知道地址. C 语

c 结构体链表初探

结构体链表 1 #include <stdio.h> 2 struct tnode 3 { 4 char *word; 5 int count; 6 struct tnode *left; 7 struct tnode *right; 8 }; 9 10 int main(int argc, char const *argv[]) 11 { 12 13 struct tnode a, b, c, *tmp; 14 a.word = "a"; 15 b.word = &quo

C语言结构体(struct)常见使用方法(转)

本文转自 CSDN huqinweI987 基本定义:结构体,通俗讲就像是打包封装,把一些有共同特征(比如同属于某一类事物的属性,往往是某种业务相关属性的聚合)的变量封装在内部,通过一定方法访问修改内部变量. 结构体定义: 第一种:只有结构体定义 [cpp] view plaincopy struct stuff{ char job[20]; int age; float height; }; 第二种:附加该结构体类型的“结构体变量”的初始化的结构体定义 [cpp] view plaincopy

C语言结构体赋初值

C语言结构体赋初值,特别是结构体中含有数组成员是,最后一个逗号最好是不要多写.因为有些时候可能会出错.图中,红色的框框处.

读陈浩的《C语言结构体里的成员数组和指针》总结,零长度数组

原文链接:C语言结构体里的成员数组和指针 复制如下: 单看这文章的标题,你可能会觉得好像没什么意思.你先别下这个结论,相信这篇文章会对你理解C语言有帮助.这篇文章产生的背景是在微博上,看到@Laruence同学出了一个关于C语言的题,微博链接.微博截图如下.我觉得好多人对这段代码的理解还不够深入,所以写下了这篇文章. 为了方便你把代码copy过去编译和调试,我把代码列在下面: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <stdio.h>

c 语言 结构体

结构体初学者都有点小怕其实思维清晰之后你会发现结构体是个非常好的东西,嘿嘿. 第一,结构体的定义和初始化.别被书上大量的描述吓到 1.怎么定义结构体了例子如下,我们以构建一个包含学生姓名,年龄,Email为例子 1 struct 2 { 3 char name; 4 int age; 5 char Email; 6 }person; 现在我们定义就已经完成了,当然这是我最喜欢的范式,你们也可以在书上找到自己喜欢的. 2.怎么初始化了?结构体一般初始化都是以结构体数组的形式来的所以我们只说这个 t