C语言----链表实践(高阶篇三十七)
结构变量地址与成员地址
下列代码:
struct student
{
char name[9]; /*姓名*/
int age; /*年龄*/
struct student *next; /*下一结点指针*/
};
main()
{
struct student stu,*pstu;
int *pi;
pstu=&stu;
pi=&stu.age;
pi=&pstu->age;
}
pstu只能指向同类型的结构变量地址,pi只能指向同类型的结构成员地址。
创建链表并添加结点
链表的代码都比较长,要做到无限制地动态创建,有些难度。在这里,简单地创建4个节点,先删除一些需要判断的因素。
链表创建流程:
(1)创建一个链表需要3个指针,头指针(pHead),尾指针(pEnd),新指针(pNew)
(2)刚开始链表中一个结点都没有,可用malloc申请内存,动态创建1个结点,令pNew指向它
(3)输入数据后,目前这个新结点又是头结点,也是最后一个结点,所以要令pHead和pEnd也指向它。第一个结点通常需要特殊处理,所以将它放在循环外面建立
(4)剩下3个结点有相同规律,可用(5)到(7)步的循环进行处理:
(5)新建结点给pNew,输入数据
(6)使最后一个结点pEnd的下一结点next指向这个新结点,形成兄弟关系
(7)将新结点pNew设为最后一个结点pEnd
(8)循环结束
(9)不再添加结点,要使最后一个结点pEnd的指针指向NULL
(10)返回头指针pHead
程序1:create函数
创建链表并输入4个结点
输出链表
相对其它操作,输出链表结点的操作比较简单,用一个临时指针通过循环不停地指向下一结点即可。
程序1:print函数
输出链表所有结点
删除结点
删除结点时通常会进行结点查找,找到符合条件的结点再进行删除操作。
在本程序中找到第3个结点为要删除的结点,再令第2个结点的下一结点指针指向第4个结点,第3个结点就完成了自然脱链动作。
程序1:del函数
删除指定姓名的结点
插入结点
插入的意思是把结点插入至链表中间,插入方法有“前插”和“后插”法,前插就是找到目标结点后,在它前面插入新结点,后插就是在其后面插入。本程序中演示的是前插法。有个例外的是:如果未找到指定结点,会将新结点添加到链表最后。
程序1:insert函数
插入一个新结点在指定姓名之前
// 37-链表实践.c。 #include <stdio.h> struct student //定义学生结构体 { char name[9]; //一个汉字两个字结,末尾加 \0 int age; //年龄 struct student *pNext; //下一结点指针 }; struct student* create() //创建链表结点函数,返回student类型指针 { struct student *pHead, *pEnd, *pNew; //头指针,未指针,新指针 /*创建链表的头一个结点.*/ //申请动态内存空间地址。 9+4+4 = 17byte pNew = (struct student*) malloc(sizeof(struct student)); //输入头结点姓名,年龄 scanf("%s%d",pNew->name,&pNew->age); pHead = pEnd = pNew; //一个结点的地址相同的 //第一个结点已经创建,只需创建三个结点 for (size_t i = 0; i < 3; i++) { //申请新的链表内存,创建结点 pNew = (struct student*)malloc(sizeof(struct student)); //输入头结点姓名,年龄 scanf("%s%d", pNew->name, &pNew->age); //将上一个结点的 struct student *pNext 指针指向新结点 pEnd->pNext = pNew; pEnd = pNew; //将新结点设为最后一个结点 } //循环完成后,将最后一个结点设为空指针 pEnd->pNext = NULL; //将链表第一结地址返回 return pHead; } void print(struct student *pHead) //输出结点 { struct student *p; //定义指针变量 p = pHead; //赋值给第一个结点 while (p != NULL) //指针空就是最后一个结点 { printf("姓名:%s,年龄:%d\n", p->name, p->age); p = p->pNext; } } void del(struct student *pHead,char *name) //删除指定的结点 { //无法删除第一个结点 struct student *pFront, *pBack; //前结点,后结点 pBack = pHead; //后结点指向头结点 pFront = pBack->pNext; //前结点指向头结点的下一结点 while (pFront != NULL) //前结点为空说明指向最后一个结点 { if (strcmp(name, pFront->name) == 0) //找到对应结点,准备删除 { //将上一个结点的 struct student *pNext 指向当前结点里的 struct student *pNext pBack->pNext = pFront->pNext; free(pFront); //释放内存 return; } pBack = pFront; //后结点设为前结点 pFront = pFront->pNext; //前结点指向下一个结点 } printf("未找到删除的结点\n"); } void insert(struct student *pHead,char *name) { //无法在第一个结点前插入 struct student *pFront, *pBack, *pNew; //前结点,后结点,新结点 //创建一个新结点 pNew = (struct student *)malloc(sizeof(struct student)); printf("输入姓名和年龄:\n"); scanf("%s%d", pNew->name, &pNew->age); pBack = pHead; //后结点指向头结点 pFront = pHead->pNext; //前结点指向头结点的下一结点 while (pFront != NULL) { if (strcmp(name, pFront->name) == 0) //找打插入的结点 { pBack->pNext = pNew; //后结点的下一结点指向新结点 pNew->pNext = pFront; //新结点的下一结点指向前结点 return; } pBack = pFront; //后结点设为前结点 pFront = pFront->pNext; //前结点指向下一个结点 } //如果未找到插入的结点,那么就把新结点插在最后面 pBack->pNext = pNew; //pBack 指向最后一个结点,将新结点pNew设为下一结点 pNew->pNext = NULL; //新结点的下一结点指向空NULL } void main() { struct student *pHead; //定义 链表头指针 pHead = create(); //创建链表结点,返回头指针 print(pHead); //输出创建的链表的结点 printf("删除指定的结点:\n\n\n"); del(pHead,"cc"); //删除指定的结点 print(pHead); //输出删除后链表的结点 printf("新增指定的结点:\n\n\n"); insert(pHead,"cc"); print(pHead); //输出新增后链表的结点 }