单链表
链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。
“结点的序列”表示线性表称作线性链表(单链表),单链表是链式存取的结构。
链接存储方法
链接方式存储的线性表简称为链表(Linked List)。
链表的具体存储表示为:
① 用一组任意的存储单元来存放线性表的结点(这组存储单元既可以是连续的,也可以是不连续的)
② 链表中结点的逻辑次序和物理次序不一定相同。为了能正确表示结点间的逻辑关系,在存储每个结点值的同时,还必须存储指示其后继结点的地址(或位置)信息(称为指针(pointer)或链(link))
链式存储是最常用的存储方式之一,它不仅可用来表示线性表,而且可用来表示各种非线性的数据结构。
结点结构
data域--存放结点值的数据域
next域--存放结点的直接后继的地址(位置)的指针域(链域)
链表通过每个结点的链域将线性表的n个结点按其逻辑顺序链接在一起的,每个结点只有一个链域的链表称为单链表(Single Linked List)。
头指针head和终端结点
单链表中每个结点的存储地址是存放在其前趋结点next域中,而开始结点无前趋,故应设头指针head指向开始结点。链表由头指针唯一确定,单链表可以用头指针的名字来命名。
终端结点无后继,故终端结点的指针域为空,即NULL。
上代码
头文件定义
#ifndef __FY_LINKLIST_H
#define __FY_LINKLIST_H
//数据类型定义
typedef int data_t;
//结点结构体定义
typedef struct node{
data_t data;
struct node *next;
}listnode,*linklist;
//创建一个表
linklist list_creat(void);
//表尾插入一个元素
int list_tail_insert(linklist H,data_t data);
//获取表中某个结点
listnode* list_get(linklist H,int pos);
//在指定位置插入一个元素
int list_insert(linklist H,data_t data,int post);
//遍历表
int list_show(linklist H);
#endif
C文件
#include "linklist.h"
#include "stdio.h"
#include "stdlib.h"
//创建一个结点
listnode *creatNode(data_t data){
listnode *newnode = (listnode *)malloc(sizeof(listnode));
if(newnode==NULL){
printf("创建结点失败!\n");
return NULL;
}
newnode->data = data;
newnode->next = NULL;
return newnode;
}
//创建一个表
linklist list_creat(void){
linklist H = (linklist)malloc(sizeof(listnode));
if(H==NULL){
printf("创建链表失败!\n");
return NULL;
}
H->data = 0;
H->next = NULL;
return H;
}
//表尾插入一个元素
int list_tail_insert(linklist H,data_t data){
if(H == NULL) {
printf("链表不存在!\n");
return -1;
}
listnode *newnode = creatNode(data);
if(newnode == NULL) return -1;
listnode *p = H;
while(p->next != NULL){
p = p->next;
}
p->next = newnode;
return 0;
}
//获取表中某个结点的地址
/*
定义:
头结点的位置是-1
结点的位置是从0开始的,
*/
listnode * list_get(linklist H,int pos){
int i;
listnode *p;
//防御性编程
if(H==NULL){
printf("链表不存在!\n");
return NULL;
}
if(pos<-1) {
printf("获取节点失败,位置无效!\n");
return NULL;
}
if(H->next == NULL){
printf("获取结点失败,链表为空!\n");
}
p = H;//指向头结点,位置为-1
for(i=-1;i<pos;i++){
if(p->next == NULL){
printf("获取结点失败,结点位置不存在!\n");
return NULL;
}
p = p->next;
}
return p;
}
//在指定位置插入一个元素
int list_insert(linklist H,data_t data,int post){
if(H==NULL){
printf("插入结点失败,链表不存在!\n");
return -1;
}
//获取结点位置的上一个结点
listnode *lastnode = list_get(H,post-1);
if(lastnode == NULL) {
printf("插入结点失败,位置不合法!\n");
return -1;
}
//为该元素创建一个结点
listnode *newnode = creatNode(data);
newnode->next = lastnode->next;
lastnode->next = newnode;
return 0;
}
//遍历表
int list_show(linklist H){
if(H == NULL){
printf("遍历链表失败,链表不存在!\n");
return -1;
}
listnode *p = H;
while(p->next !=NULL){
p = p->next;
printf("%d ",p->data);
}printf("\n");
return 0;
}
测试的main文件
#include "stdio.h"
#include "stdlib.h"
#include "linklist.h"
int main(void){
data_t value;
//创建一个空链表
linklist H = list_creat();
//初始化插入几个数据
list_tail_insert(H,1);
list_tail_insert(H,3);
list_tail_insert(H,5);
list_tail_insert(H,7);
printf("初始链表数据为:\n");
list_show(H);
printf("\n***********尾插法插入元素测试***********\n");
while(1){
printf("请输入一个数据,输入-1为结束测试!\n");
scanf("%d",&value);
if(value == -1) break;
list_tail_insert(H,value);
printf("插入新数据后的链表元素为:\n");
list_show(H);
}
printf("\n***********查找指定位置元素测试**********\n");
while(1){
printf("请输入一个位置,输入-1为结束测试!\n");
scanf("%d",&value);
if(value == -1) break;
listnode *p = list_get(H,value);
if(p!=NULL){
printf("该位置的元素数据为:%d\n",p->data);
}
}
printf("\n***********指定位置插入元素测试**********\n");
while(1){
int pos;
data_t data;
int res;
printf("请输入要插入的位置及要插入的数据:如2 3代表在第二个位置插入数据3\n输入-1 -1为结束测试!\n");
scanf("%d %d",&pos,&data);
if(pos == -1 && data == -1) break;
res = list_insert(H,data,pos);
if(res == 0){
printf("在指定位置插入元素成功,插入后的链表为:\n");
list_show(H);
}
}
list_show(H);
return 0;
}
测试运行结果如下:
By Urien 2021年2月2日 23:03:57