線形リストの連鎖表現は、リンクリストの形式で線形構造を実装することです。
C言語で構造体を定義できます。構造体は2つの部分に分割できます。一方の部分は保存するデータを格納し、もう一方の部分は構造体へのポインターを定義するために使用されます。このポインタは次のそのような構造を指し、次の構造のポインタは次の構造を指すことができます。
このように、構造は互いに直接接続されているため、リンクリストの形式を実現できます。
配列にシーケンシャル形式で格納されている最後の線形構造の場合、論理アドレスは隣接しており、物理アドレスも隣接しているため、ランダムアクセスと表示に便利であり、挿入と削除には不便です(両方の要素を前方に移動する必要があります。後方に移動)。
今回リンクリストの形式で実装された線形構造には、隣接する論理アドレスがありますが、必ずしも隣接する物理アドレスである必要はありません。
リンクリスト形式の線形リストのすべてのアルゴリズムのアイデアは、次のように機能します。
記事ディレクトリ
構造リンクリストの定義
#include<stdio.h>
#include<stdlib.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
//定义结构体Student,作为链表的数据
struct Student{
int id;
char *name;
int age;
};
//定义链表结构体(此结构体也可单独作为链表结点)
typedef struct LNode{
Student student; //数据Student
LNode *next; //下一结点LNode
}LNode, *LinkList; //LinkList即为链表的定义形式
すべての関数宣言
int initLinkList(LinkList &list); //初始化链表
void printLinkList(LinkList &list); //打印链表列表
int getStudentList(LinkList list, int i, Student &student); //获取链表中某一元素
int insertLinkList(LinkList &list, int i, Student student); //为链表的指定位置插入元素
int deleteLinkList(LinkList &list, int i, Student &student); //删除链表指定位置的元素
int mergeLinkList(LinkList &list_a, LinkList &list_b, LinkList &list_c); //合并有序链表list_a、list_b为新有序单链表list_c
リンクリストを初期化する
//链表的初始化操作
int initLinkList(LinkList &list)
{
list = (LNode *)malloc(sizeof(LNode)); //开辟头结点指针
list->next = NULL; //头结点的后继结点初始化为NULL
return OK; //返回成功信息
}
リンクリストの要素を取得する
//数据结构 算法2.8---->获取线性表中的某个元素
int getStudentList(LinkList list, int i, Student &student)
{
if(i < 1) return ERROR; //若序号小于1表示获取元素失败,返回错误信息
int j = 1; //定义标识位j并设置为1
LNode *p = list; //定义p指针指向链表的头结点
//循环找出链表中的第i个结点,令p指向它
while(j <= i)
{
p = p->next; //指针后挪,遍历下一结点
if(p==NULL) return ERROR; //若结点已为NULL,返回错误信息
j++; //计数器累加
}
student = p->student; //将该结点的信息赋值返回
return OK; //返回操作成功信息
}
リンクリスト挿入操作
//数据结构 算法2.9---->指定位置插入一个元素
int insertLinkList(LinkList &list, int i, Student student)
{
int j = 1;
if(i < 1) return ERROR; //若插入位置小于1,返回ERROR失败信息,插入失败
LNode *p = list, *node; //定义p指针指向头节点,定义node结点作为插入结点
//通过循环找到待插入结点的前一个结点,即i-1个结点
for(j = 1; j < i && (p!=NULL); j++)
{
p = p->next;
}
if(p == NULL && j >= i) return ERROR; //若前一个结点为NULL或者插入位置超出范围表示插入失败,返回失败信息
node = (LNode *)malloc(sizeof(LNode)); //开辟一个新的结点内存信息
node->student = student; //保存插入元素的值
node->next = p->next; //将目前第i个位置的结点作为node结点的后继结点
p->next = node; //再将第i-1个结点的后继结点作为node结点,即插入第i个位置成功
return OK; //返回插入成功信息
}
リスト削除操作
//数据结构 算法2.10---->指定位置删除一个元素,并返回该元素的值
int deleteLinkList(LinkList &list, int i, Student &student)
{
int j = 1; //定义统计次数标识位j并初始化为1
if(i < 1) return ERROR; //如果删除位置小于1,则返回删除失败
LNode *p = list, *q; //定义p指针最先指向链表头指针
//循环遍历找到链表的第i-1个位置,准备进行插入
for(j = 1; j < i && (p->next!=NULL); j++)
{
p = p->next;
}
//如果第i个位置为null或者删除位置已超出,返回删除失败信息
if(p->next == NULL || j >= i) return ERROR;
student = p->next->student; //将待删除位置的结点信息赋值为student,待传回操作
q = p->next; //保存删除结点的位置信息
p->next = p->next->next; //直接将待删除结点的前一个结点的后继结点 连接到 待删除结点的后继节点(相当于删除)
free(q); //释放删除结点的地址信息数据
return OK; //返回删除成功
}
2つの順序付けられた単一リンクリスト操作をマージします
//数据结构 算法2.12---->合并两个有序单链表
int mergeLinkList(LinkList &list_a, LinkList &list_b, LinkList &list_c)
{
LNode *pa = list_a->next, *pb = list_b->next, *pc; //定义pa、pb、pc三个指针, pa、pb分别指向链表list_a, list_b
initLinkList(list_c); //初始化链表c
pc = list_c; //pc指向链表list_c
//若链表pa,pb都未合并完毕,重复循环插入
while(pa != NULL && pb != NULL)
{
if(pa->student.id <= pb->student.id) //按照升序进行有序合并,若pa指向结点学生的序号小于pb
{
pc->next = pa; //则把pa指向结点添加到pc指向链表之后
pc = pa; //pc移动到后一个结点(即pa),准备添加下一个结点
pa = pa->next; //pa添加过之后,指针也向后进行移动
}
else //反之亦然
{
pc->next = pb;
pc = pa;
pb = pb->next;
}
}
if(pa != NULL) pc->next = pa; //若最终pa指向链表未添加完毕,直接将pa剩余链表接到pc链表后
if(pb != NULL) pc->next = pb; //若最终pb指向链表未添加完毕,直接将pb剩余链表接到pc链表后
return OK; //返回成功信息
}
単一リンクリストの印刷操作
//打印所有结点
void printLinkList(LinkList &list)
{
int i = 0; //设置i作为记录结点个数
LNode *p = list->next;
while(p!=NULL) //循环输出所有结点
{
printf("id = %d.\tname = %s.\tage = %d.\n", p->student.id, p->student.name, p->student.age); //输出结点信息
p = p->next; //p指针后挪至下一结点信息
i++;
}
printf("输出链表列表完毕,共%d条数据.\n", i);
}
コードとテストをマージする
#include<stdio.h>
#include<stdlib.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
//定义结构体Student,作为链表的数据
struct Student{
int id;
char *name;
int age;
};
//定义链表结构体(此结构体也可单独作为链表结点)
typedef struct LNode{
Student student; //数据Student
LNode *next; //下一结点LNode
}LNode, *LinkList;
int initLinkList(LinkList &list); //初始化链表
void printLinkList(LinkList &list); //打印链表列表
int getStudentList(LinkList list, int i, Student &student); //获取链表中某一元素
int insertLinkList(LinkList &list, int i, Student student); //为链表的指定位置插入元素
int deleteLinkList(LinkList &list, int i, Student &student); //删除链表指定位置的元素
int mergeLinkList(LinkList &list_a, LinkList &list_b, LinkList &list_c); //合并有序链表list_a、list_b为新有序单链表list_c
int main()
{
LinkList list;
initLinkList(list);
LNode *q = list, *p = list;
for(int i = 0; i < 10; i++)
{
p = (LNode *)malloc(sizeof(LNode));
p->student.id = i;
p->student.name = {
"Hello World"};
p->student.age = i+20;
q->next = p;
q = p;
}
q->next = NULL;
printLinkList(list);
while(1)
{
int i = 0;
Student student;
printf("请输入您想要查找的元素:\n");
scanf("%d", &i);
if(getStudentList(list, i , student))
{
printf("查找成功!\n");
printLinkList(list);
}
else printf("查找失败!\n");
}
return 0;
}
//链表的初始化操作
int initLinkList(LinkList &list)
{
list = (LNode *)malloc(sizeof(LNode)); //开辟头结点指针
list->next = NULL; //头结点的后继结点初始化为NULL
return OK; //返回成功信息
}
//数据结构 算法2.8---->获取线性表中的某个元素
int getStudentList(LinkList list, int i, Student &student)
{
if(i < 1) return ERROR; //若序号小于1表示获取元素失败,返回错误信息
int j = 1; //定义标识位j并设置为1
LNode *p = list; //定义p指针指向链表的头结点
//循环找出链表中的第i个结点,令p指向它
while(j <= i)
{
p = p->next; //指针后挪,遍历下一结点
if(p==NULL) return ERROR; //若结点已为NULL,返回错误信息
j++; //计数器累加
}
student = p->student; //将该结点的信息赋值返回
return OK; //返回操作成功信息
}
//数据结构 算法2.9---->指定位置插入一个元素
int insertLinkList(LinkList &list, int i, Student student)
{
int j = 1;
if(i < 1) return ERROR; //若插入位置小于1,返回ERROR失败信息,插入失败
LNode *p = list, *node; //定义p指针指向头节点,定义node结点作为插入结点
//通过循环找到待插入结点的前一个结点,即i-1个结点
for(j = 1; j < i && (p!=NULL); j++)
{
p = p->next;
}
if(p == NULL && j >= i) return ERROR; //若前一个结点为NULL或者插入位置超出范围表示插入失败,返回失败信息
node = (LNode *)malloc(sizeof(LNode)); //开辟一个新的结点内存信息
node->student = student; //保存插入元素的值
node->next = p->next; //将目前第i个位置的结点作为node结点的后继结点
p->next = node; //再将第i-1个结点的后继结点作为node结点,即插入第i个位置成功
return OK; //返回插入成功信息
}
//数据结构 算法2.10---->指定位置删除一个元素,并返回该元素的值
int deleteLinkList(LinkList &list, int i, Student &student)
{
int j = 1; //定义统计次数标识位j并初始化为1
if(i < 1) return ERROR; //如果删除位置小于1,则返回删除失败
LNode *p = list, *q; //定义p指针最先指向链表头指针
//循环遍历找到链表的第i-1个位置,准备进行插入
for(j = 1; j < i && (p->next!=NULL); j++)
{
p = p->next;
}
//如果第i个位置为null或者删除位置已超出,返回删除失败信息
if(p->next == NULL || j >= i) return ERROR;
student = p->next->student; //将待删除位置的结点信息赋值为student,待传回操作
q = p->next; //保存删除结点的位置信息
p->next = p->next->next; //直接将待删除结点的前一个结点的后继结点 连接到 待删除结点的后继节点(相当于删除)
free(q); //释放删除结点的地址信息数据
return OK; //返回删除成功
}
//数据结构 算法2.12---->合并两个有序单链表
int mergeLinkList(LinkList &list_a, LinkList &list_b, LinkList &list_c)
{
LNode *pa = list_a->next, *pb = list_b->next, *pc; //定义pa、pb、pc三个指针, pa、pb分别指向链表list_a, list_b
initLinkList(list_c); //初始化链表c
pc = list_c; //pc指向链表list_c
//若链表pa,pb都未合并完毕,重复循环插入
while(pa != NULL && pb != NULL)
{
if(pa->student.id <= pb->student.id) //按照升序进行有序合并,若pa指向结点学生的序号小于pb
{
pc->next = pa; //则把pa指向结点添加到pc指向链表之后
pc = pa; //pc移动到后一个结点(即pa),准备添加下一个结点
pa = pa->next; //pa添加过之后,指针也向后进行移动
}
else //反之亦然
{
pc->next = pb;
pc = pa;
pb = pb->next;
}
}
if(pa != NULL) pc->next = pa; //若最终pa指向链表未添加完毕,直接将pa剩余链表接到pc链表后
if(pb != NULL) pc->next = pb; //若最终pb指向链表未添加完毕,直接将pb剩余链表接到pc链表后
return OK; //返回成功信息
}
//打印所有结点
void printLinkList(LinkList &list)
{
int i = 0; //设置i作为记录结点个数
LNode *p = list->next;
while(p!=NULL) //循环输出所有结点
{
printf("id = %d.\tname = %s.\tage = %d.\n", p->student.id, p->student.name, p->student.age); //输出结点信息
p = p->next; //p指针后挪至下一结点信息
i++;
}
printf("输出链表列表完毕,共%d条数据.\n", i);
}
まとめ
つまり、要素を挿入および削除する場合、リンクリストはシーケンシャルストレージよりも便利であり、動的形式でのノードの拡張もスペース使用率において効率的ですが、最初のノードから順番にトラバースおよび検索するのは少し不便です。 。リンクリストを保存する必要がある場合の長さ情報の場合、他の情報をヘッドノードに保存することもできます。循環リンクリスト、二重リンクリストなど、リンクリストにはさまざまな形式があり、更新してから更新します。将来はゆっくり!
さあ、オリがあげる〜