第三章    数据结构

章首:不好意思,这两天要帮家里做一些活儿。而且内容量与操作量也确实大幅提升了。所以写得很慢。

不过,从今天开始。我写的东西,许多都是之前没怎么学的了。所以速度会慢下来,同时写得也会详细许多。

第三章是数据结构,数据结构可以说是理论学习的重点。同时许多学校(包括我所就读的大学)都开设了数据结构课程。但是讲的东西大多太过理论性,主要讲解概念与思想。

另外,数据结构可是计算机考研中专业课的重点科目哦。

这章数据结构包括结构体、链表、栈与队列、串与广义表、二叉树、图与图的应用。

每一个都是重点,所以我会细细地过一遍。

3.1结构体

ps:也许你的C语言老师不会讲解链表、二叉树等,但他一定会讲解结构体的使用,并且让你们作出代码实现。

结构体是什么?其实结构体就是一个制式容器。里面包括了规定的各个变量。

比如说,我设定了

 1 struct student
 2 { 3   char name;
 4   int age;
 5   float score;6 };

那么在这个结构体所在的程序里,student就是一个包含三个不同数据类型的变量。当然,你也可以认为student是一个新的数据类型,一个自己设立的数据类型。不过这个数据类型是一个特定的数组,因为其中有着许多不同的数据类型(数组只能是相同数据类型)。

创建结构体是要用到struct。其他用法将在接下来的例子中提到。

实例076

问题:从键盘中输入姓名和电话号码,以#结束,编程实现输入姓名,查询电话号码的功能。

逻辑:首先一个主函数作为程序入口,实现程序运行框架。然后一个存储函数readin实现数据的存储,再一个查询函数seach实现数据的查找。

主函数无非定义,初始化变量。调用存储函数来存储我们输入的函数。再调用查询函数来输出所要的结果。

存储函数定义,初始化变量。建立循环,判读输入是否为#,同时将数据存储。

查询函数定义,初始化变量。建立循环,判断所要查找的数据与当前数据是否符合,判断数据是否已经全部遍历。

代码

 1 #include<stdio.h>
 2 #include<string.h>
 3 #define MAX 101
 4 struct aa
 5 {
 6   char name[15];
 7   char tel[15];
 8 };
 9 int readin(struct aa *a)
10
11 //注意这里结构体aa的变量名为*a,是一个指针,因为这个结构体在三个函数中均被调用。所以只有使用指针才较为便利地可以实现函数间大量数据的调用。
12
13 //其实,在使用指针为变量时,就已经建立了一个以a为名的aa型结构体数组了。
14
15 {
16   int i=0,n=0;
17   while(1)
18
19   //本人最为喜欢的循环体设置方法,包括for(;1;)的设立,循环体中再建立相关判断条件。
20   {
21     scanf("%s",a[i].name);
22     if(!strcmp(a[i].name,"#"))
23
24     //利用这样的判断语句判断输入是否为#,(其实可以在判断语句中实现赋值与判断的共同实现,虽然好看,但是确保自己逻辑正确。)
25
26     //strcmp()比较两个字符串是否相等,相等返还0,相等返还0,相等返还0.
27       break;
28     scanf("%s",a[i].tel);
29     i++;
30     n++;
31   }
32   return n;
33
34   //返回输入结构体的数量。(一组数据就是一个结构体)
35 }
36 void search(struct aa *b,char *x,int n)
37
38 //x是一个指针,主函数中name是数组名,即一个指针。
39 {
40   int i;
41   i=0;
42   while(1)
43   {
44     if(!strcmp(b[i].name,x))
45     {
46       printf("name:%s            tel:%s\n",b[i].name,b[i].tel);
47       break;
48     }
49     else
50       i++;
51     n--;
52
53     //其实这个n是用来计算是否所有结构体遍历。但是我认为用i就行了。虽然i是在判断语句里面,但这个语句在没找到目标是是一直执行的,如同在外面和n相同待遇
54
55     //当判断语句找到目标时,那就更不需要他了。因为程序结束了。
56
57     if(n==0)
58     {
59       printf("No found!");
60       break;
61     }
62   }
63 }
64 main()
65 {
66   struct aa s[MAX];
67   int num;
68   char name[15];
69   num=readin(s);
70
71   //这个语句有两个用处,1.将readin函数返回给num;2.readin函数将数据存储于数组s。
72   printf("input the name:");
73   scanf("%s",name);
74   search(s,name,num);
75 }

反思:结构体在日后的使用中,就好像int、char这些数据类型一般,很常用。同时,这个程序中,我们学到程序中函数的简单架构。另外,我们完全可以将这个函数扩展化。比如小到平时存储东西,查找东西。大到各个程序中的存储,查找功能等。

3.2链表

ps:一般来说,数据结构这门课讲解的第一个数据结构一般就是链表。很多教材第一页就是链表。

曾经有公司高层谈论编程时,说:”学生大多缺乏实际编程经验,我在招聘时经常让应聘者做一个简单的链表。结果很多人都不会。“

链表可以说是数据结构应用的入门,如果连这个都不会,最好别去考虑与编程有关的职业。

曾经看过一本书,它的开头讲述了一个故事。说有一个刚入行的程序员第一次处理网站数据,做了一个1500长度的数组和循环用来存储临时数据。然后不久那个网站就挂了。后来作者去就将他做得数组改成了一个1500的循环链表就完事儿了。

链表是动态分配存储空间来存储数据,避免了空间的浪费。(当年用数组存储数据有多少人和我一样纠结空间大小的举个手)同时,链表的存储空间可以不连续、不连续、不连续。这样产生了许多便利,并且有效利用了存储空间。

我会讲解每一个例子。(我才不会说,之前看的时候,我就记得单向链表了。。。)

实例078    创建单向链表

问题:创建一个单向链表,实现数据的输入、输出。

逻辑:链表是由一个个节点组成的。每一个节点分为两部分:数据域与指针域。数据域用来存储数据,指针域用来存储下一个节点位置(双向链表就还有一个指向前一个节点的链表)。一般第0个节点是整个链表的头结点,称为”头指针“,一般不存放数据,只存放指向第1个节点的指针。链表的最后一个节点的指针设为空(NULL),作为链表的结束标志。

代码

 1 #include<stdio.h>
 2 #include<malloc.h>
 3 //malloc是用来划分存储空间的函数。
 4 struct LNode
 5 {
 6   int data;
 7   struct LNode *next;
 8   //指向下一个的结构体。从而形成链表。
 9 };
10 struct LNode *create(int n)
11 {
12   int i;
13   struct LNode *head,*p1,*p2;
14   //head表示头节点。p1,实现存储空间的获取,数据域赋值等。p2,作为与p1的中间指针,构成链表的替换连接。
15   int a;
16   head=NULL;
17   //头节点为空。
18   printf("Input the integers:\n");
19   for(i=n;i>0;--i)
20   {
21     p1=(struct LNode*)malloc(sizeof(struct LNode));
22     //malloc(sizeof(struct LNode)表示划分LNode大小的存储空间。
23     //(struct LNode*)表示数据类型的转换,将划分来的存储空间首地址转化为LNode的变量名(指针类型)。
24     scanf("%d",&a);
25     p1->data=a;
26     //向p1的结构体中存储数据。
27     if(head==NULL)
28     {
29       head=p1;
30       p2=p1;
31       //对头节点的处理。
32     }
33     else
34     {
35       p2->next=p1;
36       //表明p2的下一个节点是p1。其中p2是上个循环中的p1。也就是说,p2只是一个中间变量temp。
37       p2=p1;
38       //印证了上个注释中,p2的由来。
39       //具体的过程在变量名的说明中就已经体现了。
40     }
41   }
42   p2->next=NULL;
43   //最后一个节点的指针域为空,作为结束的标志。
44   return head;
45   //返回代表头结点的结构体的变量名(指针)。
46 }
47 void main()
48 {
49   int n;
50   struct LNode *q;
51   printf("Input the count of the nodes you want to creat:");
52   scanf("%d",&n);
53   q=create(n);
54   //输入,返回。
55   printf("The result is:\n");
56   while(q)
57   //q只有到了最后一个节点的next时,为NULL,才会跳出循环。一个很有用的小技巧。
58   {
59   printf("%d    ",q->data);
60   q=q->next;
61   //实现q的转换,从而输出所有数据。
62   }
63   getch();
64 }

ps:如果对其中提到的malloc函数,以及相关的calloc函数,free函数感兴趣的话,可以浏览http://blog.csdn.net/shuaishuai80/article/details/6140979。

反思:学习该例有这么几个要点: 1.指针不要混淆,不要将结构体名的指针和结构体内next的指针混淆,虽然有时这两者表达的是同一个东西;

                2.一定要完全理解p1=(struct LNode*)malloc(sizeof(struct LNode));这句代码;(解释在样例中)

                3.正确理解p2->next=p1;与p2=p1;这两句代码的实现。(无法理解可带入数据进行两到三次循环,即可理解)。  

实例079    创建双向链表

问题:创建一个双向链表 ,并将这个链表中数据输出到窗体上,输入要查找的学生姓名,将查找的姓名从链表中删除,并现实删除后的链表。

逻辑:其实就逻辑而言是很简单的。与之前的单向链表相同,不过比后继结点的设置多了一个前驱节点的设置。另外查找,与一般的结构体数组查找,并没有什么区别。至于删除嘛,就需要改动删除节点的前驱节点和后继结点的设置。具体操作,可以看代码。

代码

  1 #include<stdio.h>
  2 typedef struct node
  3 {
  4   char name[20];
  5   struct *prior,*next;
  6   //设立节点的前驱节点和后继结点。
  7 }stud;
  8 stud *creat(int n)
  9 {
 10   stud *p,*h,*s;
 11   int i;
 12   h=(stud*)malloc(sizeof(stud));
 13   //申请存储空间
 14   h->name[0]='\0';
 15   //设置name为空
 16   h->prior=NULL;
 17   h->next=NULL;
 18   p=h;
 19   for(i=0;i<n;i++)
 20   {
 21     s=(stud*)malloc(sizeof(stud));
 22     p->next=s;
 23     printf("Input the %d student'sname:",i+1);
 24     scanf("%s",s->name);
 25     s->prior=p;
 26     s->next=NULL;
 27     p=s;
 28     //方法和单向链表没什么区别,区别只在于多了一个前驱节点的设置。
 29     //从一些方面来说,多了前驱节点更容易理解了。
 30   }
 31   p->next=NULL;
 32   //设置最后节点的后继结点为空,作为结束标志。
 33   return(h);
 34 }
 35 stud *search(stud *h,char *x)
 36 {
 37   stud *p;
 38   char *y;
 39   p=h->next;
 40   while(p)
 41   {
 42     y=p->name;
 43     if(strcmp(y,x)==0)
 44     //判断是否为寻找的目标。
 45       return(p);
 46       //返回目标地址。
 47     else
 48       p=p->next;
 49       //继续下一个节点的检测。
 50   }
 51   printf("cannot find data!\n");
 52   //没有任何符合条件的返回。
 53 }
 54 void del(stud *p)
 55 {
 56   p->next->prior=p->prior;
 57   //令p的下一个节点的前驱节点与现在p的前驱节点一致(这样在前驱节点中p就不存在了。并且链表没有断开。)
 58   p->prior->next=p->next;
 59   //令p的前一个节点的后继结点与现在p的后继结点一致(这样在后街节点中p就不存在了。并且链表没有断开。)
 60   //切记:p->next是指p的后一个节点。p->prior同理。
 61   //无法理解的话,请在草稿纸上画出链表图,就清晰无比了。
 62   //这里两句代码在有些运行环境中会报错,可以自行更改语句或环境。
 63   free(p);
 64   //释放p的存储空间(链表上p已经不存在了。当然不能让它占着空间了)
 65 }
 66 main()
 67 {
 68   int number;
 69   char sname[20];
 70   stud *head,*sp;
 71   puts("Please input the size of the list:");
 72   scanf("%d",&number);
 73   head=creat(number);
 74   sp=head->next;
 75   printf("\nNow the double list is:\n");
 76   while(sp)
 77   {
 78     printf("%s",&*(sp->name));
 79     sp=sp->next;
 80   }
 81   //之前的都与单向链表相同。
 82   printf("\nPlease input the name which you want to find:\n");
 83   scanf("%s",sname);
 84   sp=search(head,sname);
 85   //通过search函数,寻找到所要寻找的sname的地址sp。
 86   printf("the name you want to find is:\n",*&sp->name);
 87   del(sp);
 88   //将sp带入到del()函数中,删除。
 89   sp=head->next;
 90   //这句话只是为了下面的while循环做二次利用的。完全可以删除这句话,为下面的循环单独设置一个变量。
 91   printf("\nNow the double list is:\n");
 92   while(sp)
 93   {
 94     printf("%s",&*(sp->name));
 95     sp=sp->next;
 96   }
 97   printf("\n");
 98   puts("\nPress any key to quit...");
 99   getch();
100   //与单向链表相同的输出原理。
101 }

 反思:双向链表与单向链表并没有什么不同。要记得的是,双向链表可是比单向链表多了一个prior的指针,无论是添加,删除,移动,修改,都要记住。

实例080    循环链表

还记得开头,我说的那个网站关于链表的故事吗。这下说的就是循环链表。

其实到了这个时候也就没有什么说的了。循环链表就是将最后节点的后继结点设置为头结点。

循环链表与普通链表的操作基本一致,只是在算法中循环遍历链表节点时判断条件不再是p->next是否为空,而是是否等于链表的头结点

程序代码:(这里就不演示。篇幅不应该留给不需要的东西。)

实例081    双链表逆置

问题:创建一个双向链表,将双向链表的节点逆置,即将尾节点放到第一个节点的位置,倒数第二个节点放到第二个节点的位置,依此类推。

逻辑:双向链表的创建、输入、输出,都和之前一样。为了模块化的操作,就单独创建一个reverse函数,用来执行逆置操作。逆置操作就是指针的变换。

部分代码

 1 stud *reverse(stud *head)
 2 {
 3   stud *p,*r,*h;
 4   h=head->next;
 5
 6   //设置h。
 7   if(h&&h->next)
 8   {
 9     p=h;
10     r=p->next;
11     p->next=NULL;
12     while(r)
13     {
14       p=r;
15       r=r->next;
16       p->next=h;
17       h->prior=p;
18       h=p;
19
20       //中间变量p,变量r从链表的头部向后遍历,变量h从链表的尾部向前遍历。变量p作为中间变量来转移指针地址,完成链表逆置。
21     }
22     head->next=h;
23     h->prior=head;
24
25     //事后,完成链表的补全。即链表的开头和结尾。
26     return head;
27   }
28 }

反思:想要完成这些,自己一定不能混淆指针,指针的指针,指针的指向。这三个概念。

后面还有很多相关的知识,比如逆序输出,约瑟夫环,链表的元素插入,节点插入,节点删除,合并链表以及头插入法建立链表等。但是,我认为,如果之前的链表都懂了。那么后面的知识无非就是链表的基础知识版应用。如果有需要,可以找我。

总结:其实链表在学习后,就会发现,之前指针学得好是多么重要啊。尤其是指针的指针这一点。如果,指针学得好,那么链表要学的就是链表的概念,链表的一些专用函数,以及常用的算法。那么之后的一些应用就是水到渠成的事儿。(完全就是之前程序的链表版应用啦。)

由于时间关系,这次就先写这么多了。(其实这次写的比之前多了很多,尤其线下还做了那么多的程序调试。)

谢谢大家的鉴赏和评价。也希望能够结识一些相关兴趣的小伙伴。

另外,也许不久,我还会写一些别的东西。

(刚刚博客园官方通知了我,我才知道有代码插入这个东西。挺赞的。对于我这个有代码行洁癖的,每次copy后敲Tab,也是蛮难过的。谢谢了。)

转载于:https://www.cnblogs.com/Tiancheng-Duan/p/5702134.html

C语言范例学习03-上相关推荐

  1. C语言再学习 -- Linux下find命令用法

    参看:linux下find(文件查找)命令的用法总结 linux下查找文件的命令有两个:locate 和 find 首先说一下locate: 这个命名是对其生成的数据库进行遍历(生成数据库的命令:uo ...

  2. EDA实验课课程笔记(三)——TCL脚本语言的学习1

    本文参考资料为<Tcl语言教程>,感谢作者的分享,这里仅仅作为简单常用语法的入门,若有需要后期对本文进行添加补充. EDA实验课课程笔记(三)--TCL脚本语言的学习 前言(TCL综述) ...

  3. c语言编程学多久,丰城c语言编程学习,丰城学c语言编程的学校,丰城学c语言编程一般要多久才能学会...

    丰城c语言编程学习,丰城学c语言编程的学校,丰城学c语言编程一般要多久才能学会 首页 > 软件 > 丰城c语言编程学习 作者:镀金池   发布时间:2018-04-09 16:40 在之后 ...

  4. C语言报名里面培训怎么填,庄河c语言编程学习,庄河学c语言编程培训,庄河学c语言编程报个培训班怎么样...

    庄河c语言编程学习,庄河学c语言编程培训,庄河学c语言编程报个培训班怎么样 首页 > 软件 > 庄河c语言编程学习 作者:镀金池   发布时间:2017-11-29 11:13 明天利用时 ...

  5. 安庆师范大学c语言程序设计,安庆c语言编程学习,安庆学c语言编程培训,安庆学c语言编程一般能拿多少工资...

    安庆c语言编程学习,安庆学c语言编程培训,安庆学c语言编程一般能拿多少工资 首页 > C语言 > 安庆c语言编程学习 作者:镀金池   发布时间:2017-10-18 15:20 假定我们 ...

  6. c语言 字母 八进制表示'/1011',C语言C语言第一课:C语言概述为什么学习C语言怎样学习C语言.DOC...

    [摘要]C语言 第一课: C语言概述 为什么学习C语言 怎样学习C语言 参考资料 ----------------------------------------------------------- ...

  7. 秦州:西瓜书 + 南瓜书 吃瓜系列 13. 降维与度量学习(上)

    吃瓜教程--西瓜书+南瓜书 Datawhale南瓜书是经典机器学习教材<机器学习>(西瓜书)的公式推导解析指南,旨在让在学习西瓜书的过程中,再也没有难推的公式,学好机器学习. 内容属性:机 ...

  8. R语言可视化学习笔记之相关矩阵可视化包ggcorrplot

    本文转载自"R语言中文社区",己获授权. 作者简介Introduction taoyan:伪码农,R语言爱好者,爱开源. 个人博客: https://ytlogos.github. ...

  9. 一文回顾深度学习发展史上最重要经典模型

    这篇文章的目的是回顾经过时间考验的,被广泛采用的想法.我将介绍一小部分技术,这些技术涵盖了解现代深度学习研究所必需的许多基本知识.如果你是该领域的新手,那么这是一个很好的起点. 深度学习是一个瞬息万变 ...

  10. c语言struct_学习了C语言之后还是感觉不会编程,应该怎么办?其实你想错了!...

    其实对于程序而言,C语言抑或着C++.Java等其他程序语言只是用于表达你的想法的一个工具.就像让我们以建筑为例,画图是一个基本功,但是画什么才是核心所在.那么,今天我们以一个设计一个RPG(角色扮演 ...

最新文章

  1. kvm_guest主机克隆
  2. 计算机组装与维护教案_计算机组装与维护小课堂(1)
  3. 通过jsl工具将java程序注册为windows服务
  4. 二 DeepinV20版本安装
  5. 初学Java Web(3)——第一个Servlet
  6. ajax 获取服务器返回的XML字符串
  7. 软件项目管理的内在定律
  8. threading模块的使用
  9. NUll is null like
  10. 【报告分享】零售行业三大平台之对比分析-阿里VS京东VS拼多多:分级、竞争、进化.pdf...
  11. Windows程序开发——指挥官夏尔对于Windows程序开发框架的选择
  12. linux php oauth安装,Linux安装phpmyadmin
  13. 奔图 Pantum M6550 打印机驱动
  14. 新基建促进智能化基础设施管控平台的搭建
  15. Mac os 10.5.8, 驱动声卡成功
  16. beacon帧主要结构
  17. 高通骁龙600系列处理器
  18. pytorch【Conv2d参数介绍】
  19. 目标检测比赛提高mAP的方法
  20. “一阶数字低通滤波器”原理推导(含仿真和代码实现)

热门文章

  1. 关于Mysql datetime类型存储范围测试
  2. ubantu删除文件(夹)
  3. 字符串匹配-kmp算法
  4. Angular实现购物车计算
  5. 关于memcpy和 strcpy的区别 以及memset
  6. Error:Execution failed for task ':app:clean'. Unable to delete directory: /media/file/workspaces/a
  7. mabatis传入参数
  8. SQLserver查询练习
  9. zencart 1.5.1 英文原版 安装前和安装后目录文件的变换
  10. 在BizTalk Server 2006 R2 中调用 WCF Services – Part 3