周记(7.26~8.1)

本周任务:

  1. 完成一个demo
  2. 学习C语言线性表到单链表的插入删除等;
  3. C语言知识总结

单链表

若在链表中,每个结点只有一个指针,所有结点都是单线联系,除了末尾结点指针以空外,每个结点的指针都指向下一个结点,一环扣一环形成一条线性链,则称此链表为单向线性链表,简称单链表。

特点

  • 有一个 head 指针变量,它存放在头结点的地址,称之为头指针。
  • 头结点的指针域head->next存放首元结点的地址。
  • 从头指针 head 开始,head 指向头结点,头节点指向首元结点,首元结点指向第二个结点,直到最后一个结点。所有结点都是单线联系。
  • 最后一个结点不再指向其他结点,称为“表尾节点”,它的指针域为空指针NULL,表示链表到此结束。指向表尾结点的指针称为尾指针
  • 链表各结点之间的顺序关系由指针域 next 来确定,并不要求逻辑上相邻的结点物理位置上也相邻。即链表依靠指针相连不需要占用一片连续的内存空间
1 初始化

由于链表的每个结点都包含数据域和指针域,即每个节点都要包含不同类型的数据,所以结点的数据类型必须选用结构体类型。且结构体中必须有一个成员的类型是指向本结构体类型的指针类型。
单链表的初始化就是创建一个头结点,头结点的数据域可以不使用,头结点的指针域为空,表示空单链表

  1. 先定义一个需要用的结构体类型:
typedef struct node {
	int number;				//数据域
	char name[20];			//数据域
	struct node *next;		//递归定义指向struct node类型结构体的指针变量next。
}NODE,*LinkList;
  1. 然后才开始链表的初始化。单链表的初始化就是创建一个头结点,头结点的数据域可以不使用,头结点指针域为空,表示空单链表。
LinkList List() {
	LinkList head;							//定义头指针变量
	head = (NODE*)malloc(sizeof(NODE));		//头指针指向分配的头结点内存空间
	head->next = NULL;						//头结点的指针域为空
	return head;							//返回头结点的地址,即头指针
}
2 建立

单链表的建立就是在程序的运行过程中,从无到有的建立一个链表,即一个一个的分配结点的内存空间,然后输入结点中的数据,并建立结点间的相连关系。
单链表的建立可以分为两种方法:尾插法头插法

  1. 尾插法:在单链表的尾部插入新结点。
           从一个空表开始,重复读入数据,生成新结点,将读入数据存放到新结点的数据域中,然后将新结点插入到当前链表的表尾上,直至读入结束标志为止。
void(CreatByRear(LinkList)) {
	NODE *r,*s;			//s用于创建新结点
	int number;
	char name[20];
	r = head;			//head指向头结点,故r指向头结点
	printf("请输入学生的学号和姓名:\n");
	while(1) {
		scanf("%d",&number);
		scanf("%s",name);
		if(number == 0) break;
		s = (node *)malloc(sizeof(NODE));		//分配结点的内存空间
		s->number = number;
		strcpy(s->name,name);
		r->next = s;							//原来的结点指向新结点
		r = s;									//r指向新结点
	}
	r->next = NULL;								//链表的尾结点指针为空
}
  1. 头插法:在单链表的头部插入新结点
           从一个空表开始,重复读入数据,生成新结点,将读入的数据存放到新结点的数据域中,然后将新结点插入到当前链表的表头节点之后,直至读入结束标志为止。
void CreatByHead(LinkList head) {
	NODE *S;
	int number;
	char name[20];
	printf("请输入学生学号和姓名;\n");
	while(1) {
		scanf("%d",&number);
		scanf("%s",name);
		if(number == 0) break;
		s = (NODE *)malloc(sizeof(NODE));		//分配节点的内存空间
		s->number = number;
		strcpy(s->name,name);
		s->next = head->next;					//让新结点指向首元结点
		head->next = s;							//让头结点指向新结点
	}

}

如下图:

3 遍历

直接上代码:

void OutPut(LinkList head) {
	NODE *p;				//循环所用的临时指针
	p = head->next;			//p指向链表的首元结点
	while(p) {
		printf("学号:%d\n",p->number);
		printf("姓名:%s\n",p->name);
		p = p->next;		//移动临时指针到下一个结点
	}
}
  • 函数定义了一个临时指针p用来进行循环操作,使其指向要输出链表的首元结点。
  • 在while循环中,每输出一个结点的内容后,就移动临时指针p到下一个节点的位置。如果是最后一个结点,指针指向NULL,表示链表中的节点都已经输出,循环结束。
4 插入

链表的插入操作可以在链表的头指针位置进行插入,也可以在链表中某个结点的位置进行插入,或者在链表的最后面添加结点。在头指针位置和在最后面插入的思路与头插法和尾插法的思路相同。
以下写一段在链表中某个结点的位置插入新结点的代码示例:

void Insert(LinkList head,int i) {
	NODE *P = head,*s;
	int j = 0;
	while(j < i-1 && p) {			//从头结点开始,故开始j=0,头结点是第0个结点,遍历找到第i-1个结点的地址
		p = p->next;
		j++;
	}
	if(p) {
		printf("请输入待添加学生的学号和姓名:\n");	
		s = (NODE *)malloc(sizeof(NODE));	//定义s指向新分配的空间
		scanf("%d",&s->number);
		scanf("%d",s->name);
		s->next = p->next;					//新结点指向原来的第i个结点
		p->next = s;						//新结点成为原来的第i个结点
	}
}
5 删除

在创建单链表删除某个结点的函数时需要两个参数,一个表示链表的头指针head,另一个表示要删除的节点在链表中的位置。
代码示例:

void Delete(LinkList head,int pos) {
	NODE *p = head,*q;
	int j = 0;
	printf("删除第%d个学生的信息",pos);
	while(j < pos-1 && p) {			//通过循环,找到第pos-1个结点的地址
		p = p->next;
		j++;
	}
	if(p == NULL || p->next == NULL) printf("the pos is error");	//第pos个结点不存在
	else {
		q = p->next;				//q 指向第pos个结点
		p->next = q->next;			//连接所要删除结点两边的结点
		free(q);					//释放所要删除结点的内存空间
	}
}
6 查询

在创建单链表查询某个结点的函数时需要两个参数,一个表示链表的头指针head,另一个表示要查找的值。
代码示例:

NODE *Search(LinkList head,char name[]) {		//在单链表head中找到值为name的结点
	NODE *p = head->next;
	while(p) {
		if(strcmp(s->name,name)!=0) p = p->next;	//判断结点的值是不是name的值,若不是则移动p指向下一个结点
		else break;			//查找成功!
	}
	if(p == NULL) 
		printf("未找到值为%d的结点",name)return p;
}
7 单链表的长度

单链表的长度是隐形表示的,当从首元结点开始,依次遍历链表的所有结点,并同时统计结点个数,最后返回结点个数值。
代码示例:

int Length(LinkList head) {		
	int count;
	NODE *p;
	p = head->next;			//指针变量p指向链表的首元结点
	while(p) {				//结点存在,表示链表没有遍历结束
		count++;			//结点个数累加器加1
		p = p->next;		//指向当前结点的下一结点
	}
	return count;			//返回链表结点的个数
}
8 不带头结点的单链表

不带头结点的单链表,在操作过程中必须针对第一个结点和其余结点分别进行操作。

  1. 插入
    分为在链表的首位置插入不在链表的首位置插入两种情况。

在链表首位置:
插入时,首先为插入的新结点分配内存,然后将新结点的指针指向原来的首结点,最后将头指针指向新结点。需要注意的是,在这种情况下,头指针发生了改变,所以需要返回新的头指针。

不在链表首位置: 例如要在第 i 个结点插入新结点
需要先通过循环找到链表的第 i-1个结点的地址p。如果该结点存在,则可以在第 i-1 个结点后面插入第i个结点。为插入的新结点分配内存,然后向新结点输入数据。插入时,首先将新结点的指针指向原来第 i 个结点,然后将第 i-1 个结点指向新结点。完成。

  1. 删除
    分为删除首结点删除其他结点两种情况。

删除首结点:
定义指针变量去指向待删除的结点,再让头指针指向原来的第二个结点,成为新的首结点。最后释放原来的首结点的内存空间。在这种情况下,头指针也发生了改变,所以需要返回新的头指针。

删除不是头结点的结点:
定义整型变量 j 来控制循环次数,然后定义指针变量p表示该结点之前的结点。接着利用循环找到要删除的结点之前的结点p;如果该结点存在并且待删除结点存在,则将指针变量q指向待删除的结点,再连接要删除结点两边的结点。,并使用free函数将q指向的内存空间进行释放。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值