作为编程语种链最底层的OG(元老),相信无论是学Java,python,JS还是其他语种的小伙伴们,都或多或少地听说过我们年长的长辈,c语言!那么今天,博主就带大家讲解一篇由我操刀的c语言学生管理系统!!!手把手,深入浅出地带你玩飞c语言!!!It is show time!
首先,在手撸管理系统之前,我们想到,诶,写这玩意儿应该会用到某种数据结构吧,什么?你问我数据结构是什么?不明白数据结构是啥玩意儿的小伙伴们看过来,我悄悄告诉你:其实…它特么的就是一个随便你咋定义的一种自定义变量组成的各种稀奇古怪的结构空间,对,你没听错,就是你完全可以天马行空地自创无数种数不清的“数据结构”,咳咳,前提是你脑洞够大哈。既然如此,数据结构那么多!而且居然还能按照自己想法想怎么设计怎么设计!这就不友好了吧,你特么的那么多,我怎么选择啊,欸,问题就来了,既然种类繁多,鱼龙混杂,那么我们就选择计算机科学家这些行业大佬共同设计的标准到不行的数据结构吧!比如,最简单的!链表!!!,链表表示,老板,给我结一下出场费哈:
不了解链表原理的童鞋们请…百度!百度!百度!当然也可以谷歌!谷歌!谷歌!重要的事情说三遍,相信以你们帅气的面庞,无敌的智慧,一定会和博主小时候一样,看一遍就眉头微皱,仰头叹息:TMD,我这么聪明,想必一定背负着上天赐给我的重任啊,若干年后,尼玛!重任就是写博客?这真特么重啊!!!
导演:行了啊,沙石乐,垃圾话到此为止!我: 好吧…开始正片吧!
- 链表模块:
首先,博主先附上几张自己DIY的链表结构图,让大家能清晰地知道这条链表到底,长啥样!如下:
图扔完了,那么接下来就是干正事的时候了,话不多说,扔代码!:
//节点:
struct Node{
//姓名:
char *name;
//性别:
int gender;
//年龄:
int age;
//分数:
double scores;
//指针域:
struct Node *next;
};
typedef struct Node * NodeRef;
//链表:
struct List{
//头指针:
NodeRef list;
//尾指针:
NodeRef rear;
//链表长度:
int length;
};
typedef struct List * ListRef;
//创建一个节点:
NodeRef newNode(const char *name,const int gender,const int age,const double scores);
//创建一个链表:
ListRef newList(NodeRef * nodes,const int len);
//尾插:
NodeRef push(ListRef list,NodeRef node);
//尾删:
int pop(ListRef list);
//头插:
NodeRef unshift(ListRef list,NodeRef node);
//头删:
int shift(ListRef list);
//插入:
NodeRef insert(ListRef list,NodeRef node,int pos);
//删除:
int remove(ListRef list,const int pos);
//查找:
NodeRef find(ListRef list,const int pos);
//修改节点信息:
int set(ListRef list,const int pos,NodeRef node);
//输出节点:
void display(NodeRef node);
//迭代链表:
int foreach(ListRef list);
3.链表函数接口的实现:
NodeRef newNode(const char *name,const int gender,const int age,const double scores){
NodeRef node = (NodeRef)malloc(sizeof(struct Node));
if(name == null)
node->name = null;
if(name != null){
node->name = (char *)malloc(sizeof(char) * strlen(name));
strcpy(node->name,name);
}
node->gender = (int)gender;
node->age = (int)age;
node->scores = scores;
node->next = null;
return node;
}
ListRef newList(NodeRef * nodes,const int len){
if(nodes == null || len <= 0)
return null;
for(int i = 1;i <= len - 1;++i)
nodes[i - 1]->next = nodes[i];
ListRef list = (ListRef)malloc(sizeof(struct List));
list->list = nodes[0];
list->rear = nodes[len - 1];
list->length = (int)len;
return list;
}
NodeRef push(ListRef list,const NodeRef node){
if(list == null || node == null)
return null;
list->rear->next = (NodeRef)node;
list->rear = list->rear->next;
++list->length;
return (NodeRef)node;
}
int pop(ListRef list){
if(list == null)
return -1;
NodeRef move = list->list;
while(TRUE){
move = move->next;
if(move->next == list->rear)
break;
}
free(list->rear);
list->rear = move;
--list->length;
return 0;
}
NodeRef unshift(ListRef list,NodeRef node){
if(list == null || node == null)
return null;
node->next = list->list;
list->list = node;
++list->length;
return node;
}
int shift(ListRef list){
if(list == null)
return -1;
NodeRef target = list->list;
list->list = list->list->next;
free(target);
--list->length;
return 0;
}
NodeRef insert(ListRef list,NodeRef node,int pos){
if(list == null || node == null)
return null;
if(pos < 0)
pos = 0;
if(pos >= list->length)
pos = list->length - 1;
if(pos == 0){
node->next = list->list;
list->list = node;
}
if(pos == list->length - 1){
list->rear->next = node;
node->next = null;
list->rear = node;
}
if(pos > 0 && pos < list->length - 1){
NodeRef pre = find(list,pos - 1);
node->next = pre->next;
pre->next = node;
}
++list->length;
return node;
}
int remove(ListRef list,const int pos){
if(list == null || pos < 0 || pos > list->length - 1)
return -1;
if(pos == 0){
NodeRef target = list->list;
list->list = list->list->next;
free(target);
}
if(pos != 0){
NodeRef pre = find(list,pos - 1);
NodeRef target = pre->next;
pre->next = pre->next->next;
free(target);
if(pos == list->length - 1)
list->rear = pre;
}
--list->length;
return 0;
}
NodeRef find(ListRef list,const int pos){
if(list == null || pos < 0 || pos > list->length - 1)
return null;
NodeRef move = list->list;
for(int i = 0;i <= pos - 1;++i)
move = move->next;
return move;
}
int set(ListRef list,const int pos,NodeRef node){
if(node == null)
return -1;
if(pos == 0){
node->next = list->list->next;
free(list->list);
list->list = node;
return 0;
}
NodeRef pre = find(list,pos - 1);
if(pre == null)
return -1;
if(pre->next == list->rear)
list->rear = node;
NodeRef target = pre->next;
pre->next = node;
node->next = target->next;
free(target);
return 0;
}
void display(NodeRef node){
if(node == null)
return;
printf("| name: %s \n| gender: %s \n| age: %d \n| scores: %lf \n\n",node->name,node->gender == Male ? "male" : "female",node->age,node->scores);
}
int foreach(ListRef list){
if(list == null)
return -1;
NodeRef move = list->list;
for(int i = 0;i <= list->length - 1;++i){
printf("| name: %s \n| gender: %s \n| age: %d \n| scores: %lf \n\n",move->name,move->gender == Male ? "male" : move->gender == Female ? "female" : "Unknown",move->age,move->scores);
move = move->next;
}
return 0;
}
吃瓜群众:沙石乐,你这代码贴是贴上去了,关键是我们这群直来直往的大老爷们儿看不懂撒,看不懂哟!
我:纳尼,不要逼我飙出日本话哈。那行吧,下面就是链表接口的讲解讲解讲解,但是为了拒绝白嫖以及让童鞋们发挥自我学习的能力,哥们我只讲思路,如果讲完还是看不懂,那你就!再看一遍…
newNode接口解析:
功能:接受一系列学生信息数据,然后生成一个Node,最后通过返回值扔给用户
咋写滴呢:
接受到参数后,创建一个Node结构体@#¥&*…把传入的参数赋值进去,写完了!(太过简单的逻辑不多说哈!)
newList接口解析:
功能:接受一个node节点的数组,然后生成一个List链表,最后通过返回值扔给用户
咋写滴呢:
接受到参数后,将数组从前往后,依次通过指针区域链接起来,就好比,你和你的一堆朋友,排成一列,第一个骚年拉着他后面少女的手,这个少女拉着她后面另一个骚年的手,这个骚年再拉着他后面另一个少女的手,就这么循环拉着,一个队伍全部从前往后彼此拉着彼此,大家手拉手,我们还是好基友(特此澄清,我没有在搞绿色大草原哈,这话你信么?不管你信不信,反正我身正不怕影子斜,我自己绝对不信!),最后拉完手(链接完后的节点数组),将自己数组的第一个元素(头节点,俗称脑袋)交给链表的头节点指针成员(它:就问你怕不怕,脑袋在我手里嘿),同样的,把节点数组的最后一个元素交给链表的尾节点成员(友情提示,rear是指尾部噢,咳咳,装个毫无激情的b),同时将节点数组的长度赋给链表的len成员,以此来监控链表的长度。
push接口解析:
功能:接受一个链表,接受一个要插入的节点,然后将节点插入链表尾部,返回插入的节点引用。
咋写滴呢:
接受到参数后,@#¥&*…通过链表的rear成员找到链表尾部,然后,往尾部插!,写完了!,对了不要忘记更新rear的指向喔,因为插入后的尾部不将是尾部了,那已经变成颈椎了…(太过简单的逻辑不多说哈!)
pop接口解析:
功能:接受一个链表,然后把链表尾部元素弹出去,俗称:卖屁股!
咋写滴呢:
接受到参数后,@#¥&*…通过rear找到尾部元素,然后用你的卖屁股大法卖掉自己的屁股,然后用卖屁股的钱开开心心地去吃喝完了就完事了
unshift接口解析:
功能:接受一个链表,接受一个节点,然后将要插入的节点往头部插入
咋写滴呢:
接受到参数后,@#¥&*…然后通过链表的list成员找到头部位置,然后将要插入的节点往头部插入…(太简单了,不用多说了)
shift接口解析:
功能:接受一个链表,然后把头节点弹出,俗称:卖脑袋
咋写滴呢:
接受到参数后,@#¥&*…然后通过链表的list成员找到头部位置,然后将头节点直接再二手市场卖掉…(太简单了,不用多说了)
find接口解析:
功能:接受一个链表,接受一个位置,然后找到该位置的节点并返回
咋写滴呢:
接受到参数后,@#¥&*…通过pos - 1找到要插入的位置的前一个节点的位置,然后将要插入的节点往找到的节点与其后的节点中间插入…(太简单了,不用多说了)
insert接口解析:
功能:接受一个链表,接受一个节点,接受一个要插入的位置,然后插入节点
咋写滴呢:
接受到参数后,@#¥&*…通过pos - 1找到要插入的位置的前一个节点的位置,然后将要插入的节点往找到的节点与其后的节点中间插入…(太简单了,不用多说了)
remove接口解析:
功能:接受一个链表,接受一个要删除的位置,然后删除该元素
咋写滴呢:
接受到参数后,@#¥&*…通过pos - 1找到要删除的位置的前一个节点的位置,然后将要pos位置的节点删掉…(太简单了,不用多说了)
set接口解析:
功能:接受一个链表,接受一个节点,接受一个要插入的位置,然后将该位置的节点被覆盖为传入的节点
咋写滴呢:
接受到参数后,@#¥&*…通过pos - 1找到要修改的位置的前一个节点的位置,然后将要pos位置的节点替换为传入的新节点…(太简单了,不用多说了)
display接口解析:
功能:接受一个节点,然后输出节点相关信息
咋写滴呢:
接受到参数后,@#¥&*…依次输出成员…(这TMD无比简单,不用说了)
foreach接口解析:
功能:接受一个链表,然后输出所有节点信息
咋写滴呢:
接受到参数后,@#¥&*…通过外部迭代的方式依次将节点输出…(这也TMD无比简单,不用说了)
以上就是链表模块的简单设计了,关于代码部分我没做详细说明,只是简单的介绍了一下各接口的主要过程和功能描述,目的是給大家留下足够的研究空间,比较简单。
欲知管理系统后事如何,请看管理系统下篇------系统篇!
以下是我的联系方式(qq),1611653027(ID:沙石乐),需要源码的小伙伴儿可以加我qq哈!