单链表
(1)构造链表
链表的基本单位是节点,一个节点中由数据域和指针域组成,如下图所示:
链表用来存储数据,通过前驱或者后继来找寻上一个或下一个节点,一个个连接起来就是链表,如下图所示:
通过下面的代码我们就可以构造一个链表了:
#include <stdio.h>
#include <malloc.h>
struct LinkNode *initLink();
int main() {
struct LinkNode* p;
printf("linkNode init");
p=initLink();
return 0;
}
struct ListNode{
int val;
struct ListNode* next;
};
struct LinkNode *initLink(){
int i;
struct ListNode* p=NULL; //创建头指针
struct ListNode* temp=(struct ListNode*)malloc(sizeof (struct ListNode)); //动态分配
temp-> val =0;
temp->next=NULL;
//头指针指向头节点
p=temp;
//每创建一个结点,都让其直接前驱节点的指针指向temp
for (int j = 0; j < 5; ++j) {
struct ListNode* a=(struct ListNode*) malloc(sizeof (struct ListNode));
a->val=i;
a->next=NULL;
temp->next=a;//p的后继节点是a
temp=temp->next; //temp再指向下一个节点
}
return p;
}
(2)遍历链表
接下来可以通过遍历链表来打印链表:
void printList(struct ListNode* p) {
struct ListNode* temp = p;//temp指针用来遍历链表
//只要temp指向结点的next值不是NULL,就执行输出语句。
while (temp) {
// struct ListNode* f = temp;//准备释放链表中的结点
printf("%d ", temp->val);
temp = temp->next;
// free(f);
}
printf("\n");
}
(3)链表插入
对链表进行插入操作,要考虑三种情况:首部,中部,尾部
-
在链表首部插入
创建一个新的节点,节点的Next指向链表的头节点,原来的每个节点依次退后;直接在首部添加节点,可能会导致链表顺序逆转。
-
在链表中间插入
在中间插入要先通过遍历链表找的要插入的位置以及前驱节点和后继节点,直接在中间添加新节点可能导致链表断裂,所以在插入时新节点的Next为前驱节点的Next,然后前驱节点的Next为新节点。
-
在链表尾部插入节点
直接在链表的尾节点指向新节点,尾部插入较简单,但是没有尾指针的时候要遍历整个链表才能找到,导致效率较差。
综上所述,链表的插入代码如下:
struct ListNode* insertNode(struct ListNode* head, struct ListNode* nodeInsert, int position) {
if (head == NULL) {
// 这里可以认为待插入的节点就是链表的头节点,也可以抛出不能插入的异常
return nodeInsert;
}
int size = getLength(head);
if (position > size + 1 || position < 1) {
printf("位置参数越界");
return head;
}
// 插入节点到头部
if (position == 1) {
nodeInsert->next = head;
head = nodeInsert;
return head;
}
struct ListNode* pNode = head;
int count = 1;
// 遍历链表,找到插入位置的前一个节点
while (count < position - 1) {
pNode = pNode->next;
count++;
}
nodeInsert->next = pNode->next;
pNode->next = nodeInsert;
return head;
}
(4)链表的删除
链表的删除和插入一样分为删除首部,中间和尾部元素。
-
删除表头节点
将表头变成原表头的Next节点即可,原表头不可达,如下图所示:
-
删除中间节点
找到要被删除节点的前驱节点,前驱的原本Next为被要删除节点,改为要被删除节点的Next
-
删除尾部节点
找到要被删除的节点的前驱节点,通过遍历找到,直接将前驱节点的Next改为NULL。
通过下面的代码实现删除:
struct ListNode* deleteNode(struct ListNode*head, int position) {
if (head == NULL) {
return NULL;
}
int size = getLength(head);
if (position > size || position < 1) {
printf("输入的参数有误\n");
return head;
}
if (position == 1) {
return head->next;
} else {
struct ListNode* preNode = head;
int count = 1;
while (count < position - 1) {
preNode = preNode->next;
count++;
}
struct ListNode*curNode = preNode->next;
preNode->next = curNode->next;
free(curNode);
return head;
}
}