前の記事から続く:https://blog.csdn.net/m0_37957160/article/details/108685364
例:動的リンクリスト内の指定されたノードを削除する関数を記述します。
問題解決のアイデア:
1. pが指す最初のノードから始めて、ノードのnumの値が、入力されて削除を要求された学生番号と等しいかどうかを確認します。
2.等しい場合はノードを削除します。等しくない場合は、pを1ノード戻し(検索を続行)、テーブルの最後に到達するまで移動を続けます。
3. 2つのポインタ変数p1とp2を設定し、最初にp1が最初のノードを指すようにすることができます。
4.削除するノードが最初のノードでない場合は、p1を次のノードを指すように戻し(p1-> p1の隣に割り当てます)、p1の値をp2に割り当てる前に、p2をチェックしたばかりのノードを指すようにします。過去のノード(これはなぜですか?今すぐ削除操作Cを実装する必要があることがわかっているため、このノードBの次のノードは次のノードDのアドレスを指している必要があります。したがって、このp2は最初にBを指している必要があります。それを保持すると、p2の次はp1を指すことができます)。
アルゴリズムのフローチャート:
コードは次のとおりです(ノードを削除する前に、まずリンクリストを作成してください)
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#define LEM sizeof(struct student)//student结构大小
struct student *create();//创建链表
struct student *del(struct student *head,int num);//del函数用于删除结点,*head即链表的头指针,num是要删除的结点num
void print(struct student *head);//打印链表
struct student
{
int num;
float score;
struct student *next
};
int n;//全局变量,用来记录存放了多少数据
void main()
{
struct student *stu,*p;
int n;
stu=creat();
p=stu;
print(p);
printf("Please enter the num to delete:");
scanf("%d",&n);
print(del(p,n));
printf("\n\n");
system("pause");
}
struct student *creat()
{
struct student *head;
struct student *p1, *p2;
p1 = p2 = (struct student *)malloc(LEN); // LEN是student结构的大小
printf("Please enter the num :");
scanf("%d", &p1->num);
printf("Please enter the score :");
scanf("%f", &p1->score);
head = NULL;
n = 0;
while( p1->num )
{
n++;
if( 1 == n )
{
head = p1;
}
else
{
p2->next = p1;
}
p2 = p1;
p1 = (struct student *)malloc(LEN);
printf("\nPlease enter the num :");
scanf("%d", &p1->num);
printf("Please enter the score :");
scanf("%f", &p1->score);
}
p2->next = NULL;
return head;
}
void print(struct student *head)
{
struct student *p;
printf("\nThere are %d records!\n\n", n);
p = head;
if( head )
{
do
{
printf("学号为 %d 的成绩是: %f\n", p->num, p->score);
p = p->next;
}while( p );
}
}
struct student *del(struct student *head,int num)//1指向struct student结构的指针
{
struct student *p1,*p2;//2指向结构的指针
if(NULL==head)//3我们要判断上边函数传进来的指向头结点的这个指针是否为NULL,如果头结点指向NULL,这是一个空链表
{
printf("\nThis list is null!\n");
goto end;//4直接跳转到end这个地方
}
p1=head;//p1指向head
while(p1->num!=num&&p1->next!=NULL)//5p1指向链表的第一个结点,这个结点的学号不等于我们要删除的学号的时候;p1的next还不指向NULL,也就是p1还不是最后一个结点的时候(&&操作两个只要一个为0,则就为0)
{
p2=p1;//6p1的值就给了p2
p1=p1->next;//7p1就指向了下一个数据(下一个结点)(这个时候第一个数据是p2指向了,第二个数据是p1指向了)
}//直到不满足上述while的两个条件才会退出循环
if(num==p1->num)//8p1指向的学号p1->num,等于我们要删除的学号num的时候就应该要做删除操作了
{
if(p1==head)//8还需要再验证一下p1这个时候是不是头结点
{
head=p1->next;//是的话,就必须把头结点给p1的下一个,然后才把p1给删了,(你不能直接把头给切了,如果把头给切了拿什么来返回)(头应该指向p1的下一任,然后才能把头给切掉)
}
else//如果不是头结点,(p2是指向了p1的上一任)
{
p2->next=p1->next;//把p1的next赋值给p1的next(比如p2是指向A结点,P1是结点,p1的next是C结点,因为p1的next就是B指向C(B->C),p2的next就是A指向B(A->B),就是将C给了A,就是直接把B给删除掉了(A->C))(next是一个指针,指向下一个地点的指针)
}
printf("\nDelete No:%d succeed!\n",num);
n=n-1;//n是作为一个全局变量用来记录链表的数据数
}
else
{
printf("%d not been found!\n",num)
}
end://直接结束,因为空链表没有办法删除
return head;
}
結果:
リンクリストの挿入:
リンクリストの挿入とは、既存のリンクリストにノードを挿入することです。
正しく挿入するには、次の2つの問題を解決する必要があります。
(1)挿入位置の見つけ方。
(2)挿入の実現方法。
最初に、ポインタ変数p0を使用して挿入するノードを指し、p1を使用して最初のノードを指すことができます。p0-> numをp1-> numと比較します。p0-> numがp1-> numより大きい場合は、p1を元に戻し、p2がp1が指すノードを指すようにします。(大前提番号はリストのサイズに従って保存されます)
(以下のabcは挿入方法です。02は01の後、03より前なので、挿入位置は03より前でなければなりません。挿入位置を見つけて、このリンクリストに移動するように指示すると、リンクリストは最初に03をダンプし、次にp1が03の後、p2-> nextはまだ03を指しており、それから接触がなくなり始めます(p1が次の位置を指す前に、p1が安全に移動できるようにp1の元の位置をp2で保存する必要があります)。 02(p2)この時点で、p0-> nextは03であるp1を指しているため、ハンドオーバーが実行され、彼はチェーンインされます(この時点で、主な変更は次の変更であることがわかります。ポインタなので、リンクリストの3番目のデータの次の変数は非常に重要です。次のノードの場所を記録します。場所を変更する限り、操作を正常に削除および挿入できます)(途中でさらに面倒ですが、最初に切断し、最初のものはp0を指し、彼は3番目のものを指します)
dは挿入方法です(つまり、挿入されたものは前面、つまりヘッドノードの前にあり、ヘッドはp0を指します。次は元の最初のノードを指します)
eは挿入方法です(挿入される位置は最後にあり、挿入される位置は最後にあるため、そのp0-> nextはnullを指している必要があります)
フローチャート:
まず、p1はヘッドを指し、p0は入力する構造を指します。リンクされたリストが空の場合、ヘッドはp0を指し、p0->はNULLを指します。空のリストではありません、判断しましょう
コード:
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#define LEM sizeof(struct student)//student结构的大小
struct student *create();//创建链表
struct student *del(struct student*head,int num); //del函数用于删除结点, *head即链表的头指针, num是要删除的结点num。
struct student *insert(struct student *head,struct student *stu_2);// 第一个参数需要被插入的链表// 第二个参数待插入的结构的地址
void print(struct student *head);//打印链表
struct student
{
int num;
float score;
struct student *next;
};
int n;//全局变量,用来记录存放了多少数据
void main()
{
struct student *stu,*p,stu_2;
int n;
stu=creat();
p=stu;
print(p);
printf("\nPlease input the num to delete:")
scanf("%d",&n);
print(del(p,n));
printf("\nPlease input the num to insert:")
scanf("%d",&stu_2.num);
printf("Please input the score: ");
scanf("%f", &stu_2.score);
p = insert(stu, &stu_2);//用p指向了他返回的头指针
print( p );//把它给打印出来//其实也可以不用p直接嵌套调用print(insert(stu, &stu_2));
printf("\n\n");
system("pause");
}
struct student *creat()
{
struct student *head;
struct student *p1, *p2;
p1 = p2 = (struct student *)malloc(LEN); // LEN是student结构的大小
printf("Please enter the num :");
scanf("%d", &p1->num);
printf("Please enter the score :");
scanf("%f", &p1->score);
head = NULL;
n = 0;
while( p1->num )
{
n++;
if( 1 == n )
{
head = p1;
}
else
{
p2->next = p1;
}
p2 = p1;
p1 = (struct student *)malloc(LEN);
printf("\nPlease enter the num :");
scanf("%d", &p1->num);
printf("Please enter the score :");
scanf("%f", &p1->score);
}
p2->next = NULL;
return head;
}
//打印
void print(struct student *head)
{
struct student *p;
printf("\nThere are %d records!\n\n", n);
p = head;
if( head )
{
do
{
printf("学号为 %d 的成绩是: %f\n", p->num, p->score);
p = p->next;
}while( p );
}
}
struct student *del( struct student *head, int num)
{
struct student *p1, *p2;
if( NULL == head )
{
printf("\nThis list is null!\n");
goto end;
}
p1 = head;
while( p1->num != num && p1->next != NULL)
{
p2 = p1;
p1 = p1->next;
}
if( num == p1->num )
{
if( p1 == head )
{
head = p1->next;
}
else
{
p2->next = p1->next;
}
printf("Delete No: %d succeed!\n", num);
n = n-1;
}
else
{
printf("%d not been found!\n", num);
}
end:
return head;
}
//插入
struct student *insert(struct student *head,struct student *stu_2)
{
struct student *p0,*p1,*p2;
p1=head;
p0=stu_2;
if(NULL==head)
{
head=p0;
p0->next=NULL;
}
else
{
while((p0->num > p1->num)&&(p1->next!=NULL))//意思就是待插入的102大于101,或者//两种情况退出while((第一种p0->num < p1->num)达到了插入的条件,)(第二种p0跑到了最后表的结尾)
{
p2=p1;//p2用来保存p1的结点(因为我们插入需要用到p1的上一个结点,所以用p2来保存)
p1=p1->next;//p1跳槽指向下一个节点(其实这个while循环是在为中间插入做前期工作)
}
if(p0->num <= p1->num)//小于的话又有两种情况:
{
if(head==p1)//p1是头结点,插入头部
{
head=p0;
}
else//普通情况,插入中间
{
p2->next=p0;//p2是刚才p1的上一个结点的值,p2的next指向了p0
}
p0->next=p1;//p0的next指向了p1
}
else//p0的num最大,插入到末尾
{
p1->next=p0;
p0->next=NULL
}
}
n=n+1;//由于插入,所以增加了一位数据成员进入链表中。
return head;//返回插入链表的头指针(后再通过print调用)
}
//書き直すこともできます。複数回挿入する必要があります
最後に、プログラムを挿入して、学生の家族管理システムを作成します。