【データ構造学習記録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、次の操作を実行できます。

  1. 挿入する適切なノード情報を作成し、を示しThisNode、へThisNode*next割り当てをLastNode行い*nextます。このようにして、挿入したノードは次のノードを指します。
  2. なります割り当てられたアドレス。このようにして、テーブルは再び完成します。たとえば、図ではLastNode*nextThisNode
    LastNode 是 0 ThisNode = index 是 1

1.3.7ノードの削除

ここに画像の説明を挿入

挿入と同様に、削除するノードの前の位置に移動してから、次のプロセスを実行する必要があります。

  1. アドレスを読み取って保存LastNode*nextます。これが削除したいものですThisNode
  2. 私たちは入れポイントのをこの時点で、リストを再度トラバースするとトラバースできなくなり、スキップされます。LastNode*nextThisNode*nextThisNode
  3. freeThisNode意味がないのでオフにします。そのようなノードの削除。

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;
} 

おすすめ

転載: blog.csdn.net/u011017694/article/details/109287688