1.概念
逻辑结构:线性结构
存储结构:链式结构
链表又分为有头节点和无头节点的,每种又细分为单向的,循环的,双向的。
以单向链表为例。
有头节点单向链表示意图:
2.对链表的操作
1.创建链表节点 √
2.清空链表 √
3.销毁链表 √
4.向链表中插入元素(头插) √
5.向链表中插入元素(尾插) √
6.向链表中插入元素(任意位置插入) √
7.在链表中删除元素(头删) √
8.在链表中删除元素(尾删) √
9.在链表中删除元素(任意位置删除) √
10.修改链表中指定位置的元素 √
11.查找链表中指定位置的元素 √
12.两个链表的合并 √
13.链表的排序 √
14.链表的翻转 √
15.链表的剔重 √
16.遍历打印链表中所有元素----看现象用的 √
3.链表操作流程图
(1)链表插入节点流程图
(2)链表删除节点流程图
(3)两个链表合并的流程图
(4)链表翻转流程图
(5)链表排序流程图
也是采用冒泡排序的思想
(6)链表剔重流程图
4.代码实现
link_list.h
#ifndef __LINK_LIST_H__
#define __LINK_LIST_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//链表节点的结构体
typedef struct _Node{
int data; //数据域 此处以int为例 实际使用时用实际类型替换即可
struct _Node *next; //指针域 此处不能使用 node_t 因为还不认识呢
}node_t;
int create_node(node_t **p, int data);
int insert_list_by_head(node_t *phead, int data);
int print_list(node_t *phead);
int insert_list_by_tail(node_t *phead, int data);
int insert_list_by_pos(node_t *phead, int pos, int data);
int delete_list_by_head(node_t *phead);
int delete_list_by_tail(node_t *phead);
int delete_list_by_pos(node_t *phead, int pos);
int modify_list_by_pos(node_t *phead, int pos, int new_data);
int search_list_by_pos(node_t *phead, int pos, int *num);
int clean_list(node_t *phead);
int destroy_list(node_t **phead);
int merge_list(node_t *phead1, node_t **phead2);
int reverse_list(node_t *phead);
int sort_list(node_t *phead);
int tichong_list(node_t *phead);
#endif
link_list.c
#include "link_list.h"
//创建链表节点的函数
int create_node(node_t **p, int data){
if(NULL == p){
printf("入参为NULL\n");
return -1;
}
*p = (node_t *)malloc(sizeof(node_t));
if(NULL == *p){
printf("内存分配失败\n");
return -1;
}
//初始化新节点
(*p)->data = data;
(*p)->next = NULL;
return 0;
}
//向链表中插入元素(头插)
int insert_list_by_head(node_t *phead, int data){
if(NULL == phead){
printf("入参为NULL\n");
return -1;
}
node_t *pnew = NULL;
create_node(&pnew, data);
//执行头插操作
pnew->next = phead->next;
phead->next = pnew;
return 0;
}
//遍历链表
int print_list(node_t *phead){
if(NULL == phead){
printf("入参为NULL\n");
return -1;
}
node_t *ptemp = phead;//备份一下头结点
//防止函数内部后面使用时 找不到链表头了
while(NULL != ptemp->next){
ptemp = ptemp->next;
printf("%d ", ptemp->data);
}
printf("\n");
return 0;
}
//向链表中插入元素(尾插)
int insert_list_by_tail(node_t *phead, int data){
if(NULL == phead){
printf("入参为NULL\n");
return -1;
}
//先遍历链表 找到最后一个节点
node_t *ptemp = phead;
while(NULL != ptemp->next){
ptemp = ptemp->next;
}
node_t *pnew = NULL;
create_node(&pnew, data);
ptemp->next = pnew;
return 0;
}
//向链表中插入元素(任意位置插入)
int insert_list_by_pos(node_t *phead, int pos, int data){
if(NULL == phead){
printf("入参为NULL\n");
return -1;
}
if(pos < 0){
printf("插入位置不合理 插入失败\n");
return -1;
}
node_t *ptemp = phead;
int i = 0;
for(i = 0; i < pos; i++){
ptemp = ptemp->next;
if(NULL == ptemp){
break;
}
}
if(i < pos){
printf("插入位置不合理 插入失败\n");
return -1;
}
//执行插入操作
node_t *pnew = NULL;
create_node(&pnew, data);
pnew->next = ptemp->next;
ptemp->next = pnew;
return 0;
}
//在链表中删除元素(头删)
int delete_list_by_head(node_t *phead){
if(NULL == phead){
printf("入参为NULL\n");
return -1;
}
if(NULL == phead->next){
printf("链表为空 删除失败\n");
return -1;
}
node_t *pdel = phead->next;
#if 1
phead->next = phead->next->next;
#else
phead->next = pdel->next;
#endif
free(pdel);
pdel = NULL;
return 0;
}
//在链表中删除元素(尾删)
int delete_list_by_tail(node_t *phead){
if(NULL == phead){
printf("入参为NULL\n");
return -1;
}
if(NULL == phead->next){
printf("链表为空 删除失败\n");
return -1;
}
//遍历链表 找到倒数第二个数据节点
node_t *ptemp = phead;
while(NULL != ptemp->next->next){
ptemp = ptemp->next;
}
free(ptemp->next);
ptemp->next = NULL;
return 0;
}
//在链表中删除元素(任意位置删除)
int delete_list_by_pos(node_t *phead, int pos){
if(NULL == phead){
printf("入参为NULL\n");
return -1;
}
if(NULL == phead->next){
printf("链表为空 删除失败\n");
return -1;
}
if(pos < 0){
printf("删除位置不合理 删除失败\n");
return -1;
}
node_t *ptemp = phead;
int i = 0;
for(i = 0; i < pos; i++){
ptemp = ptemp->next;
if(NULL == ptemp->next){
break;
}
}
if(i < pos){
printf("删除位置不合理 删除失败\n");
return -1;
}
//执行删除操作
node_t *pdel = ptemp->next;
ptemp->next = pdel->next;
free(pdel);
pdel = NULL;
return 0;
}
//修改链表中指定位置的元素
int modify_list_by_pos(node_t *phead, int pos, int new_data){
if(NULL == phead){
printf("入参为NULL\n");
return -1;
}
if(NULL == phead->next){
printf("链表为空 修改失败\n");
return -1;
}
if(pos < 0){
printf("修改位置不合理 修改失败\n");
return -1;
}
node_t *ptemp = phead;
int i = 0;
for(i = 0; i < pos; i++){
ptemp = ptemp->next;
if(NULL == ptemp->next){
printf("修改位置不合理 修改失败\n");
return -1;
}
}
//执行修改操作
ptemp->next->data = new_data;
return 0;
}
//查找链表中指定位置的元素
int search_list_by_pos(node_t *phead, int pos, int *num){
if(NULL == phead || NULL == num){
printf("入参为NULL\n");
return -1;
}
if(NULL == phead->next){
printf("链表为空 没有数据节点\n");
return -1;
}
if(pos < 0){
printf("查找的位置没有数据\n");
return -1;
}
node_t *ptemp = phead;
int i = 0;
for(i = 0; i < pos; i++){
ptemp = ptemp->next;
if(NULL == ptemp->next){
printf("查找的位置没有数据\n");
return -1;
}
}
//执行查找操作
*num = ptemp->next->data;
return 0;
}
//清空链表
int clean_list(node_t *phead){
if(NULL == phead){
printf("入参为NULL\n");
return -1;
}
//循环头删
node_t *pdel = NULL;
while(NULL != phead->next){
pdel = phead->next;
phead->next = pdel->next;
free(pdel);
}
pdel = NULL;
return 0;
}
//销毁链表
int destroy_list(node_t **phead){
if(NULL == phead || NULL == *phead){
printf("入参为NULL\n");
return -1;
}
//为了防止内存泄漏 应该先清空再销毁
clean_list(*phead);
free(*phead);
*phead = NULL;
return 0;
}
//两个链表合并
int merge_list(node_t *phead1, node_t **phead2){
if(NULL == phead1 || NULL == phead2 || NULL == *phead2){
printf("入参为NULL\n");
return -1;
}
node_t *ptemp = phead1;
while(NULL != ptemp->next){
ptemp = ptemp->next;
}
ptemp->next = (*phead2)->next;
free(*phead2);
*phead2 = NULL;
return 0;
}
//链表的翻转
int reverse_list(node_t *phead){
if(NULL == phead){
printf("入参为NULL\n");
return -1;
}
if(NULL == phead->next){
printf("链表为空 无需翻转\n");
return -1;
}
if(NULL == phead->next->next){
printf("只有一个节点 无需翻转\n");
return -1;
}
node_t *p = phead->next;
node_t *q = p->next;
p->next = NULL;
while(NULL != p){
p = q->next;
q->next = phead->next;
phead->next = q;
q = p;
}
return 0;
}
//链表的排序 以升序为例
int sort_list(node_t *phead){
if(NULL == phead){
printf("入参为NULL\n");
return -1;
}
if(NULL == phead->next){
printf("链表为空 无需排序\n");
return -1;
}
if(NULL == phead->next->next){
printf("只有一个节点 无需排序\n");
return -1;
}
node_t *p = phead->next;
node_t *q = NULL;
int temp = 0;
while(NULL != p->next){
q = p->next;
while(NULL != q){
if(p->data > q->data){
temp = p->data;
p->data = q->data;
q->data = temp;
}
q = q->next;
}
p = p->next;
}
return 0;
}
//链表的剔重
int tichong_list(node_t *phead){
if(NULL == phead){
printf("入参为NULL\n");
return -1;
}
if(NULL == phead->next){
printf("链表为空 无需剔重\n");
return -1;
}
if(NULL == phead->next->next){
printf("只有一个节点 无需剔重\n");
return -1;
}
node_t *p = phead->next;
node_t *q = NULL;
node_t *m = NULL;//用来保存q的前一节点 删除q时使用
while(NULL != p){
m = p;
q = p->next;
while(NULL != q){
if(p->data == q->data){
m->next = q->next;
free(q);
q = m->next;
}else{
m = q;
q = q->next;
}
}
p = p->next;
}
return 0;
}
main.c 调试用的
#include "link_list.h"
int main(int argc, const char *argv[])
{
node_t *phead = NULL;
create_node(&phead, -1);
printf("phead = %p\n", phead);//非NULL
//测试头插
insert_list_by_head(phead, 10);
insert_list_by_head(phead, 20);
insert_list_by_head(phead, 30);
print_list(phead); // 30 20 10
//测试尾插
insert_list_by_tail(phead, 40);
insert_list_by_tail(phead, 50);
insert_list_by_tail(phead, 60);
print_list(phead); // 30 20 10 40 50 60
//测试任意位置插入
insert_list_by_pos(phead, 7, 100);//不合理
insert_list_by_pos(phead, 6, 100);
insert_list_by_pos(phead, 3, 200);
print_list(phead); // 30 20 10 200 40 50 60 100
//测试头删
delete_list_by_head(phead);
delete_list_by_head(phead);
print_list(phead); // 10 200 40 50 60 100
//测试尾删
delete_list_by_tail(phead);
delete_list_by_tail(phead);
print_list(phead); // 10 200 40 50
//测试任意位置删除
delete_list_by_pos(phead, 4);//不合理
delete_list_by_pos(phead, 3);
delete_list_by_pos(phead, 1);
print_list(phead); // 10 40
//测试修改
modify_list_by_pos(phead, 2, 20);//不合理
modify_list_by_pos(phead, 1, 20);
print_list(phead); // 10 20
//测试查找
int num = 0;
search_list_by_pos(phead, 2, &num);//不合理
search_list_by_pos(phead, 1, &num);
printf("num = %d\n", num); //20
//测试清空
clean_list(phead);
print_list(phead); // 没有元素了
//测试销毁
destroy_list(&phead);
printf("phead = %p\n", phead);//NULL
//测试合并
create_node(&phead, -1);
insert_list_by_tail(phead, 10);
insert_list_by_tail(phead, 20);
insert_list_by_tail(phead, 30);
node_t *phead2 = NULL;
create_node(&phead2, -1);
insert_list_by_tail(phead2, 40);
insert_list_by_tail(phead2, 50);
insert_list_by_tail(phead2, 60);
merge_list(phead, &phead2);
print_list(phead); // 10 20 30 40 50 60
printf("phead2 = %p\n", phead2);//NULL
//测试翻转
reverse_list(phead);
print_list(phead); // 60 50 40 30 20 10
//测试排序
sort_list(phead);
print_list(phead); // 10 20 30 40 50 60
//测试剔重
insert_list_by_pos(phead, 2, 10);
insert_list_by_pos(phead, 5, 10);
insert_list_by_pos(phead, 7, 20);
insert_list_by_tail(phead, 60);
insert_list_by_tail(phead, 60);
insert_list_by_tail(phead, 60);
print_list(phead); // 10 20 10 30 40 10 50 20 60 60 60 60
tichong_list(phead);
print_list(phead); // 10 20 30 40 50 60
destroy_list(&phead);
return 0;
}