Data structure learning record 3-singly linked list
1. Principle
1. Brief description
Because the sequence table is a fixed space, there will be some problems with the space time rate. If we can dynamically connect one node after another in some way, it might be much better. Therefore, in this case, we came up with the data structure of a singly linked list.
2. Analysis
For singly linked lists, we definitely still need 增删改查
these basic functions. Further, in addition to the definition of a node, we store in addition to data, should be capable of further needs to include a "sense" the data structure of the next node, then we can use 指针
instead.
3. Illustration of ideas
1.3.1 Definition of Node
We can create a structure that contains two parts: the first part is our data; the second part stores our pointer to the next node, and *next
initializes it to the default value NULL
. As long as it is detected later, it is not NULL
. Then it shows that there are nodes behind him. Once a node is pointed NULL
, it means that this node is over.
1.3.2 Definition of Linked List
Because the structure of our entire linked list is the same, we can directly take a fixed node as it 表头
.
Then, according to habit, we specify the sequence number of the first node pointed to by the header 0
.
1.3.3 Initialization of linked list/node
Because our linked list is composed of the same nodes, the initialization of our linked list is equal to the initialization of our nodes. So we only need to use to malloc
generate a node and *next
point NULL
it to it.
1.3.4 Table traversal
Table traversal we can use while
to carry out until *next == NULL
.
1.3.5 Destruction of the table
For the destruction of the table, we can traverse, free
and until the end.
1.3.6 Node Insertion
We can find the previous position of the node to be inserted by traversing + counting , record it as LastNode
, and perform the following operations:
- Creating good node information to be inserted, denoted
ThisNode
, andThisNode
the*next
assignment toLastNode
the*next
. In this way, the node we inserted will point to our next node. - Will be
LastNode
the*next
assignedThisNode
address. In this way, the table is complete again.
For example, in the figureLastNode 是 0
ThisNode = index 是 1
1.3.7 Deletion of nodes
Similar to inserting, we still have to traverse to the previous position of the node to be deleted, and then execute this process:
- Read and save
LastNode
the*next
address, this is what we want to deleteThisNode
. - We put
LastNode
the*next
pointThisNode
of*next
. At this point, if we traverse the list again, it can no longer be traversedThisNode
, it is skipped free
OffThisNode
because it has no meaning. The deletion of such a node.
1.3.7 Modification of nodes
There is nothing to say about the modification, just modifying the data will not change the structure of the linked list, so just traverse the modification directly data
.
1.3.8 Node query
For query, just traverse.
2. Code
Modify the main function yourself to achieve the effect
#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;
}