数据结构——单链表
来源:互联网 发布:java接口有哪些 编辑:程序博客网 时间:2024/06/13 18:28
1. 相关概念
1. 1 单链表定义
单链表是线性表链式存储的一种,其储存不连续。单链表的数据结构中包含两个变量:结点数据data和指向下一结点的指针next。一个结点只知道下一个结点的地址。
注:一个单链表必须有一个头指针,指向单链表中的第一个结点。否则链表会在内存中丢失。
1. 2 关于头指针
链表中第一个结点的存储位置叫做头指针,那么整个链表的存取就必须是从头指针开始进行了。之后的每一个结点,其实就是上一个的后继指针指向的位置。无论链表是否为空,头指针均不为空。头指针是链表的必要元素。
若链表有头结点,则头指针就是指向链表头结点的指针。如下图所示:
1. 3 关于头结点
为什么要设置头结点呢?
头指针具有标识作用,故常用头指针冠以链表的名字。
有了头结点后,对在第一个元素结点前插入结点和删除第一个结点,其操作与对其它结点的操作统一了。
注:下面的程序均指带有头结点的单链表。
1.4 结点定义
typedef int datatype;typedef struct LNode{ datatype data; /*结点数据*/ struct LNode *next; /*下一结点的指针*/}LNode;typedef struct LNode *LinkList;
2. 链表的基本操作
2.1 ADT 单链表(List)
void InitList( LinkList *L ); //初始化空表void HeadCreatList(LinkList L); //头插法创建链表void RearCreatList( LinkList L ); //尾插法创建链表void PrintList(LinkList L); //遍历链表void HeadInsert( LinkList L, int e ); //头插法void TailInsert( LinkList L, int e ); //尾插法BOOL ListInsert( LinkList L, int i, int e ); //固定位置插入BOOL ListSearch( LinkList L, int i, int *e ); //固定位置寻找BOOL DeleteList( LinkList L, int i , int *e ); //固定位置删除元素int ListLength( LinkList L ); //链表长度BOOL DestroyList( LinkList *L ); //销毁链表BOOL IsListEmpty( LinkList L ); //链表是否为空
2 .2 相关实现
相关宏定义
#define OVERFLOW -2#define OK 1#define ERROR 0
2.2.1 单链表的初始化
void InitList( LinkList *L) /* 这里的输入参数为头指针的地址,因为该函数是要对头指针进行分配地址,所以需要将头指针的地址输入,类似函数的传址*/{ /*申请一个头节点,L为指向头结点的头指针*/ *L = ( LinkList ) malloc ( sizeof(LNode) ); if( !*L ) { printf("单链表创建失败!\n"); exit( OVERFLOW ); /*#define OVERFLOW -2*/ } (*L) -> next = NULL; /*将头结点的next指针设置为NULL,表明表为空*/}
2.2.2 单链表的整表创建
void CreatList( LinkList L ) /*函数的输入即为链表的头指针L*/{ int d= 0; LinkList p, q; q = L; while( scanf( "%d" , &d) != EOF ) /*从终端读取数据,遇到ctrl+d结束*/ { p = ( LinkList ) malloc ( sizeof(LNode) ); /*申请一个新的结点*/ if( !p ) exit( OVERFLOW ); p -> data = d; /*给新结点赋值*/ q -> next = p; /*修改指针,将上一个结点的next设置为当前结点*/ q = p; /*将当前结点设置为上一结点*/ } q -> next = NULL; /*将最后一个结点的next设置为NULL,表示表尾*/}
2.2.3 单链表的打印
void PrintList( LinkList L ) /*函数输入为链表的头指针*/{ LinkList p; p = L -> next; /*L是头指针,L->next是指向第一个结点的地址*/ while( p != NULL ) /*没有访问到表尾*/ { printf( "%d" , p -> data ); /*打印当前结点p的数据*/ p = p -> next; /*访问下一个结点*/ } return OK;}
2.2.4 单链表的头插法
方法如下图所示:
void HeadInsert( LinkList L, int e )/*不改变头指针,所以函数的输入为单链表的头指针L, e为待插入的元素*/{ LinkList s, q; s = ( LinkList )malloc( sizeof(LNode)); /*申请新结点s*/ if( !s ) exit( OVERFLOW ); s -> data = e; /*将e写入新结点*/ q = L -> next; /*指针修改*/ L -> next = s; s -> next = q; return OK;}
2.2.5 单链表的尾插法
方法如下图所示:
int TailInsert( LinkList L, int e )/*不改变头指针,所以函数的输入为单链表的头指针L, e为待插入的元素*/{ LinkList p, s; p = L; while( p->next ) /*判断是否到表尾*/ { p = p -> next; } s = ( LinkList )malloc( sizeof(LNode)); /*申请新结点s*/ if( !s ) exit( OVERFLOW ); s -> data = e; /*将e写入新结点*/ p -> next = s; /*将原表尾的指针指向新结点*/ return OK;}
2.2.6 单链表的固定位置插入
方法如下图所示:
int ListInsert( LinkList L, int i, int e )/*不改变头指针,所以函数的输入为单链表的头指针L, i为插入的位置, e为待插入的元素*/{ int j = 1; LinkList p, s; p = L; while( p && j < i) /*定位到第i-1个位置*/ { p = p -> next; j++; } if( !p || j > i ) return ERROR; s = ( LinkList )malloc( sizeof(LNode)); /*申请新结点s*/ if( !s ) exit( OVERFLOW ); s -> data = e; /*将e写入新结点*/ s -> next = p -> next; /*调整指针*/ p -> next = s; return OK;}
2.2.7 单链表的固定位置删除
方法如下图所示:
void DeleteList( LinkList L, int i , int *e ) /*不改变L,i代表位置,*e代表删除的数据*/{ int j = 1; LinkList p, q; p = L -> next; /*p指向第一个结点*/ while( p && j < i - 1 ) /*将p指向第i-1个结点*/ { p = p -> next; j++; } if( p || j > i) /*i的位置错误*/ return ERROR; q = p -> next; /*q指向第i个顶点*/ p -> next = q -> next; *e = q -> data; free(q);}
2.2.8 单链表的固定位置查找
int ListSearch( LinkList L, int i, int *e )/*不改变头指针,所以函数的输入为单链表的头指针L, i为查找的位置, *e为待查找位置的元素*/{ int j = 1; LinkList p = L -> next; /*p指向第一个结点*/ while( p && j < i) /*定位到第i个位置*/ { p = p -> next; j++; } if( !p || j > i ){ /*i的位置输入错误*/ printf("查找的位置错误!\n"); return ERROR; } *e = p -> data; return OK;}
2.2.9 单链表的空判断
int IsListEmpty( LinkList L ){ return L-> next == NULL;}
2.2.10 单链表的长度
int ListLength( LinkList L ){ int count = 0; LinkList p = L -> next; /*p指向第一个结点*/ while( p ) { /*遍历直到表尾*/ count++; /*每遍历一个结点,计数+1*/ p = p -> next; } return count;}
2.2.11 单链表的清空
void ClearList( LinkList L ){ LinkList p, q; p = L ->next; /*p指向第一个结点*/ while( p ) /*没到表尾*/ { q = p -> next; free( p ); /*保存当前结点的下一节点地址,释放当前结点地址的内存*/ p = q; } L -> next = NULL; /*将头指针的next设置为NULL*/}
2.2.12 单链表的整表销毁
void DestroyList( LinkList *L ) /*为什么输入的不是头指针L,而是头指针的地址呢? */{ LinkList p; if( NULL == *L ) /*单链表不存在*/ return ERROR; while( *L ) { p = *L -> next; free( *L ); *L = p; }}
3 完整的测试程序
#include <stdio.h>#include <stdlib.h>#define OVERFLOW -2#define OK 1#define ERROR 0#define BOOL inttypedef int datatype;typedef struct LNode { datatype data; /*结点数据*/ struct LNode *next; /*下一结点的指针*/}LNode;typedef struct LNode *LinkList;void InitList( LinkList *L ); //初始化空表void HeadCreatList(LinkList L); //头插法创建链表void RearCreatList( LinkList L ); //尾插法创建链表void PrintList(LinkList L); //遍历链表void HeadInsert( LinkList L, int e ); //头插法void TailInsert( LinkList L, int e ); //尾插法BOOL ListInsert( LinkList L, int i, int e ); //固定位置插入BOOL ListSearch( LinkList L, int i, int *e ); //固定位置寻找BOOL DeleteList( LinkList L, int i , int *e ); //固定位置删除元素int ListLength( LinkList L ); //链表长度BOOL DestroyList( LinkList *L ); //销毁链表BOOL IsListEmpty( LinkList L ); //链表是否为空int main(){ LinkList L; /*L为头指针,单链表带头结点*/ /*初始化空表*/ InitList(&L); if( !IsListEmpty( L ) ){ printf("单链表非空,初始化错误!"); return ERROR; } else printf("单链表初始化完成!\n输入你保存到链表中的数据:\n"); RearCreatList(L); //尾插法创建链表 PrintList(L); //打印 printf("\n"); /*插入操作*/ HeadInsert( L, 5 ); //头插法 HeadInsert( L, 6 ); HeadInsert( L, 11 ); PrintList(L); printf("\n"); TailInsert( L, 7 ); //尾插法插法 TailInsert( L, 8 ); PrintList(L); printf("\n"); ListInsert( L, 3, 10 ); //固定位置插入 ListInsert( L, 8, 12 ); PrintList(L); printf("\n"); /*长度判断*/ printf("单链表的长度:%d\n", ListLength( L )); int *d; ListSearch( L, 6, d); /*固定位置查找*/ printf( "第6个位置的元素值:%d\n", *d ); ListSearch( L, 20, d); DeleteList( L, 5 , d ); printf( "第5个被删除的元素值:%d\n", *d ); DeleteList( L, 10 , d ); printf( "第10被删除的元素值:%d\n", *d ); PrintList(L); printf("\n"); if(DestroyList( &L ) ); printf("单链表销毁完成!\n"); return 0;}void InitList( LinkList *L ) { /*申请一个头节点,L为指向头结点的头指针*/ *L = (LinkList)malloc(sizeof(LNode)); if (!*L) { printf("单链表初始化失败!\n"); exit(OVERFLOW); } (*L)->next = NULL; return ;}void HeadCreatList(LinkList L){ int d; while ( scanf("%d", &d) != EOF ) { LinkList p; p = ( LinkList )malloc(sizeof(LNode)); if (!p) exit(OVERFLOW); p->data = d; p->next = L->next; L->next = p; }}void RearCreatList( LinkList L ){ int d; LinkList p, q; q = L; while ( scanf("%d", &d) != EOF ) { p = ( LNode* ) malloc ( sizeof (LNode) ); if (!p) exit(OVERFLOW); p -> data = d; q -> next = p; q = p; } q -> next = NULL;}void PrintList(LinkList L){ LinkList p; p = L->next; printf("单链表中的元素为:"); while (p != NULL) { printf("%d ", p->data); p = p->next; }}void HeadInsert( LinkList L, int e ){ LinkList q, s; s = ( LinkList )malloc( sizeof(LNode)); s -> data = e; q = L -> next; L -> next = s; s -> next = q;}void TailInsert( LinkList L, int e ){ LinkList p, s; p = L; while( p->next ) { p = p -> next; } s = ( LinkList )malloc( sizeof(LNode)); /*申请新结点s*/ if( !s ) exit( OVERFLOW ); s -> data = e; /*将e写入新结点*/ p -> next = s;}BOOL ListInsert( LinkList L, int i, int e )/*不改变头指针,所以函数的输入为单链表的头指针L, i为插入的位置, e为待插入的元素*/{ int j = 1; LinkList p, s; p = L -> next; //p指向第一个结点 while( p && j < i-1) /*定位到第i-1个位置*/ { p = p -> next; j++; } if( !p || j > i ) return ERROR; s = ( LinkList )malloc( sizeof(LNode)); /*申请新结点s*/ if( !s ) exit( OVERFLOW ); s -> data = e; /*将e写入新结点*/ s -> next = p -> next; /*调整指针*/ p -> next = s;}BOOL IsListEmpty( LinkList L ){ return L-> next == NULL;}BOOL ListSearch( LinkList L, int i, int *e )/*不改变头指针,所以函数的输入为单链表的头指针L, i为查找的位置, *e为待查找位置的元素*/{ int j = 1; LinkList p = L -> next; while( p && j < i) /*定位到第i个位置*/ { p = p -> next; j++; } if( !p || j > i ){ printf( "查找的位置 %d 错误!\n", i); return ERROR; } *e = p -> data; return OK;}int ListLength( LinkList L ){ int i = 0; LinkList p = L -> next; /*p指向第一个结点*/ while( p ) { i++; p = p -> next; } return i;}BOOL DestroyList( LinkList *L ){ LinkList p ; while( *L ) { p = (*L) -> next; free(*L); (*L) = p; } return OK;}BOOL DeleteList( LinkList L, int i , int *e ){ int j = 1; LinkList p = L -> next, q; while( p && j < i-1 ) { p = p -> next; j++; } if( !p || j > i) return ERROR; q = p -> next; p -> next = q -> next; *e = q -> data; free(q); return OK;}
运行结果如下:
阅读全文
0 0
- 数据结构——单链表
- 数据结构——单链表
- 数据结构——单链表
- 数据结构——单链表
- 数据结构——单链表
- 数据结构——单链表
- 数据结构——单链表
- 数据结构——单链表
- 数据结构——单链表
- 数据结构——单链表
- 数据结构——单链表
- 数据结构——单链表
- 数据结构——单链表
- 数据结构——单链表
- 数据结构—单链表瞎搞
- 数据结构—单链表
- 【数据结构】单链表—逆置单链表
- 数据结构—单链表
- 山东省第八届acm省赛C题 fireworks
- HDU 4417 Super Mario(树状数组离线处理 or 主席树)
- POJ3984 迷宫问题【BFS】
- MenuInfo.java10
- Linux上传文件(超简单)
- 数据结构——单链表
- VS2013社区版试用30天过期重新激活
- StreamTools.java10
- Python学习之函数以及函数式编程详解
- Java 从零开始实现支付宝支付(后台)
- Java穷举法例子
- C++程序员学Java系列之二四:内部类及匿名内部类概念
- myeclipse常用快捷键
- 新手linux系统安装ssh及xshell连接的问题