1.单链表
组成:存放内容的data(数据域)+指向下一个节点的next指针(指针域),尾节点的next指针的指向为NULL(所以叫单链表)
核心:头节点和尾节点的next指向,新节点的next指针的指向,新节点的前后节点的next指针
实现:
//步骤:
// 动态创建一个链表: 动态内存申请+模块化设计
//1.创建链表(创建一个表头表示整个链表)
//2.创建节点
//3.插入节点
//4.删除节点
//5.打印遍历链表(测试)
#include<stdio.h>
#include<stdlib.h>
typedef struct Node //设置一个结构体,定义节点基本信息
{
int data; //数据域 //用data存放链表有几个节点的信息
struct Node* next; // 指针域
}Node;
struct Node* createList() //创造一个表头表示整个链表
{
//设置一个headNode表示表头的信息,动态内存分配给一个struct Node大小的空间
struct Node* handNode = (struct Node*)malloc(sizeof(struct Node));
//将头节点的next指针指向空,data重置为0
handNode->data = 0;
handNode->next = NULL;
return handNode;
}
void headInsert(Node* handNode, int data) // 头插法 //int data是我要插入的数
{
//动态内存分配创建一个node变量存放要插入的节点信息
Node* node = (Node*)malloc(sizeof(Node));
node->data = data;
//handNode->next初始指向的内容就是node插入后的下一个节点
node->next = handNode->next;
handNode->next = node; // 让handNode->next指向node
handNode->data++; // 链表数量加一,handNode->data++;
}
//尾插法
void tailInsert(Node* handNode, int data)
{
//创建一个head变量存放头节点的指针,方便从头开始遍历
Node* head = handNode;
//动态内存分配创建一个node变量存放要插入的节点信息
Node* node = (Node*)malloc(sizeof(Node));
//尾插,尾节点的next指针指向NULL
node->next = NULL;
node->data = data;
while(head->next)
{
//让head不断向后遍历
head = head->next;
}//出循环后head->next就为尾节点的next
//让head->next指向新节点
head->next = node;
handNode->data++;
}
//删除节点
void delete(Node* handNode, int data)
{
//创建一个head变量存放头节点的指针
Node* head = handNode;
//current保存当前编列的节点
Node* current = handNode->next;
//pre保存遍历节点的前一个节点
Node* pre = handNode;
while (current)
{
//找到要删除节点
if (current->data == data)
{
//让pre->next指向当前遍历的节点的下一个节点
pre->next = current->next;
free(current);
break;
}
else
{
//让两个变量继续向前遍历
pre = pre->next;
current = current->next;
}
}
//删除后链表节点数量减一 == handNode->data--;
handNode->data--;
}
//打印各个节点内容
void printNode(Node* handNode)
{
Node* node = handNode;
while (node->next)
{
printf("%d->", handNode->data);
node = node->next;
}
printf("NULL\n");
}
int main()
{
Node* list = createList();
headInsert(list, 1);
headInsert(list, 2);
headInsert(list, 3);
headInsert(list, 4);
headInsert(list, 5);
headInsert(list, 6);
delete(list, 4);
delete(list, 1);
delete(list, 6);
printNode(list);
system("pause");
return 0;
}
2.单循环链表
组成:存放节点信息的data(数据域)+指向下一个节点的next(指针域),尾节点的next指针指向的是头节点(所以叫单循环链表)
核心:实现循环,对于尾节点的next的指向,与尾插法后的新节点的next指针的指向
实现:
#include<stdio.h>
#include<stdlib.h>
#define TRUE 1
#define FALSE 0
typedef struct Node
{
int data;
struct Node* next;
}Node;
Node* initList()
{
Node* headNode = (Node*)malloc(sizeof(struct Node));
headNode->data = 0;
//headNode->next指向头,形成循环
headNode->next = headNode;
return headNode;
}
//头插法
void headInsert(Node* headNode, int data)
{
Node* node = (Node*)malloc(sizeof(Node));
node->data = data;
node->next = headNode->next;
headNode->next = node;
headNode->data++;
}
//尾插法
void tailInsert(Node* headNode, int data)
{
Node* node = (Node*)malloc(sizeof(Node));
node->data = data;
Node* head = headNode;
while (head->next != headNode)
{
head = head->next;
}
//最后node->next指向头节点,形成循环
node->next = headNode;
head->next = node;
headNode->data++;
}
int delete(Node* headNode, int data)
{
//node在前,currst在后
Node* node = headNode->next;
Node* currst = headNode;
while (node != headNode)
{
if (node->data == data)
{
//让currst的next指向node的下一个元素
currst->next = node->next;
free(node);
return TRUE;
}
currst = currst->next;
node = node->next;
}
return FALSE;
}
void printNode(Node* headNode)
{
Node* node = headNode->next;
while (node != headNode)
{
printf("%d->", node->data);
node = node->next;
}
printf("NULL\n");
}
int main()
{
Node* l = initList();
headInsert(l, 1);
headInsert(l, 2);
headInsert(l, 3);
headInsert(l, 4);
tailInsert(l, 5);
tailInsert(l, 6);
delete(l, 4);
delete(l, 5);
printNode(l);
return 0;
}
3.双链表
组成:指向上一个节点的pre指针(指针域)+存放节点内容的data(数据域)+指向下一个节点的指针next(指针域),可以通过一个节点双向的找到下一个节点和上一个节点(所以叫双链表)
核心:头节点的pre指针,插入新节点时的pre指针与next指针的指向问题,插入新节点的后节点的pre指针的指向问题,链表为空时的插入,删除链表元素时的前后节点的两个指针的指向问题
实现:
/*1.初始化链表
2.插入节点(头插,尾插)
3.删除节点
4.遍历链表*/
#define TRUE 1
#define FALSE 0
#include<stdio.h>
#include<stdlib.h>
typedef struct Node
{
int data;
//相比单链表多了一个指向前的pre指针
struct Node* pre;
struct Node* next;
}Node;
Node* initList()
{
Node* headNode = (Node*)malloc(sizeof(Node));
headNode->data = 0;
headNode->next = NULL;
//头节点的pre指针指向NULL
headNode->pre = NULL;
return headNode;
}
//头插法
void headInsert(Node* headNode, int data)
{
Node* node = (Node*)malloc(sizeof(Node));
node->data = data;
if (headNode->data == 0)
{
//链表为空
//步骤 1.将新插入的节点的next指针指向为空(== headNode->next)
//2.将新节点的pre指针指向headNode
//3.将头节点的的next指针指向新节点
node->next = headNode->next;
node->pre = headNode;
headNode->next = node;
headNode->data++;
}
else {
//链表不为空
//要注意要插入位置的前节点的next指针和后节点的pre指针
//步骤:1.将新节点的next指针指向下一个节点(==node->next = headNode->next)
//2.将新节点的pre指针指向头节点(== node->pre = headNode)
//3.将头节点的next指针指向新节点(== headNode->next = node)
//4.将头节点的next指针所指向的pre指针指向新节点(== headNode->next->pre = node)
node->pre = headNode;
node->next = headNode->next;
headNode->next->pre = node;
headNode->next = node;
headNode->data++;
}
}
void tailInsert(Node* headNode, int data)
{
Node* node = headNode;
Node* n = (Node*)malloc(sizeof(Node));
n->data = data;
while (node->next)
{
node = node->next;
}
n->next = node->next;
node->next = n;
//将尾部插入的节点的pre指针指向之前的尾节点
n->pre = node;
headNode->data++;
}
int delete(Node* headNode, int data)
{
Node* node = headNode->next;
Node* n = headNode->next;
while (node)
{
if (node->data == data)
{
//找到要删除的节点后
//步骤:1.将要删除的节点的pre指针指向的next指针指向要删除的节点的下一个节点
//(== node->pre->next = node->next)
//2.将要删除的节点的next指针指向的pre指针指向要删除节点的pre指针
// (就是node的前一个节点)
//(== node->next->pre = node->next)
//3.将要删除的节点释放
node->pre->next = node->next;
node->next->pre = node->pre;
free(node);
return TRUE;
}
node = node->next;
}
return FALSE;
}
void printNode(Node* headNode)
{
Node* node = headNode;
while (node->next)
{
printf("%d->", node->data);
node = node->next;
}
printf("NULL\n");
}
int main()
{
Node* a = initList();
headInsert(a, 1);
headInsert(a, 2);
headInsert(a, 3);
headInsert(a, 4);
headInsert(a, 7);
tailInsert(a, 5);
tailInsert(a, 6);
delete(a, 3);
printNode(a);
return 0;
}
双向链表内容不为空时的插入
双向链表的删除
4.双循环链表
组成:指向上一个节点的pre指针(指针域)+存放节点内容的data(数据域)+指向下一个节点的指针next(指针域),可以通过一个节点双向的找到下一个节点和上一个节点,并且尾节点的next指针指向头节点,头节点的pre指针指向尾节点(所以叫双循环链表)
核心:头节点的pre指针的指向,尾节点的next的指向,头插与尾插时的两个指针的指向问题,删除链表元素时的两边元素的指针的指向
实现:
#include<stdio.h>
#include<stdlib.h>
#define TRUE 1
#define FALSE 0
typedef struct Node
{
int data;
struct Node* next;
struct Node* pre;
}Node;
Node* initList()
{
Node* headNode = (Node*)malloc(sizeof(Node));
headNode->data = 0;
//尾节点next指针指向头节点,形成循环
headNode->next = headNode;
//尾节点的pre指针指向头节点,形成循环
headNode->pre = headNode;
return headNode;
}
//头插法
void headInsert(Node* headNode, int data)
{
Node* node = (Node*)malloc(sizeof(Node));
node->data = data;
if (headNode->data == 0)
{
//链表为空
node->pre = headNode;
//在没有插入node时,headNode->next的指向就为headNode->pre
node->next = headNode->next;
headNode->next = node;
headNode->pre = node;
headNode->data++;
}
else
{
node->next = headNode->next;
node->pre = headNode;
headNode->next = node;
headNode->next->pre = node;
headNode->data++;
}
}
void del(Node* headNode, int data)
{
Node* curNode = headNode->next;
while (curNode) {
if (curNode->data == data) {
//删除节点
if (curNode->next != NULL) {
//不是最后一个节点
curNode->pre->next = curNode->next;
curNode->next->pre = curNode->pre;
free(curNode);
headNode->data--;
}
else {
//最后一个节点
curNode->pre->next = NULL;
free(curNode);
headNode->data--;
}
return TRUE;
}
curNode = curNode->next;
}
return FALSE;
}
void tailInsert(Node* headNode, int data)
{
Node* node = headNode;
while (node->next != headNode)
{
node = node->next;
}
Node* n = (Node*)malloc(sizeof(Node));
n->data = data;
n->pre = node;
n->next = headNode;
headNode->pre = n;
node->next = n;
headNode->data++;
}
void printNode(Node* headNode)
{
Node* head = headNode->next;
while (head->next != headNode)
{
printf("%d->", head->data);
head = head->next;
}
printf("NULL\n");
}
int main()
{
Node* l = initList();
headInsert(l, 1);
headInsert(l, 2);
headInsert(l, 3);
tailInsert(l, 4);
printNode(l);
return 0;
}