后台组贾浩琛周报(2020.11.30-12.6)

学习内容

  • C语言学习内容
    • 链表的创建
      • 头插法和尾插法
    • 链表的销毁
    • 链表的查找
    • 链表的插入
    • 链表的删除
  • 总结

C语言学习内容

链表的创建

一,链表的创建

头插法和尾插法

(1)头插法

在这里插入图片描述

Linklist Creat_list(Linklist head) {
     
	head = (Linklist)malloc(sizeof(Lnode));      //  为头指针开辟内存空间
	Lnode *node = NULL;                    //  定义新结点
	int count = 0;                          //  创建结点的个数
	head->next = NULL;              
	node = head->next;              	//  将最后一个结点的指针域永远保持为NULL
	printf("Input the node number: ");
	scanf("%d", &count);
	for (int i = 0; i < count; i++) {
     
		node = (Linklist)malloc(sizeof(Lnode));     //  为新结点开辟内存空间
		node->data = i;               //  为新结点的数据域赋值
		node->next = head->next;          //  将头指针所指向的下一个结点的地址,赋给新创建结点的next 
		head->next = node;          //  将新创建的结点的地址赋给头指针的下一个结点
	}
	return head;
}

头插法的核心所在是要理解这部分

	node->next = head->next;          //  将头指针所指向的下一个结点的地址,赋给新创建结点的next 
	head->next = node;          //  将新创建的结点的地址赋给头指针的下一个结点

会发现,头插法创建链表时候,就相当于后来居上。 后面的结点不断往前插,而最后创建的结点在第一个结点处, 第一个创建的结点变成了尾结点

(2)尾插法

void CreatByRear(LinkList head)
{
     
	Node *r,*s;
	char name[20];
	int number;
	r=head;//r指向头结点 
	printf("请输入姓名和学号:\n");
	while(1)
	{
     
		scanf("%s",name);
		scanf("%d",number);
		if(number==0)
		{
     
			break;
		}
		s=(Node *)malloc(sizeof(Node));//分配结点的内存空间
		strcpy(s->name,name);
		s->number=number;
		r->next=s;//原来的结点指向新结点
		r=s;//r指向新结点 
	}
	r->next=NULL;//链表的尾结点指针为空 
}//CreatByRear函数的功能是创建链表,在该函数中首先定义需要用的指针变量r和s,r指向当前链表的表尾结点,s指向新创建的结点

核心所在是这部分
在这里插入图片描述

头插法相对简便,但插入的数据与插入的顺序相反;
尾插法操作相对复杂,但插入的数据与插入顺序相同。

链表的销毁

从前往后销毁如下
后台组贾浩琛周报(2020.11.30-12.6)_第1张图片

先让p指向,头结点后面那个第一个有效节点。 (红色箭头的p)
然后把头结点的next值修改成,现在第一个有效节点的next成员的值(蓝色的箭头)
然后再释放p,这样不会使链表中途断开,一直删完。当删到最后一个时,head->next变为NULL,销毁正式结束。

void destroy(point *head)
{
     
	point *p;
	while (head->next)
	{
     
		p = head->next;
		head->next = p->next;
		free(p);
	}
}

链表的查找

有三个参数(point head, int oldrows, int oldcols)
从前往后用一个指针分别指向链表的每一个结构体判断oldrows和oldcols是否相等
我们不管以后的插入删除听起来是想要这个点的位置,其实最重要的是找到他的前驱结点
找到它的前驱结点才能把它"架空",修改掉前驱结点的next值,然后才可以大方的把它的空间释放
需要两个指针:一个负责查找的指针,一个负责记录前驱结点的指针

红色为循环开始,蓝色为循环一次的结果
后台组贾浩琛周报(2020.11.30-12.6)_第2张图片

for (p = head.next; p && ((p->cols != oldcols) || (p->rows != oldrows)); p = p->next)
	q = p;

后台组贾浩琛周报(2020.11.30-12.6)_第3张图片
用程序实现

point *found(point head, int oldrows,int oldcols)
{
     
point *p;
point *q = NULL;
for (p = head.next; p && ((p->cols != oldcols) || (p->rows != oldrows)); p = p->next)
q = p;
return q;
//若指定点为第一个,返回值为NULL
//若指定点为除了第一个以外的其他节点,则该函数的返回值为目标的前一个指定点。
//若指定点不存在,则该函数的返回值指向末节点。
}

链表的插入

思想:定位到它的前驱结点,然后改变它的前驱结点的值,让它指向需要插入的结构体,然后把原始的前驱结点的NEXT赋值给你新插入进来的结构体

q指针是查找返回的值,p指针是新开辟地址,红色是初始指向,蓝色是程序结束的指向。
后台组贾浩琛周报(2020.11.30-12.6)_第4张图片
核心思想代码

if (q == NULL)  //新点插入到头结点的后面(原来第一个有效节点前面)
{
       
p->next = head->next;
head->next = p;
}
else if (q->next==NULL)  //指定点不存在,应补充在链表的后面。
{
     
        p->next = q->next;
q->next = p;
}
else
{
     
p->next = q->next;
q->next = p;
}
//这段3段程序明显都是一个算法,可以进行简化,
if (NULL == pro)
{
     
	q = head;
}
p->next = q->next;
q->next = p;

程序实现

void insert(point *head)   //采用左插入节点方式
{
     
	int newrows;
	int newcols;
	int oldrows;
	int oldcols;
	point *p;
	point *pro;
	showtopic("\n当前坐标如下,请参考插入位置进行左插入\n");
	showpoints(*head);
	showtopic("\n请输入将要插入的位置\n");
	scanf("%d %d", &oldrows, &oldcols);
	fflush(stdin);
	pro = found(*head, oldrows, oldcols);
	showtopic("\n请输入你要插入的数据\n");
	scanf("%d %d", &newrows, &newcols);
	fflush(stdin);
	p = create(newrows, newcols);
	if (NULL == pro)
	{
     
		pro = head;
	}
	p->next = pro->next;
	pro->next = p;
}

链表的删除

先想办法把你要删的元素从链表上剔除,然后让链表仍然连续。
后台组贾浩琛周报(2020.11.30-12.6)_第5张图片

步骤
1.让p指向目标节点的前驱结点(如果是第一个点的话,p=head->next)
2.把q->next的值赋值为p所指向实例的next成员,然后p所指向的成员就被“架空”了。
3.释放p的空间。

程序实现

void *delete(point *head)
{
     
	int rows;
	int cols;
	point *p;
	point *pro;
	showpoints(*head);
	showtopic("\n请输入你所需要删除节点的rows和cols值\n");
	scanf("%d %d", &rows, &cols);
	fflush(stdin);
	pro = found(*head, rows, cols);
	if (pro && pro->next == NULL)        //这种表达式,如果前面为假后面直接都不用看了,如果你调换了他两个的条件的位置,会引发一个bug。
	{
     
		showtopic("\n要删除的节点不存在(按任意键继续....)\n");
		getch();
	}
	else
	{
     
		if (NULL == pro)
		{
     
			pro = head;
		}
		p = pro->next;
		pro->next = p->next;
		free(p);
		showpoints(*head);
		showtopic("\n删除成功!!!!(按任意键继续)");
		getch();
	}
	return pro;
}

总结

要理解链表的各个结点连接方式,在完成对链表的一系列操作时,要先查找到目标结点的前驱结点,然后通过改变该节点的指向来实现操作。因此要充分理解和掌握链表的查找。链表这一内容,应用到了结构体和指针,要掌握好链表,还需要掌握好指针与结构体的相关知识。

你可能感兴趣的:(笔记)