C语言实现链表的基本操作(增删改查)
#include <>
#include <>
#include <>
#include <>
// 链表的节点必须包含两个信息“有效数据和指针”,也就是“数据域和指针域 ”
typedef struct Node {
//数据域
int data;
//指针域
struct Node *pNext;//链表中的指针,指向的是下一个节点的整体,所以指针类型必须和下一个节点类型相同
} *PNODE, NODE;
PNODE init_list(); // 初始化链表
void add_list(PNODE pHead,int val); // 给链表追加节点
void traverse_list(PNODE pHead); // 遍历输出链表
bool is_empty(PNODE pHead); // 判断链表是否为空
int length_list(PNODE pHead); // 获取链表长度
void sort_list(PNODE pHead); // 对链表排序
// 这里我使用的是下标index(从0开始),注意不是pos(从1开始)
bool insert_list(PNODE pHead,int index,int val);// 插入节点
bool delete_list(PNODE pHead,int index,int *val);// 删除节点
int main() {
PNODE pHead = init_list();
int i;
for(i = 0; i < 5; i++) {
add_list(pHead, pow(2,i));
}
traverse_list(pHead);
if(is_empty(pHead)) {
printf("链表为空\n");
} else {
printf("链表不为空\n");
}
printf("链表长度为:%d\n",length_list(pHead));
sort_list(pHead);
traverse_list(pHead);
insert_list(pHead,0,5);
printf("插入成功:");
traverse_list(pHead);
int val;
delete_list(pHead, 5, &val);
printf("删除的值为:%d\n", val);
traverse_list(pHead);
//pHead指向的内存是我在init_list函数中动态分配,执行完之后需要手动销毁
free(pHead);
return 0;
}
PNODE init_list() {
PNODE pHead = (PNODE) malloc(sizeof(NODE));
if(pHead == NULL) {
printf("内存分配失败\n");
exit(-1);
}
pHead->pNext = NULL;
return pHead;
}
void add_list(PNODE pHead,int val) {
// 1.新建一个节点
PNODE pNew = (PNODE) malloc(sizeof(NODE));
if(pNew == NULL) {
printf("内存分配失败\n");
exit(-1);
}
// 2.给新节点赋值
pNew->data = val;
pNew->pNext = NULL;
// 3.将pTail指向尾节点
PNODE pTail = pHead;
while(pTail->pNext != NULL) { // 当pTail指向的节点不为NULL,说明pTail指向的不是尾节点
pTail = pTail->pNext; // 进入循环说明pTail指向的还不是尾节点,所以将pTail指向下一个节点
}
// 4.最后将新建节点pNew挂载到尾节点之后
pTail->pNext = pNew;
}
void traverse_list(PNODE pHead) {
// 1.创建一个指针(pMOVE),指向首节点(pHead->pNext)
PNODE pMove = pHead->pNext;
int i;
// 2.如果pMove指向的节点不为空,则进入循环输出
while(pMove != NULL) {
printf("%d ", pMove->data);
//3.将 pMove 指向下一个节点
pMove = pMove->pNext;
}
printf("\n");
return;
}
bool is_empty(PNODE pHead) {
if(pHead->pNext == NULL) {
return true;
} else {
return false;
}
}
int length_list(PNODE pHead) {
PNODE pMove = pHead;
int len = 0;
while(pMove->pNext != NULL) {
pMove = pMove->pNext;
len++;
}
return len;
}
void sort_list(PNODE pHead) {
//这里使用的是选择排序,与数组的选择排序有点不同,因为链表不能记录最小值的下标,所以每轮比较会进行多次交换
int i,j,t;
int len = length_list(pHead);
PNODE p, q;
for(i = 0, p = pHead->pNext; i < len-1; i++) {
for(j = i+1,q = p->pNext; j < len; j++, q = q->pNext) {
if(p->data > q->data) {
t = p->data;
p->data = q->data;
q->data = t;
}
}
}
return;
}
bool insert_list(PNODE pHead,int index,int val) {
int i = 0;
PNODE p = pHead;
// 在下标index前插入节点,通过循环拿到下标index前面的节点,这样便于插入
while(p != NULL && i < index) {
p = p->pNext;
i++;
}
// 判断p是否指向 NULL,插入的下标位置index是否小于0
if(p == NULL || index < 0) {//老师这里用的是 i>pos所表达的意思就是 index<0,个人认为index<0更加便于理解
return false;
}
PNODE pNew = (PNODE) malloc(sizeof(NODE));
if(pNew == NULL) {
printf("内存分配失败\n");
exit(-1);
}
pNew->pNext = p->pNext;
pNew->data = val;
p->pNext = pNew;
return true;
}
bool delete_list(PNODE pHead,int index,int *val) {
int i = 0;
PNODE p = pHead;
// 这里删除,也是通过循环拿到“需要删除节点的前一个节点 ”
while(p->pNext != NULL && i < index) {
p = p->pNext;
i++;
}
if(NULL == p->pNext || index < 0){
return false;
}
*val = p->pNext->data;
// 删除 p 后面第一个节点,并让 p 指向后面的第二个节点
PNODE q = p->pNext;
// 判断后面的第二个节点是否存在,不存在直接赋值为NULL
p->pNext = p->pNext->pNext == NULL ? NULL : p->pNext->pNext;
free(q);
q = NULL;
return true;
}