知识点1【链表的排序(选择法)】0-1(了解)
void sort_link(STU *head)
{
//1、判断链表是否存在
if(NULL == head)
{
printf("link not found\n");
return;
}
else
{
STU *p_i = head;//i=0
while(p_i->next != NULL)//i<n-1 外层循环
{
STU *p_min = p_i;//min = i;
STU *p_j = p_min->next;//j = min+1
while(p_j != NULL)//j<n 内层循环
{
//寻找成员num最小值的 节点
if(p_min->num > p_j->num)//if(arr[min] > arr[j])
p_min = p_j;//min = j
p_j = p_j->next;//j++
}
if(p_min != p_i)//min != i
{
//只交换数据域(1、节点内容整体交换 2、只交换指针域)
//1、节点内容整体交换(数据域交换第1次 指针域交换第1次)
STU tmp;
tmp = *p_i;
*p_i = *p_min;
*p_min = tmp;
//2、只交换指针域(指针域交换第2次)
tmp.next = p_i->next;
p_i->next = p_min->next;
p_min->next = tmp.next;
}
p_i = p_i->next;//i++
}
}
}
知识点2【双向循环链表】(了解)0-2
main.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//定义一个双向循环链表的节点类型
typedef struct stu
{
//数据域
int num;
char name[32];
int age;
//指针域
struct stu *next;//指向下一个节点
struct stu *pre;//指向前一个节点
}STU;
extern STU* insert_link(STU *head, STU tmp);
extern void print_link(STU *head);
extern STU* search_link(STU *head, char *name);
extern STU* delete_link(STU *head, int num);
extern STU* free_link(STU *head);
int main(int argc,char *argv[])
{
char name[32]="";
int num = 0;
int n =0;//保存学生的个数
int i=0;
STU *head = NULL;
STU *ret = NULL;
printf("请输入学员的个数:");
scanf("%d", &n);
for(i=0;i<n;i++)
{
STU tmp;
printf("请输入第%d个学员的信息:\n",i+1);
scanf("%d %s %d", &tmp.num, tmp.name, &tmp.age);
//插入一个节点
head = insert_link(head, tmp);
}
//遍历整个链表
print_link(head);
//查找指定节点
printf("请输入要查找的用户名:");
scanf("%s",name);
//查找中...
#if 1
ret = search_link(head, name);
if(ret == NULL)
{
printf("没有找到与%s相关的节点信息\n", name);
}
else
{
printf("查找到的信息为:%d %s %d\n", ret->num, ret->name,ret->age);
}
#endif
//删除指定节点 num
printf("请输入要删除的学号:");
scanf("%d", &num);
head = delete_link(head, num);
//遍历整个链表
print_link(head);
//释放整个链表
head = free_link(head);
//遍历整个链表
print_link(head);
return 0;
}
//头部之前插入
STU* insert_link(STU *head, STU tmp)
{
//1、为插入的节点pi申请空间
STU *pi = (STU *)calloc(1,sizeof(STU));
//2、将tmp的值 赋值给 *pi
*pi = tmp;
//3、判断链表是否存在
if(head == NULL)//链表不存在
{
head = pi;
pi->next = head;
pi->pre = head;
}
else//链表存在(头部之前插入)
{
pi->next = head;
pi->pre = head->pre;
head->pre->next = pi;
head->pre = pi;
head = pi;
}
return head;
}
#if 1
void print_link(STU *head)
{
//判断链表是否存在
if(head == NULL)
{
printf("link not found\n");
return;
}
else//链表存在
{
STU *pb = head;
do
{
//访问节点内容
printf("num=%d, name=%s, age=%d\n", pb->num,pb->name,pb->age);
//pb指向下一个节点
pb = pb->next;
}while(pb != head);
}
return;
}
#endif
#if 0
void print_link(STU *head)
{
//判断链表是否存在
if(head == NULL)
{
printf("link not found\n");
}
else//链表存在
{
STU *pb = head;//pb指向头结点
STU *pf = head->pre;//pf指向了尾节点
do
{
if(pb == pf)//相遇 只需要打印pf或pb中任何一个信息就够了
{
printf("num=%d,name=%s,age=%d\n", pb->num,pb->name,pb->age);
break;
}
printf("num=%d,name=%s,age=%d\n", pb->num,pb->name,pb->age);
printf("num=%d,name=%s,age=%d\n", pf->num,pf->name,pf->age);
pb = pb->next;//next方向的移动
pf = pf->pre;//pre方向的移动
}while( pb->pre != pf );//pf和pb不能 擦肩而过
}
}
#endif
STU* search_link(STU *head, char *name)
{
//判断链表是否存在
if(head == NULL)
{
return NULL;
}
else//链表存在
{
STU *pb = head;//指向头结点
STU *pf = head->pre;//指向的是尾节点
printf("pb = %p\n", pb);
printf("pf = %p\n", pf);
printf("pb->pre = %p\n", pb->pre);
while( (strcmp(pb->name,name) != 0) && (strcmp(pf->name,name)!=0) && (pb != pf) )
{
printf("##pb->name=%s##\n",pb->name);
printf("##pf->name=%s##\n",pf->name);
pb=pb->next;//next方向移动
pf=pf->pre;//pf方向移动
if(pb->pre == pf)
{
break;
}
}
if(strcmp(pb->name,name) == 0)
{
return pb;
}
else if(strcmp(pf->name,name)==0)
{
return pf;
}
}
return NULL;
}
STU* delete_link(STU *head, int num)
{
//判断链表是否存在
if(head == NULL)
{
printf("link not found\n");
return head;
}
else
{
STU *pb = head;//指向头节点
STU *pf = head->pre;//指向尾节点
//逐个节点寻找删除点
while((pb->num != num) && (pf->num != num) && (pf != pb))
{
pb = pb->next;//next方向移动
pf = pf->pre;//pre方向移动
if(pb->pre == pf)
break;
}
if(pb->num == num)//删除pb指向的节点
{
if(pb == head)//删除头节点
{
if(head == head->next)
{
free(pb);
head = NULL;
}
else
{
head->next->pre = head->pre;
head->pre->next = head->next;
head = head->next;
free(pb);
}
}
else//删除中尾部节点
{
pb->pre->next = pb->next;
pb->next->pre = pb->pre;
free(pb);
}
}
else if(pf->num == num)//删除pf指向的节点
{
if(pf == head)//删除头节点
{
if(head == head->next)
{
free(pf);
head = NULL;
}
else
{
head->next->pre = head->pre;
head->pre->next = head->next;
head = head->next;
free(pf);
}
}
else//删除中尾部节点
{
pf->pre->next = pf->next;
pf->next->pre = pf->pre;
free(pf);
}
}
else
{
printf("未找到%d相关的节点信息",num);
}
}
return head;
}
STU* free_link(STU *head)
{
if(head == NULL)//链表为空
{
printf("link not found\n");
return NULL;
}
else//链表存在
{
STU *pb = head;
STU *tmp;
do
{
tmp = pb;
pb = pb->next;
free(tmp);
}while(pb != head);
}
return NULL;
}
1、认识双向 循环 链表2、双链表 插入
//头部之前插入
STU* insert_link(STU *head, STU tmp)
{
//1、为插入的节点pi申请空间
STU *pi = (STU *)calloc(1,sizeof(STU));
//2、将tmp的值 赋值给 *pi
*pi = tmp;
//3、判断链表是否存在
if(head == NULL)//链表不存在
{
head = pi;
pi->next = head;
pi->pre = head;
}
else//链表存在(头部之前插入)
{
pi->next = head;
pi->pre = head->pre;
head->pre->next = pi;
head->pre = pi;
head = pi;
}
return head;
}
3、链表的遍历
单向遍历
void print_link(STU *head)
{
//判断链表是否存在
if(head == NULL)
{
printf("link not found\n");
return;
}
else//链表存在
{
STU *pb = head;
do
{
//访问节点内容
printf("num=%d, name=%s, age=%d\n", pb->num,pb->name,pb->age);
//pb指向下一个节点
pb = pb->next;
}while(pb != head);
}
return;
}
双向遍历:1-1
void print_link(STU *head)
{
//判断链表是否存在
if(head == NULL)
{
printf("link not found\n");
}
else//链表存在
{
STU *pb = head;//pb指向头结点
STU *pf = head->pre;//pf指向了尾节点
do
{
if(pb == pf)//相遇 只需要打印pf或pb中任何一个信息就够了
{
printf("num=%d,name=%s,age=%d\n", pb->num,pb->name,pb->age);
break;
}
printf("num=%d,name=%s,age=%d\n", pb->num,pb->name,pb->age);
printf("num=%d,name=%s,age=%d\n", pf->num,pf->name,pf->age);
pb = pb->next;//next方向的移动
pf = pf->pre;//pre方向的移动
}while( pb->pre != pf );//pf和pb不能 擦肩而过
}
}
4、双向链表的查找
STU* search_link(STU *head, char *name)
{
//判断链表是否存在
if(head == NULL)
{
return NULL;
}
else//链表存在
{
STU *pb = head;//指向头结点
STU *pf = head->pre;//指向的是尾节点
printf("pb = %p\n", pb);
printf("pf = %p\n", pf);
printf("pb->pre = %p\n", pb->pre);
while( (strcmp(pb->name,name) != 0) && (strcmp(pf->name,name)!=0) && (pb != pf) )
{
printf("##pb->name=%s##\n",pb->name);
printf("##pf->name=%s##\n",pf->name);
pb=pb->next;//next方向移动
pf=pf->pre;//pf方向移动
if(pb->pre == pf)
{
break;
}
}
if(strcmp(pb->name,name) == 0)
{
return pb;
}
else if(strcmp(pf->name,name)==0)
{
return pf;
}
}
return NULL;
}
5、双向链表 删除指定节点1-2
STU* delete_link(STU *head, int num)
{
//判断链表是否存在
if(head == NULL)
{
printf("link not found\n");
return head;
}
else
{
STU *pb = head;//指向头节点
STU *pf = head->pre;//指向尾节点
//逐个节点寻找删除点
while((pb->num != num) && (pf->num != num) && (pf != pb))
{
pb = pb->next;//next方向移动
pf = pf->pre;//pre方向移动
if(pb->pre == pf)
break;
}
if(pb->num == num)//删除pb指向的节点
{
if(pb == head)//删除头节点
{
if(head == head->next)//链表只有一个节点
{
free(pb);
head = NULL;
}
else
{
head->next->pre = head->pre;
head->pre->next = head->next;
head = head->next;
free(pb);
}
}
else//删除中尾部节点
{
pb->pre->next = pb->next;
pb->next->pre = pb->pre;
free(pb);
}
}
else if(pf->num == num)//删除pf指向的节点
{
if(pf == head)//删除头节点
{
if(head == head->next)//链表只有一个节点
{
free(pf);
head = NULL;
}
else
{
head->next->pre = head->pre;
head->pre->next = head->next;
head = head->next;
free(pf);
}
}
else//删除中尾部节点
{
pf->pre->next = pf->next;
pf->next->pre = pf->pre;
free(pf);
}
}
else
{
printf("未找到%d相关的节点信息",num);
}
}
return head;
}
6、释放这个链表节点(了解)
STU* free_link(STU *head)
{
if(head == NULL)//链表为空
{
printf("link not found\n");
return NULL;
}
else//链表存在
{
STU *pb = head;
STU *tmp;
do
{
tmp = pb;
pb = pb->next;
free(tmp);
}while(pb != head);
}
return NULL;
}
知识点3【结构的浅拷贝 和深拷贝】(了解)
1、知识点的引入(指针变量 作为 结构体的成员)
typedef struct
{
int num;
char *name;//指针变量作为 结构体的成员
}DATA;
void test01()
{
DATA data={100,"hehehehaha"};
printf("%d\n",sizeof(DATA));//8字节
printf("num = %d\n",data.num);
//指针变量作为结构体的成员 保存的是空间的地址
printf("name = %s\n",data.name);
}
2、指针变量 作为结构体的成员 操作前 必须有合法的空间
void test02()
{
DATA data;
printf("%d\n",sizeof(DATA));
printf("num = %d\n",data.num);
//指针变量 作为结构体的成员 操作前 必须有合法的空间
//data.name = "hehe";
//给name 事先申请 一块 堆区空间
data.name = (char *)calloc(1,10);
strcpy(data.name,"hahaha");
printf("name = %s\n",data.name);
//如果name指向堆区空间 一定要记得释放
if(data.name != NULL)
{
free(data.name);
data.name = NULL;
}
}
原理图分析:3、指针变量 作为结构体的成员 结构体变量间的赋值操作 容易导致“浅拷贝”发生
void test03()
{
DATA data1;
DATA data2;
data1.num = 100;
data1.name = (char *)calloc(1,10);
strcpy(data1.name,"my data");
printf("data1:num = %d, name = %s\n",data1.num, data1.name);
//指针变量 作为结构体的成员 结构体变量间的赋值操作 容易导致“浅拷贝”发生
data2 = data1;//“浅拷贝”
printf("data2: num = %d, name = %s\n",data2.num, data2.name);
if(data1.name != NULL)
{
free(data1.name);
data1.name = NULL;
}
if(data2.name != NULL)
{
free(data2.name);
data2.name = NULL;
}
}
运行结果 出现段错误