封装 链表
2015-07-29 02:18
393 查看
<strong><span style="font-family:Microsoft YaHei;">linknode.h</span></strong>
<strong><span style="font-family:Microsoft YaHei;">#include <stdio.h> #include <stdlib.h> typedef struct student { int num; float score; struct student *pNext;//用于存储下一个节点的地址 }ST; //函数声明 void add(ST **phead, int inum, float iscore);//函数声明 传入头结点的地址 然后插入数据 //显示所有数据 void showall(ST *head);//传递头结点的指针 用于有可能要改变头结点的指向 //实现逆转 不改变数据 改变指针指向 ST *rev(ST *head); //统计链表节点个数 int getnum(ST *head); //查找数据 ST *search(ST*head, int num); //查找oldnum 修改为newnum void change(ST*head, int oldnum, int newnum); //删除链表所有的节点 用完后释放链表 void *freeall(ST *head); //返回头结点 传入头结点 要删除节点的编号 ST *delete(ST*head, int num);//头指针 //根据节点 在节点前面插入 ST *HeadInsert(ST*head, int num, int inum, float iscore); //根据节点 在节点尾部插入 ST*BackInsert(ST*head, int num, int inum, float iscore); //链表排序 void sort(ST*head, char ch);//传入头结点 当ch=='>'时,实现从大到小排序 当ch=='<'时,实现从小到大排序</span></strong>
---------------------------------------------------------------------------------------------------------------------------------------------------------
linknode.cpp
<strong><span style="font-family:Microsoft YaHei;">//函数定义 及实现 #include "linknode.h" void add(ST **phead, int inum, float iscore)//函数声明 传入头结点的地址 然后插入数据 { if (*phead==NULL)//判断链表是否为空 { ST *newnode = (ST *)malloc(sizeof(ST));//分配内存 if (newnode==NULL) { printf("内存分配失败\n"); return; } newnode->num = inum;//节点初始化 newnode->score = iscore; newnode->pNext = NULL; *phead = newnode;//让头指针指向这个节点 } else//建立链表:先建立一个空链表 然后在一个一个的将元素插在队尾 {//尾部插入方式 //链表不为空 ST*p = *phead;//指向头结点 //while (p!=NULL)//p=NULL循环终止 表示到了链表的尾部 //{ // p = p->pNext;//循环向前 //} //让p存储最后一个节点地址 while (p->pNext != NULL)//循环到最后一个节点的地址 { p = p->pNext;//循环向前 } //p->pNext==NULL//跳出循环 //创建节点 ST*newnode = (ST*)malloc(sizeof(ST));// if (newnode == NULL) { printf("内存分配失败\n"); return; } newnode->num = inum; newnode->score = iscore; newnode->pNext = NULL; p->pNext = newnode;//链接上 } } void showall(ST *head)//传递头结点的指针 显示所有数据 用于有可能要改变头结点的指向 {//遍历所有节点 while (head!=NULL)//判断指针指向是否为空 { printf("num=%d score=%f ",head->num,head->score); printf("%p %p\n",head,head->pNext);//打印两个节点的地址 head = head->pNext;//指针不断向前循环 } } //实现逆转 ST *rev(ST *head) { ST*p1, *p2, *p3; p1 = p2 = p3 = NULL; if (head==NULL||head->pNext==NULL)//如果头结点为空 有一个节点 或者链表为空 { return head;//返回头结点 } p1 = head; p2 = head->pNext; while (p2!=NULL)//从第二个到最后一个节点进行循环 { p3 = p2->pNext;//布局三个节点 p2->pNext = p1;//指向前面一个节点 p1 = p2;//指针向前移动 从第二个到最后一个节点全部指向前面的节点 p2 = p3; } head->pNext = NULL;//代表链表的结束 设置第一个节点指向为空 head = p1;//指向最后一个节点 return head;//副本机制 改变的head并不会生效 需要返回值赋值生效 } //获取节点个数 int getnum(ST *head) { //遍历所有的节点 int i = 0;//节点计数器 while (head!=NULL) { i++;//计数器自增 head = head->pNext;//指针不断向前循环 } return i;//统计个数 } //查找数据 ST *search(ST*head, int num)//根据编号查找节点 { while (head!=NULL)//判定指针指向是否为空 循环遍历一个链表 { if (num==head->num) { return head;//返回当前节点的指针地址 表示找到 } head = head->pNext;//指针不断向前移动 循环 } return NULL;//如果没有找到 返回为空 } //查找oldnum 修改为newnum void change(ST*head, int oldnum, int newnum) { ST*psearch = search(head, oldnum);//创建指针psearch 调用查找节点函数search if (psearch==NULL) { printf("没有找到\n"); } else { psearch->num = newnum; printf("修改成功\n"); } } //链表的清空 用完后就要释放链表 void *freeall(ST *head)// error C2040: “freeall”:“void *(ST *)”与“void (ST *)”的间接寻址级别不同 {//此处的freeall添加* 不要忘记头文件中的声明也要添加* ST *p1, *p2; p1 = p2 = NULL; p1 = head; while (p1->pNext!=NULL)//循环遍历所有节点 { p2 = p1->pNext;//pw2为p1的下一个节点 p1->pNext = p2->pNext;//p1存储了p2的下一个节点的地址 free(p2);//释放 //显示删除的中间状态 printf("\n---删除的过程---\n"); showall(head); } free(head);//释放最后一个节点 return NULL; } //返回头结点 传入头结点 要删除节点的编号 定位要删除的节点所在位置 ST *delete(ST*head, int num) { ST*p1, *p2; p1 = p2 = NULL;//定义两个空节点 p1 = head;//从头结点开始循环 while (p1!=NULL)//循环所有的节点 { if (num == p1->num )//判断是否等价于参数中的num { break; } else { p2 = p1;//记录当前节点 p1 = p1->pNext;//继续完后循环 } } if (p1==head)//头结点的情况 { head = p1->pNext;//跳过头结点 free(p1);//释放第一个节点 } else//如果不是head的情况 { p2->pNext = p1->pNext;//跳过p1 free(p1); } return head;//函数有副本机制 所以返回头结点的值 } //根据节点 在节点前面插入 ST *HeadInsert(ST*head, int num, int inum, float iscore) { ST*p1, *p2; p1 = p2 = NULL;//定义两个空节点 p1 = head;//从头结点开始 while (p1!=NULL)//一直循环到尾部最后一个节点 { if (p1->num==num) { break; } else//找到节点当前位置 { p2 = p1;//记录当前节点 p1 = p1->pNext;//循环到下一个节点 } } if (p1==head)//如果是头结点 就在头结点的前部插入节点 { ST*newnode = (ST*)malloc(sizeof(ST));//分配内存 newnode->num = inum;//初始化节点 newnode->score = iscore; newnode->pNext = head;//指向第一个节点的头结点 head = newnode;//newnode成为第一个节点 } else { ST*newnode = (ST*)malloc(sizeof(ST));//分配内存 //初始化节点的两个数据 newnode->num = inum; newnode->score = iscore; newnode->pNext = p1;//新节点指向p1 p2->pNext = newnode;//指向新节点 } return head; } //根据节点 在节点尾部插入 不需要记录前面的节点 要记住后面的节点 ST*BackInsert(ST*head, int num, int inum, float iscore) { ST*p1, *p2; p1 = p2 = NULL;//对节点置空 p1 = head;//从头结点开始 while (p1!=NULL)//一直循环到最后一个节点 { if (p1->num==num)//判断相等 { break; } else { p1 = p1->pNext;//循环到下一个节点 } } if (NULL==p1->pNext)//最后一个节点 { ST*newnode = (ST*)malloc(sizeof(ST));//分配内存 newnode->num = inum;//初始化节点 newnode->score = iscore; newnode->pNext = NULL;//指针域此时为空 代表最后一个节点 p1->pNext = newnode;//指向新开辟的节点 } else { p2 = p1->pNext;//记录下一个节点的位置 ST*newnode = (ST*)malloc(sizeof(ST));//分配内存 newnode->num = inum;//初始化节点 newnode->score = iscore; newnode->pNext = p2;//连接下一个节点 p1->pNext = newnode;//p1指向新的节点 } return head; } //链表排序 不能随便访问另外一个节点,只能访问与自己相近的一个节点 选择排序不适用于链表,需要使用冒泡排序法 void sort(ST*head, char ch)//传入头结点 当ch=='>'时,实现从大到小排序 当ch=='<'时,实现从小到大排序 { //链表的冒泡排序 if ('>'==ch)//从大到小排序 4000 { for (ST*p1=head; p1!=NULL; p1=p1->pNext)//循环终止条件 首结点为空 { for (ST*p2 = head; p2 != NULL; p2 = p2->pNext) { if (p1->num<p2->num) { ST temp;//交换p1、p2节点 temp.num = p1->num;//实现编号num的交换 p1->num = p2->num; p2->num = temp.num; //此结构体中还有成绩 temp.score = p1->score;//实现成绩score的交换 p1->score = p2->score; p2->score = temp.score; } } } } else if ('<'==ch)//从小到大排序 { for (ST*p1=head;p1!=NULL;p1=p1->pNext)//外层循环 只能遍历所有情况 数组可以规避一些无意义的,但是链表必须全部遍历一遍 { for (ST*p2 = head; p2 != NULL;p2=p2->pNext)//内层循环 { if (p1->num>p2->num) { ST temp; temp.num = p1->num; p1->num = p2->num; p2->num = temp.num; //交换score temp.score = p1->score; p1->score = p2->score; p2->score = temp.score; } } } } }</span></strong>
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
测试代码段 主程序
main.c
<strong><span style="font-family:Microsoft YaHei;">#include "linknode.h" void main5() { struct student *head = NULL;//创建头结点的指针 //添加5个节点 add(&head, 1, 70); add(&head, 2, 67); add(&head, 3, 99); add(&head, 4, 87); add(&head, 5, 67); //显示所有节点 //printf("%d %f\n",head->num,head->score);//打印数据 //printf("%d %f\n",head->pNext->num,head->pNext->score); //printf("%d %f\n",head->pNext->pNext->num,head->pNext->pNext->score); //逆转链表 head = rev(head); //显示所有节点 showall(head); //测试获取有多少个节点 printf("num=%d\n",getnum(head)); //链表查找测试 ST*psearch = search(head, 3); printf("%d %f\n",psearch->num,psearch->score);//打印返回链表指针指向的数据 change(head, 3, 30);//修改数据 showall(head);//显示所有的节点 //显示所有数据 传递头结点的指针 showall(head); getchar(); } <img src="https://img-blog.csdn.net/20150729085428211?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" /> void main4() { struct student *head = NULL; add(&head, 1, 70); add(&head, 2, 67); add(&head, 3, 99); add(&head, 4, 87); add(&head, 5, 67); showall(head);//显示所有的节点 printf("删除之后:"); //freeall(head); //由于最后把head也给释放掉了 所以在此处要把head设为NULL //head = NULL;//方法一 ok 删除所有节点之后 头结点务必为空 //为了代码的稳健型 使用方法二 //方法二 让freeall函数返回void*指针 最后return NULL 即可 head=freeall(head); showall(head);//显示所有的节点 getchar(); } <img src="https://img-blog.csdn.net/20150729085337085?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" /> //测试链表的排序 void main3() { struct student *head = NULL; add(&head, 10, 70); add(&head, 2, 67); add(&head, 30, 99); add(&head, 4, 87); add(&head, 50, 67); showall(head);//显示所有的节点 printf("\n从小到大,排序之后:\n"); sort(head,'>'); showall(head);//显示所有的节点 printf("\n从大到小,排序之后:\n"); sort(head, '<'); showall(head); printf("该链表一共有:%d个节点\n",getnum(head)); getchar(); } </span></strong><strong><span style="font-family:Microsoft YaHei;"><img src="https://img-blog.csdn.net/20150729085528724?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" /></span></strong>
<strong><span style="font-family:Microsoft YaHei;"> //测试前插 节点 void main2() { struct student *head = NULL; add(&head, 10, 70); add(&head, 2, 67); add(&head, 30, 99); add(&head, 4, 87); add(&head, 50, 67); showall(head);//显示所有的节点 printf("\n插入之后的链表节点\n"); head = HeadInsert(head, 2, 20, 90.0);//在节点2的前面插入20 showall(head); printf("\n插入之后的链表节点\n"); head = HeadInsert(head, 50, 520, 590.0);//在节点2的前面插入20 showall(head); printf("\n插入之后的链表节点\n"); head = HeadInsert(head, 4, 40, 444.0);//在节点2的前面插入20 showall(head); getchar(); } </span></strong><strong><span
style="font-family:Microsoft YaHei;"><img src="https://img-blog.csdn.net/20150729085546274?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" /></span></strong>
<strong><span style="font-family:Microsoft YaHei;"> //测试后 插节点 void main() { struct student *head = NULL; add(&head, 10, 70); add(&head, 2, 67); add(&head, 30, 99); add(&head, 4, 87); add(&head, 50, 67); showall(head);//显示所有的节点 printf("\n插入之后的链表节点\n"); head = BackInsert(head, 2, 20, 90.0);//在节点2的前面插入20 showall(head); printf("\n插入之后的链表节点\n"); head = BackInsert(head, 50, 520, 590.0);//在节点2的前面插入20 showall(head); printf("\n插入之后的链表节点\n"); head = BackInsert(head, 4, 40, 444.0);//在节点2的前面插入20 showall(head); //测试删除指定节点 printf("\n删除节点后:\n"); //head = delete(head, 33);//如果删除一个不存在的节点 程序就会崩溃 head = delete(head, 4);//删除节点2 head = delete(head, 10);//删除节点2 head = delete(head, 50);//删除节点2 showall(head); getchar(); }</span></strong><img
src="https://img-blog.csdn.net/20150729085602092?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" />
相关文章推荐
- [C/C++]反转链表
- C#实现基于链表的内存记事本实例
- C语言实现带头结点的链表的创建、查找、插入、删除操作
- 自己简单封装的一个CDialog类实例
- C++实现简单的学生管理系统
- 封装好的一个万能检测表单的方法
- jquery datatable后台封装数据示例代码
- Linux内核链表实现过程
- c#基础学习之封装
- C++链表倒序实现方法
- C#通过链表实现队列的方法
- 纯JavaScript实现的兼容各浏览器的添加和移除事件封装
- PHP面向对象三大特点学习(充分理解抽象、封装、继承、多态)
- 找出链表倒数第n个节点元素的二个方法
- javascript的函数、创建对象、封装、属性和方法、继承
- Java数据结构之简单链表的定义与实现方法示例
- C语言单循环链表的表示与实现实例详解
- C++封装IATHOOK类实例
- C++实现的链表类实例
- WebService 的简单封装接口调用方法