データ構造学習記録3-単一リンクリスト
1.原則
1.簡単な説明
シーケンステーブルは固定スペースであるため、時空レートに問題があります。なんらかの方法でノードを次々と動的に接続できれば、はるかに良いかもしれません。そのため、この場合、単一リンクリストのデータ構造を考え出しました。
2.分析
単一リンクリストの場合、增删改查
これらの基本的な機能は間違いなく必要です。さらに、ノードの定義に加えて、データに加えて格納し、次のノードのデータ構造を「センス」する必要がある場合は、指针
代わりに使用できます。
3.アイデアのイラスト
1.3.1ノードの定義
2つの部分を含む構造を作成できます。最初の部分はデータです。2番目の部分は次のノードへのポインタを格納*next
し、デフォルト値に初期化しますNULL
。後で検出される限り、そうではありませんNULL
。次に、次のように表示されます。彼の後ろにノードがあること。ノードがポイントされるとNULL
、それはこのノードが終了したことを意味します。
1.3.2リンクリストの定義
リンクリスト全体の構造が同じであるため、固定ノードを直接取得できます表头
。
次に、習慣に従って、ヘッダーが指す最初のノードのシーケンス番号を指定します0
。
1.3.3リンクリスト/ノードの初期化
リンクリストは同じノードで構成されているため、リンクリストの初期化はノードの初期化と同じです。したがって、を使用しmalloc
てノードを生成し、それを*next
指すNULL
だけで済みます。
1.3.4テーブルトラバーサル
while
まで実行するために使用できるテーブル走査*next == NULL
。
1.3.5テーブルの破壊
テーブルを破壊するために、私たちは横断することができfree
、最後まで。
1.3.6ノードの挿入
トラバース+カウントすることにより、挿入されるノードの前の位置を見つけ、それをとして記録しLastNode
、次の操作を実行できます。
- 挿入する適切なノード情報を作成し、を示し
ThisNode
、へThisNode
の*next
割り当てをLastNode
行い*next
ます。このようにして、挿入したノードは次のノードを指します。 - なります割り当てられたアドレス。このようにして、テーブルは再び完成します。たとえば、図では
LastNode
*next
ThisNode
LastNode 是 0
ThisNode = index 是 1
1.3.7ノードの削除
挿入と同様に、削除するノードの前の位置に移動してから、次のプロセスを実行する必要があります。
- アドレスを読み取って保存
LastNode
し*next
ます。これが削除したいものですThisNode
。 - 私たちは入れポイントのを。この時点で、リストを再度トラバースすると、トラバースできなくなり、スキップされます。
LastNode
*next
ThisNode
*next
ThisNode
free
ThisNode
意味がないのでオフにします。そのようなノードの削除。
1.3.7ノードの変更
変更については何も言うことはありません。データを変更するだけではリンクリストの構造は変更されないため、変更を直接トラバースするだけdata
です。
1.3.8ノードクエリ
クエリの場合は、トラバースするだけです。
2.コード
主な機能を自分で変更して、効果を実現します
#include <stdio.h>
#include <stdlib.h>
#define OK 1
#define ERROR 0
// 定义数据类型
typedef struct elemType {
int data1;
int data2;
}data;
//定义节点
typedef struct Node {
data data;
struct Node *next;
//不能写成 Node *next 因为此时还没有typedef成功,只能用结构体嵌套的方式定义
}Node;
Node* ListInit(void);
void ListShow(Node *list);
int ListInsert(Node *list, data data_in, int index);
int ListDelect(Node *list, int index);
int ListModify(Node *List, data data_in, int index);
int ListQuery(Node *list, data data_in);
int main()
{
Node* List = ListInit();
data test;
test.data1 = 1;
test.data2 = 2;
ListInsert(List, test, 0);
test.data1 = 3;
ListInsert(List, test, 1);
ListShow(List);
printf("-------\n");
//ListDelect(List, 0);
//ListShow(List);
//printf("-------\n");
test.data1 = 5;
ListModify(List,test,1);
ListShow(List);
printf("query get %d\n", ListQuery(List, test));
test.data1 = 88;
printf("query get %d\n", ListQuery(List, test));
return 0;
}
Node* ListInit(void)
{
Node* list = (Node *)malloc(sizeof(Node)); // 创建节点
if (list == NULL)
{
exit(0); // 节点创建失败,退出
}
else
{
list->next = NULL; // 节点初始化成功,返回节点作为表头
return list;
}
}
void ListShow(Node* list)
{
int cont = 0;
while(list->next != NULL) // 遍历到表末尾
{
list = list->next; // 跳过表头,list变成真第一个节点
printf("No.%d data is %d %d\n", cont, list->data.data1, list->data.data2);
++cont; // 这个节点已输出,cont变成下一个节点的序号
}
}
int ListInsert(Node *list, data data_in, int index)
{
int cont = -1; // 初始化为 -1,简化后面操作
Node *ThisNode = (Node *)malloc(sizeof(Node));
ThisNode->data = data_in; // 初始化创建好的节点
ThisNode->next = NULL;
if (list->next == NULL) // 判断这个表是不是空表,空表就特殊处理了
{
list->next = ThisNode;
return OK;
}
while(list->next != NULL && cont < index - 1) //遍历 到插入的前一个节点
{
list = list->next; //移动到下一个节点
++cont; // 因为list初值是表头,cont初值-1,所以这样操作后,这句话后的list的节点序号和cont对应
}
ThisNode->next = list->next; //更新操作
list->next = ThisNode;
return OK;
}
int ListDelect(Node *list, int index)
{
Node *dNode = NULL; //声明一下要删除的节点变量
int cont = -1; // 同理
if (list->next == NULL)
{
return ERROR; //空链表,没意义,返回错误
}
else
{
while(list->next != NULL && cont < index - 1)
{
list = list->next;
++cont;
// 和插入一样的解释,遍历。
}
dNode = list->next;
list->next = dNode->next; // 这样就跳过了dNode
free(dNode); //释放掉删除的Node
return OK;
}
}
int ListModify(Node *list, data data_in, int index)
{
int cont = -1;
while(list->next != NULL && cont < index) // 因为要删除,所以要遍历到它本身
{
list = list->next;
++cont;
}
if (cont == index) // 确定遍历到了它
{
list->data = data_in;
return OK;
}
else // 理论上来说是长度不够 index比表长更长
{
return ERROR;
}
}
int ListQuery(Node *list, data data_ck)
{
int cont = 0;
while(list->next != NULL) // 查询同修改
{
list = list->next;
if (list->data.data1 == data_ck.data1 && list->data.data2 == data_ck.data2)
{
return cont;
}
++cont;
}
return -1;
}