封装 链表

来源:互联网 发布:妖夜慌踪 知乎 编辑:程序博客网 时间:2024/06/15 23:43
<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  修改为newnumvoid 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  修改为newnumvoid change(ST*head, int oldnum, int newnum){ST*psearch = search(head, oldnum);//创建指针psearch    调用查找节点函数searchif (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;//跳过p1free(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;//新节点指向p1p2->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)//从大到小排序{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;//交换scoretemp.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="http://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="http://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="http://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的前面插入20showall(head);printf("\n插入之后的链表节点\n");head = HeadInsert(head, 50, 520, 590.0);//在节点2的前面插入20showall(head);printf("\n插入之后的链表节点\n");head = HeadInsert(head, 4, 40, 444.0);//在节点2的前面插入20showall(head);getchar();}</span></strong>
<strong><span style="font-family:Microsoft YaHei;"><img src="http://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的前面插入20showall(head);printf("\n插入之后的链表节点\n");head = BackInsert(head, 50, 520, 590.0);//在节点2的前面插入20showall(head);printf("\n插入之后的链表节点\n");head = BackInsert(head, 4, 40, 444.0);//在节点2的前面插入20showall(head);//测试删除指定节点printf("\n删除节点后:\n");//head = delete(head, 33);//如果删除一个不存在的节点  程序就会崩溃head = delete(head, 4);//删除节点2head = delete(head, 10);//删除节点2head = delete(head, 50);//删除节点2showall(head);getchar();}</span></strong>
<img src="http://img.blog.csdn.net/20150729085602092?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" />

0 0
原创粉丝点击