您的位置:首页 > 其它

封装 链表

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="" />
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  封装 链表