文章目录
数据结构—P3线性单链表
简介
线性表
概念
线性结构中的数据元素之间是一对一的关系,线性表(List)表示零个或多个数据元素的有限序列
若将线性表记为(data(1)…data(n)),则表中的data(i-1)领先于data(i),称data(i-1)是data(i)的前驱元素,data(i)是data(i-1)的后继元素
线性表元素的个数n(n>0)定义为线性表的长度,当n=0时,称为空表
描述
线性表L可用二元组形式描述
L=(D,R)
D表示数据元素的集合
D={ai|i=0,1,2,…n}
R表示关系集合
R={<ai,ai+1>|0<=i<=n-2}
特征
1.对非空表,表头无前驱
2.对非空表,表尾无后继
3.其他的每个元素都有一个直接前驱和一个直接后继
链表
链表
以前在顺序结构中,每个数据元素只需要存数据元素信息就可以了;现在链式结构中,除了要存数据元素信息外,还要存储它的后继元素的存储地址
节点
为了表示每个数据元素ai与其直接后继数据元素ai+1之间的逻辑关系,对数据元素ai来说,除了存储其本身的信息之外,还需存储一个指示其直接后继的信息。我们把存储数据元素信息的域称为数据域,把存储直接后继位置称为指针域。指针域中存储的信息称做指针或链;这两部分信息组成数据元素ai的存储映像,称为结点(Node)
单链表
n个结点链结成一个链表,即为线性表的链式存储结构,因为此链表的每个结点中只包含指针域,所以叫做单链表
静态链表
首先我们让数组的元素都是由两个数据域组成,data和cur;用来存放数据元素,也就是通常我们要处理的数据;而游标cur相当于单链表中的next指针,存放该元素的后继在数组中的下标,我们把这种用数组描述的链表叫做静态链表
循环链表
将单链表中终端结点的指针端由空指针改为指向头结点,就使整个单链表形成一个环,这种头尾相接的单链表称为单循环链表,简称循环链表(circular linked list)
双向链表
双向链表(double linked list)是在单链表的每个结点中,再设置一个指向其前驱结点的指针域
实现
创建单链表结构体
创建文件编写程序
编写Makefile
test:test.o lklist.o
gcc -o test test.o lklist.o
test.o:test.c lklist.h
gcc -c test.c
lklist.o:lklist.c lklist.h
gcc -c lklist.c
.PHONY:clean
clean:
rm *.o
创建结构体
//宏定义int的别名为data_t
typedef int data_t;
//宏定义单链表节点和节点指正为listnode和*lklist
typedef struct node{
data_t data;
struct node *next;
}listnode, *lklist;
创建表函数
编写lklist.h
编写lklist.c
//创建表
lklist lklist_create(){
//分配内存空间
lklist H;
H = (lklist)malloc(sizeof(listnode));
if(H == NULL){
printf("malloc is failed\n");
return H;
}
//初始化
H->data = 0;
H->next = NULL;
//返回表
return H;
}
编写test.c
销毁表函数
编写lklist.h
编写lklist.c
//释放表
lklist lklist_free(lklist H){
//判断头节点是否为空
lklist p;
if(H == NULL){
return NULL;
}
//依次释放节点空间
p = H;
while(H != NULL){
p = H;
free(p);
H = H->next;
}
return NULL;
}
编写test.c
表尾插入函数
编写lklist.h
编写lklist.c
//在表尾插入内容
int lklist_downinsert(lklist H,data_t value){
lklist p,q;
//判断头节点是否为空
if(H == NULL){
printf("H is NULL\n");
return -1;
}
//创建插入的新节点
if((p = (lklist)malloc(sizeof(listnode))) == NULL){
printf("malloc is failed\n");
return -1;
}
//给新节点初始化内容
p->data = value;
p->next = NULL;
//判断是否找到尾节点
q = H;
while(q->next != NULL){
q = q->next;
}
//尾节点指向新创建的节点,新创建的节点成为尾节点
q->next = p;
return 0;
}
编写test.c
查询显示表函数
编写lklist.h
编写lklist.c
//查询并显示所有内容
int lklist_show(lklist H){
lklist p;
//判断头节点是否为空
if(H == NULL){
printf("H is NULL\n");
return -1;
}
//依次输出节点内容
p = H;
while(p->next != NULL){
printf("%d ",p->next->data);
p = p->next;
}
printf("\n");
return 0;
}
编写test.c
测试程序
优化
插入操作
表头插入
编写lklist.h
编写lklist.c
//在表头插入内容
int lklist_topinsert(lklist H,data_t value){
lklist p,q;
//判断头节点是否为空
if(H == NULL){
printf("H is NULL\n");
return -1;
}
//创建插入的新节点
if((p = (lklist)malloc(sizeof(listnode))) == NULL){
printf("malloc is failed\n");
return -1;
}
//给新节点初始化内容
p->data = value;
p->next = NULL;
q = H;
p->next = q->next;
q->next = p;
return 0;
}
编写test.c
测试程序
指定位置插入
编写lklist.h
编写lklist.c
//指定位置插入内容
int lklist_insert(lklist H,data_t value,int pos){
lklist p,q;
int i = -1;
//判断头节点是否为空
if(H == NULL){
printf("H is NULL\n");
return -1;
}
if(pos < 0){
printf("pos is invalid\n");
return -1;
}
//创建插入的新节点
if((p = (lklist)malloc(sizeof(listnode))) == NULL){
printf("malloc is failed\n");
return -1;
}
//给新节点初始化内容
p->data = value;
p->next = NULL;
q = H;
while(i < pos-1){
q = q->next;
if(q == NULL){
printf("pos is invalid\n");
return -1;
}
i++;
}
p->next = q->next;
q->next = p;
return 0;
}
编写test.c
测试程序
初始化创建
编写lklist.h
编写lklist.c
//初始化创建
lklist lklist_initcreate(){
//分配内存空间
lklist H,p,q;
int value;
H = (lklist)malloc(sizeof(listnode));
if(H == NULL){
printf("malloc is failed\n");
return H;
}
//初始化
H->data = 0;
H->next = NULL;
printf("输入内容(-1结束输入):\n");
while(1){
printf("->:");
scanf("%d",&value);
if(value == -1){
break;
}else if((p = (lklist)malloc(sizeof(listnode))) == NULL){
printf("malloc is failed\n");
return H;
}
//给新节点初始化内容
p->data = value;
p->next = NULL;
//判断是否找到尾节点
q = H;
while(q->next != NULL){
q = q->next;
}
//尾节点指向新创建的节点,新创建的节点成为尾节点
q->next = p;
}
return H;
}
编写test.c
测试程序
查询操作
指定位置查询内容
编写lklist.h
编写lklist.c
//查询指定位置内容
int lklist_poslocate(lklist H,int pos){
lklist p;
int i = -1;
//判断头节点是否为空
if(H == NULL){
printf("H is NULL\n");
return -1;
}
p = H;
while(i < pos){
p = p->next;
if(p == NULL){
printf("pos is invalid\n");
return -1;
}
i++;
}
return p->data;
}
编写test.c
测试程序
指定内容查询位置
编写lklist.h
编写lklist.c
//查询指定内容位置
int lklist_valuelocate(lklist H,data_t value){
lklist p;
int i = -1;
//判断头节点是否为空
if(H == NULL){
printf("H is NULL\n");
return -1;
}
p = H;
while(1){
p = p->next;
if(p->data == value){
break;
}
if(p == NULL){
printf("pos is invalid\n");
return -1;
}
i++;
}
return i+1;
}
编写test.c
测试程序
删除操作
删除指定位置内容
编写lklist.h
编写lklist.c
//删除指定位置内容
int lklist_posdelete(lklist H,int pos){
lklist p,q;
int i = -1;
//判断头节点是否为空
if(H == NULL){
printf("H is NULL\n");
return -1;
}
if(pos < 0){
printf("pos is invalid\n");
return -1;
}
q = H;
while(i < pos-1){
q = q->next;
if(q == NULL){
printf("pos is invalid\n");
return -1;
}
i++;
}
p = q->next;
q->next = p->next;
free(p);
q = NULL;
return 0;
}
编写test.c
测试程序
删除指定内容
编写lklist.h
编写lklist.c
//删除指定内容
int lklist_valuedelete(lklist H,data_t value){
int pos;
pos = lklist_valuelocate(H,value);
lklist_posdelete(H,pos);
return 0;
}
编写test.c
测试程序
修改操作
修改指定位置内容
编写lklist.h
编写lklist.c
//修改指定位置内容
int lklist_posmodify(lklist H,int pos,data_t value){
lklist_posdelete(H,pos);
lklist_insert(H,value,pos);
return 0;
}
编写test.c
测试程序
修改指定内容为指定内容
编写lklist.h
编写lklist.c
//修改指定内容为指定内容
int lklist_valuemodify(lklist H,data_t rvalue,data_t value){
int pos;
pos = lklist_valuelocate(H,rvalue);
lklist_posmodify(H,pos,value);
return 0;
}
编写test.c
测试程序
扩展
排序(从大到小)
编写lklist.h
编写lklist.c
//对表进行排序,从大到小
int lklist_sortmax(lklist H){
lklist p,q;
int s;
p = H;
if(H == NULL){
printf("H is NULL\n");
return -1;
}
if(H->next == NULL){
printf("H is only one \n");
return -1;
}
p = p->next;
while(p->next != NULL){
q = p->next;
while(q != NULL){
if(q->data > p->data){
s = p->data;
p->data = q->data;
q->data = s;
}
q = q->next;
}
p = p->next;
}
return 0;
}
编写test.c
测试程序
表倒置
编写lklist.h
编写lklist.c
//对表进行倒置
int lklist_reverse(lklist H){
lklist p,q;
if(H == NULL){
printf("H is NULL\n");
return -1;
}
if(H->next == NULL || H->next->next == NULL){
return 0;
}
p = H->next->next;
H->next->next = NULL;
while(p != NULL){
q = p;
p = p->next;
q->next = H->next;
H->next = q;
}
return 0;
}
编写test.c
测试程序
排序(从小到大)
编写lklist.h
编写lklist.c
//对表进行排序,从小到大
int lklist_sortmin(lklist H){
lklist_sortmax(H);
lklist_reverse(H);
}
编写test.c
测试程序
整体代码
Makefile
test:test.o lklist.o
gcc -o test test.o lklist.o
test.o:test.c lklist.h
gcc -c test.c
lklist.o:lklist.c lklist.h
gcc -c lklist.c
.PHONY:clean
clean:
rm *.o
lklist.h
#ifndef __LKLIST_H__
#define __LKLIST_H__
//宏定义int的别名为data_t
typedef int data_t;
//宏定义单链表节点和节点指正为listnode和*lklist
typedef struct node{
data_t data;
struct node *next;
}listnode, *lklist;
//创建和删除操作
lklist lklist_create();//创建表
lklist lklist_free(lklist H);//释放表
lklist lklist_initcreate();//初始化创建
int lklist_posdelete(lklist H,int pos);//删除指定位置内容
int lklist_valuedelete(lklist H,data_t value);//删除指定内容
//插入操作
int lklist_downinsert(lklist H,data_t value);//在表尾插入内容
int lklist_topinsert(lklist H,data_t value);//在表头插入内容
int lklist_insert(lklist H,data_t value,int pos);//指定位置插入内容
//查询操作
int lklist_show(lklist H);//查询并显示所有内容
int lklist_poslocate(lklist H,int pos);//查询指定位置内容
int lklist_valuelocate(lklist H,data_t value);//查询指定内容位置
//修改操作
int lklist_posmodify(lklist H,int pos,data_t value);//修改指定位置内容
int lklist_valuemodify(lklist H,data_t rvalue,data_t value);//修改指定内容为指定内容
//排序操作
int lklist_sortmax(lklist H);//对表进行排序,从大到小
int lklist_sortmin(lklist H);//对表进行排序,从小到大
int lklist_reverse(lklist H);//对表进行倒置
#endif
lklist.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lklist.h"
/*-------------------------创建与删除--------------------------------*/
//创建表
lklist lklist_create(){
//分配内存空间
lklist H;
H = (lklist)malloc(sizeof(listnode));
if(H == NULL){
printf("malloc is failed\n");
return H;
}
//初始化
H->data = 0;
H->next = NULL;
//返回表
return H;
}
//初始化创建
lklist lklist_initcreate(){
//分配内存空间
lklist H,p,q;
int value;
H = (lklist)malloc(sizeof(listnode));
if(H == NULL){
printf("malloc is failed\n");
return H;
}
//初始化
H->data = 0;
H->next = NULL;
printf("输入内容(-1结束输入):\n");
while(1){
printf("->:");
scanf("%d",&value);
if(value == -1){
break;
}else if((p = (lklist)malloc(sizeof(listnode))) == NULL){
printf("malloc is failed\n");
return H;
}
//给新节点初始化内容
p->data = value;
p->next = NULL;
//判断是否找到尾节点
q = H;
while(q->next != NULL){
q = q->next;
}
//尾节点指向新创建的节点,新创建的节点成为尾节点
q->next = p;
}
return H;
}
//释放表
lklist lklist_free(lklist H){
//判断头节点是否为空
lklist p;
if(H == NULL){
return NULL;
}
//依次释放节点空间
p = H;
while(H != NULL){
p = H;
free(p);
H = H->next;
}
return NULL;
}
//删除指定位置内容
int lklist_posdelete(lklist H,int pos){
lklist p,q;
int i = -1;
//判断头节点是否为空
if(H == NULL){
printf("H is NULL\n");
return -1;
}
if(pos < 0){
printf("pos is invalid\n");
return -1;
}
q = H;
while(i < pos-1){
q = q->next;
if(q == NULL){
printf("pos is invalid\n");
return -1;
}
i++;
}
p = q->next;
q->next = p->next;
free(p);
q = NULL;
return 0;
}
//删除指定内容
int lklist_valuedelete(lklist H,data_t value){
int pos;
pos = lklist_valuelocate(H,value);
lklist_posdelete(H,pos);
return 0;
}
/*-------------------------查询操作--------------------------------*/
//查询并显示所有内容
int lklist_show(lklist H){
lklist p;
//判断头节点是否为空
if(H == NULL){
printf("H is NULL\n");
return -1;
}
//依次输出节点内容
p = H;
while(p->next != NULL){
printf("%d ",p->next->data);
p = p->next;
}
printf("\n");
return 0;
}
//查询指定位置内容
int lklist_poslocate(lklist H,int pos){
lklist p;
int i = -1;
//判断头节点是否为空
if(H == NULL){
printf("H is NULL\n");
return -1;
}
p = H;
while(i < pos){
p = p->next;
if(p == NULL){
printf("pos is invalid\n");
return -1;
}
i++;
}
return p->data;
}
//查询指定内容位置
int lklist_valuelocate(lklist H,data_t value){
lklist p;
int i = -1;
//判断头节点是否为空
if(H == NULL){
printf("H is NULL\n");
return -1;
}
p = H;
while(1){
p = p->next;
if(p->data == value){
break;
}
if(p == NULL){
printf("pos is invalid\n");
return -1;
}
i++;
}
return i+1;
}
/*-------------------------插入操作--------------------------------*/
//在表尾插入内容
int lklist_downinsert(lklist H,data_t value){
lklist p,q;
//判断头节点是否为空
if(H == NULL){
printf("H is NULL\n");
return -1;
}
//创建插入的新节点
if((p = (lklist)malloc(sizeof(listnode))) == NULL){
printf("malloc is failed\n");
return -1;
}
//给新节点初始化内容
p->data = value;
p->next = NULL;
//判断是否找到尾节点
q = H;
while(q->next != NULL){
q = q->next;
}
//尾节点指向新创建的节点,新创建的节点成为尾节点
q->next = p;
return 0;
}
//在表头插入内容
int lklist_topinsert(lklist H,data_t value){
lklist p,q;
//判断头节点是否为空
if(H == NULL){
printf("H is NULL\n");
return -1;
}
//创建插入的新节点
if((p = (lklist)malloc(sizeof(listnode))) == NULL){
printf("malloc is failed\n");
return -1;
}
//给新节点初始化内容
p->data = value;
p->next = NULL;
q = H;
p->next = q->next;
q->next = p;
return 0;
}
//指定位置插入内容
int lklist_insert(lklist H,data_t value,int pos){
lklist p,q;
int i = -1;
//判断头节点是否为空
if(H == NULL){
printf("H is NULL\n");
return -1;
}
if(pos < 0){
printf("pos is invalid\n");
return -1;
}
//创建插入的新节点
if((p = (lklist)malloc(sizeof(listnode))) == NULL){
printf("malloc is failed\n");
return -1;
}
//给新节点初始化内容
p->data = value;
p->next = NULL;
q = H;
while(i < pos-1){
q = q->next;
if(q == NULL){
printf("pos is invalid\n");
return -1;
}
i++;
}
p->next = q->next;
q->next = p;
return 0;
}
/*-------------------------修改操作--------------------------------*/
//修改指定位置内容
int lklist_posmodify(lklist H,int pos,data_t value){
lklist_posdelete(H,pos);
lklist_insert(H,value,pos);
return 0;
}
//修改指定内容为指定内容
int lklist_valuemodify(lklist H,data_t rvalue,data_t value){
int pos;
pos = lklist_valuelocate(H,rvalue);
lklist_posmodify(H,pos,value);
return 0;
}
/*-------------------------排序操作--------------------------------*/
//对表进行排序,从大到小
int lklist_sortmax(lklist H){
lklist p,q;
int s;
p = H;
if(H == NULL){
printf("H is NULL\n");
return -1;
}
if(H->next == NULL){
printf("H is only one \n");
return -1;
}
p = p->next;
while(p->next != NULL){
q = p->next;
while(q != NULL){
if(q->data > p->data){
s = p->data;
p->data = q->data;
q->data = s;
}
q = q->next;
}
p = p->next;
}
return 0;
}
//对表进行排序,从小到大
int lklist_sortmin(lklist H){
lklist_sortmax(H);
lklist_reverse(H);
}
//对表进行倒置
int lklist_reverse(lklist H){
lklist p,q;
if(H == NULL){
printf("H is NULL\n");
return -1;
}
if(H->next == NULL || H->next->next == NULL){
return 0;
}
p = H->next->next;
H->next->next = NULL;
while(p != NULL){
q = p;
p = p->next;
q->next = H->next;
H->next = q;
}
return 0;
}
test.c
#include <stdio.h>
#include "lklist.h"
//插入测试函数
int insert_test(){
//创建表
lklist H;
H = lklist_create();
//表尾插入内容
lklist_downinsert(H,5);
lklist_downinsert(H,6);
//显示表所有内容
lklist_show(H);
//表头插入内容
lklist_topinsert(H,4);
lklist_topinsert(H,2);
//显示所有内容
lklist_show(H);
//指定位置插入内容
lklist_insert(H,1,0);
lklist_insert(H,3,2);
//显示表所有内容
lklist_show(H);
//释放表
lklist_free(H);
}
//初始化创建测试函数
int initcreate_test(){
//创建表
lklist H;
H = lklist_initcreate();
//显示表所有内容
lklist_show(H);
//释放表
lklist_free(H);
}
//删除测试函数
int delete_test(){
//创建表
lklist H;
H = lklist_initcreate();
//显示表所有内容
lklist_show(H);
lklist_posdelete(H,2);
lklist_show(H);
lklist_valuedelete(H,5);
lklist_show(H);
//释放表
lklist_free(H);
}
//定位测试函数
int locate_test(){
//创建表
lklist H;
H = lklist_initcreate();
//显示表所有内容
lklist_show(H);
//显示指定位置内容
printf("%d\n",lklist_poslocate(H,2));
//显示指定内容位置
printf("%d\n",lklist_valuelocate(H,3));
//释放表
lklist_free(H);
}
//修改测试函数
int modify_test(){
lklist H;
H = lklist_initcreate();
lklist_show(H);
lklist_posmodify(H,2,99);
lklist_show(H);
lklist_valuemodify(H,5,55);
lklist_show(H);
lklist_free(H);
}
//排序测试函数
int sort_test(){
lklist H;
H = lklist_initcreate();
lklist_show(H);
lklist_reverse(H);
lklist_show(H);
lklist_sortmax(H);
lklist_show(H);
lklist_sortmin(H);
lklist_show(H);
lklist_free(H);
}
//主函数
int main(int argc, const char *argv[])
{
int chn,n = 1;
while(n){
printf("选择测试程序\n");
printf("0.退出1.插入操作2.初始化创建3.删除操作4.查询操作5.修改操作6.排序操作:");
scanf("%d",&chn);
switch(chn){
case 0:n = 0;break;
case 1:insert_test();break;
case 2:initcreate_test();break;
case 3:delete_test();break;
case 4:locate_test();break;
case 5:modify_test();break;
case 6:sort_test();break;
default:printf("不在输入范围内请重新输入!\n");
}
}
return 0;
}