導入:
逐次記憶構造であっても連鎖記憶構造であっても、要素をメモリに記憶する際には、その要素の関連情報だけでなく、その要素と他の要素との関係も記憶する必要があります。以前に学習したように、「固有の」物理構造は要素間の関係を自然に表現でき、要素間の関係を表現するための追加情報は必要ありません。チェーン ストレージなどの非順次ストレージ構造の場合、この関係を表現するには追加のポインターが必要です。
単一リスト:
データ要素を格納することに加えて、各ノードは次のノードへのポインタも格納します。
単一リンクリストの特徴:
利点: 広い連続スペースが不要、容量変更が容易
短所: ランダムアクセスができないため、ポインタを格納するために一定量のスペースが必要です。
意味:
typedef struct LNode {
int data;
struct LNode* next;//指针指向下一个节点,指针的类型为节点类型;
}*LinkNode;//声明*LinkNode为结构体指针类型
上記の方法以外にも、まず LinkNode を構造体型として宣言し、対応する変数をポインタとして定義することもできます。
単結合リストは先頭ノードと非先頭ノードに分けられ、通常は先頭ノードを主に研究します。
初期化操作:
すべての操作の前に、まず空の単一リンク リストを作成する必要があります。次に、最初にヘッド ノードを割り当てる必要があります。
void InistLinkNode(LinkNode& L) {
L = (LNode*)malloc(sizeof(LNode));//分配头结点
L->next = NULL;
}
ヘッド挿入方法:
「ヘッド挿入法」とは、その名のとおり、ヘッドノードの後に要素を挿入する方法で、一度挿入するのは普段話していることと変わりませんが、ヘッドノードの後に複数回挿入するのが「初めての本格的な挿入」です。ノード」を選択した場合、最終的に格納されるデータの順序が挿入した順序と逆になる現象は発生しますか?
void InsertLinkNode(LinkNode& L) {
LNode* s;
int x,Length;
printf("请输入你要插入的元素个数:");
scanf("%d", &Length);
printf("请输入你要插入的元素:\n");
for (int j = 0; j < Length; j++) {
s = (LNode*)malloc(sizeof(LNode));//每插入一个元素之前,都需要给它分配节点空间
scanf("%d", &x);
s->data = x;
s->next = L->next;
L->next = s;
}
}
プログラムを通じて次のことを確認します。
テール挿入方法:
「末尾挿入法」はその名の通り、テーブルの末尾に要素を挿入する方法で、通常の挿入ですが、テーブルの末尾の位置はどうやって求めるのでしょうか?シーケンス テーブルでは、シーケンシャル ストレージ構造の自然な特性を最大限に活用し、添字を使用してそれを見つけることができます。ただし、単一リンク リストではこれを行う方法はありません。方法は 2 つしかありません。それをループするか、試してみるかです。テーブルの最後に行うには、マークを付けます。
では、どの方法が良いのでしょうか?
答えは2番目です!ループトラバーサルの方法は、要素を 1 つ挿入するだけであれば問題ないようですが、ループを複数回繰り返す場合、間違いなく時間計算量が増加し、明らかに良い方法ではありません。
2 番目の方法には時間計算量の問題はありません。只需要在表尾位置做个标记,使它永远指向表尾即可。
void TailInsertLinkNode(LinkNode& L) {
LNode* s,*r;
int x,Length;
r = L;//r为表尾指针
printf("请输入你要插入的元素个数:");
scanf("%d", &Length);
printf("请输入你要插入的元素:\n");
for (int j = 0; j < Length; j++) {
s = (LNode*)malloc(sizeof(LNode));
scanf("%d", &x);
s->data = x;
r->next = s;
r = s;//s为当前的表尾指针,将他的值赋值给r----使r永远指向表尾
}
printf("\n");
r->next = NULL;
}
i 番目の要素を削除します。
要素を削除したいので、まず保证这个元素是非NULL
、次に を保証する必要があります它前面的那个节点也是非NULL
。なぜでしょうか? リンクされたリストから要素が削除された場合、前のノードが NULL でない場合にのみ、後続の要素と前のサブリスト間の接続が確立されるためです。
void DeleteLinkNode(LinkNode& L) {
int x, j = 0,e;
printf("请输入你要删除的元素位序:\n");
scanf("%d", &x);
LNode*p = L;
while (p != NULL && j < x - 1) {
//寻找要删除元素前的元素
p = p->next;
j++;
}
if (p == NULL)
{
printf("不存在我们要删除的元素!");
}
if (p->next == NULL)//判断该要删除的节点是否为NULL
{
printf("不存在我们要删除的元素!");
}
LNode* q = p->next;//q为我们要删除的节点
e = q->data;
p->next = q->next;
free(q);//需要及时的将删除了的元素空间进行释放
}
其他的基本操作都是很常规化的,这里就不单独的进行解释了,需要注意的点,我会在文章结尾部分的完整代码的注释中展出。
位置 i に挿入:
void IncreaseLinkNode(LinkNode& L) {
printf("请输入你要插入的元素和位序:(元素和位序之间用逗号隔开)\n");
int x, j = 0, e;
scanf("%d,%d",&e, &x);
LNode* s = L, * r= (LNode*)malloc(sizeof(LNode));
while (j < x-1 && s != NULL) {
j++;
s = s->next;
}
r->data = e;
r->next = s->next;
s->next = r;
}
如下所示的代码顺序不能发生改变,否则会出现无法和后面的节点;
r->next = s->next;
s->next = r;
完全なコードは次のとおりです。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
typedef struct LNode {
int data;
struct LNode* next;
}*LinkNode;
//初始化
void InistLinkNode(LinkNode& L) {
L = (LNode*)malloc(sizeof(LNode));//分配头结点
L->next = NULL;
}
//头插法
void InsertLinkNode(LinkNode& L) {
LNode* s;
int x,Length;
printf("请输入你要插入的元素个数:");
scanf("%d", &Length);
printf("请输入你要插入的元素:\n");
for (int j = 0; j < Length; j++) {
s = (LNode*)malloc(sizeof(LNode));
scanf("%d", &x);
s->data = x;
s->next = L->next;
L->next = s;
}
}
//尾插法
void TailInsertLinkNode(LinkNode& L) {
LNode* s,*r;
int x,Length;
r = L;
printf("请输入你要插入的元素个数:");
scanf("%d", &Length);
printf("请输入你要插入的元素:\n");
for (int j = 0; j < Length; j++) {
s = (LNode*)malloc(sizeof(LNode));
scanf("%d", &x);
s->data = x;
r->next = s;
r = s;
}
printf("\n");
r->next = NULL;
}
//输出单链表
void PrintLinkNode(LinkNode& L)
{
LNode* s=L->next;
printf("单链表元素如下:\n");
while (s != NULL) {
printf("%d", s->data);
s =s->next;
}
printf("\n");
}
//求线性表长度
void lengthLinkNode(LinkNode& L)
{
LNode* s = L->next;
int n=0;
while (s != NULL) {
n++;
s = s->next;
}
printf("单链表长度为:%d",n);
printf("\n");
}
//取第i个元素
void GetElemLinkNode(LinkNode& L) {
printf("请输入你要查找的元素位序:\n");
int i, j = 0;
LNode* s=L;
scanf("%d", &i);
while (j < i && s != NULL) {
j++;
s = s->next;
}
if (s == NULL) {
printf("不存在我们要查找的元素!");
}
else {
printf("元素位序为%d的元素是%d",i, s->data);
}
printf("\n");
}
//删除第i个元素
void DeleteLinkNode(LinkNode& L) {
int x, j = 0,e;
printf("请输入你要删除的元素位序:\n");
scanf("%d", &x);
LNode*p = L;
while (p != NULL && j < x - 1) {
p = p->next;
j++;
}
if (p == NULL)
{
printf("不存在我们要删除的元素!");
}
if (p->next == NULL)
{
printf("不存在我们要删除的元素!");
}
LNode* q = p->next;
e = q->data;
p->next = q->next;
free(q);
}
//在第i个位置插入
void IncreaseLinkNode(LinkNode& L) {
printf("请输入你要插入的元素和位序:(元素和位序之间用逗号隔开)\n");
int x, j = 0, e;
scanf("%d,%d",&e, &x);
LNode* s = L, * r= (LNode*)malloc(sizeof(LNode));
while (j < x-1 && s != NULL) {
j++;
s = s->next;
}
r->data = e;
r->next = s->next;
s->next = r;
}
//查找位序
void SearchLinkNode(LinkNode &L) {
int x,j=1;
LNode* p=L->next;
printf("请输入你要查找的元素:\n");
scanf("%d", &x);
while (p != NULL && p->data != x) {
p = p->next;
j++;
}
if (p == NULL) {
printf("您要查找的元素不存在!");
}
else {
printf("你要查找的元素%d的位序为%d", x, j);
}
}
int main() {
LinkNode L;
InistLinkNode(L);
/*InsertLinkNode(L);*/
TailInsertLinkNode(L);
PrintLinkNode(L);
lengthLinkNode(L);
GetElemLinkNode(L);
IncreaseLinkNode(L);
PrintLinkNode(L);
DeleteLinkNode(L);
PrintLinkNode( L);
SearchLinkNode(L);
}
出力: