单链表以及静态链表的实现
2015-07-17 09:42
337 查看
注意:
我认为对于数据结构的深入理解并不是掌握书本上的概念,最重要的是自己的动手编写过程,其中有不少饶人的注意点,望读者有了基本了解之后,动手能够亲自实现,这是一个不一样的过程。
**链表中的数据是以节点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。
· 以“结点的序列”表示线性表称作线性链表(单链表)
· 单链表是链式存取的结构,为找第 i 个数据元素,必须先找到第 i-1 个数据元素。
· 因此,查找第 i 个数据元素的基本操作为:移动指针,比较 j 和 i
单链表
1、链接存储方法
链接方式存储的线性表简称为链表(Linked List)。
链表的具体存储表示为:
① 用一组任意的存储单元来存放线性表的结点(这组存储单元既可以是连续的,也可以是不连续的)
② 链表中结点的逻辑次序和物理次序不一定相同。为了能正确表示结点间的逻辑关系,在存储每个结点值的同时,还必须存储指示其后继结点的地址(或位置)信息(称为指针(pointer)或链(link))
注意:
链式存储是最常用的存储方式之一,它不仅可用来表示线性表,而且可用来表示各种非线性的数据结构。
2、链表的结点结构
┌───┬───┐
│data │next │
└───┴───┘
data域–存放结点值的数据域
next域–存放结点的直接后继的地址(位置)的指针域(链域)
注意:
①链表通过每个结点的链域将线性表的n个结点按其逻辑顺序链接在一起的。
②每个结点只有一个链域的链表称为单链表(Single Linked List)。
【例】线性表(bat,cat,eat,fat,hat,jat,lat,mat)的单链表示如示意图
3、头指针head和终端结点指针域的表示
单链表中每个结点的存储地址是存放在其前趋结点next域中,而开始结点无前趋,故应设头指针head指向开始结点。
注意:
链表由头指针唯一确定,单链表可以用头指针的名字来命名。
终端结点无后继,故终端结点的指针域为空,即NULL。
4、单链表注意点
①LinkList和ListNode是不同名字的同一个指针类型(命名的不同是为了概念上更明确)
②*LinkList类型的指针变量head表示它是单链表的头指针
③ListNode类型的指针变量p表示它是指向某一结点的指针
5、编写过程应了解的函数
①生成结点变量的标准函数
p=( ListNode *)malloc(sizeof(ListNode));
//函数malloc分配一个类型为ListNode的结点变量的空间,并将其首地址放入指针变量p中
②释放结点变量空间的标准函数
free(p);//释放p所指的结点变量空间
③结点分量的访问
利用结点变量的名字*p访问结点分量
方法一:(*p).data和(*p).next
方法二:p-﹥data和p-﹥next
④指针变量p和结点变量*p的关系
指针变量p的值——结点地址
结点变量*p的值——结点内容
(*p).data的值——p指针所指结点的data域的值
(*p).next的值——*p后继结点的地址
*((*p).next)——*p后继结点
注意:
① 若指针变量p的值为空(NULL),则它不指向任何结点。此时,若通过*p来访问结点就意味着访问一个不存在的变量,从而引起程序的错误。
② 有关指针类型的意义和说明方式的详细解释
可见,在链表中插入结点只需要修改指针。但同时,若要在第 i 个结点之前插入元素,修改的是第 i-1 个结点的指针。
因此,在单链表中第 i 个结点之前进行插入的基本操作为:
找到线性表中第i-1个结点,然后修改其指向后继的指针
代码如下:
**用数组描述的链表,即称为静态链表。
· 在C语言中,静态链表的表现形式即为结构体数组,结构体变量包括数据域data和游标cur。
· 这种存储结构,仍需要预先分配一个较大的空间,但在作为线性表的插入和删除操作时不需移动元素,仅需修改指针,故仍具有链式存储结构的主要优点。
我认为对于数据结构的深入理解并不是掌握书本上的概念,最重要的是自己的动手编写过程,其中有不少饶人的注意点,望读者有了基本了解之后,动手能够亲自实现,这是一个不一样的过程。
**链表中的数据是以节点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。
· 以“结点的序列”表示线性表称作线性链表(单链表)
· 单链表是链式存取的结构,为找第 i 个数据元素,必须先找到第 i-1 个数据元素。
· 因此,查找第 i 个数据元素的基本操作为:移动指针,比较 j 和 i
单链表
1、链接存储方法
链接方式存储的线性表简称为链表(Linked List)。
链表的具体存储表示为:
① 用一组任意的存储单元来存放线性表的结点(这组存储单元既可以是连续的,也可以是不连续的)
② 链表中结点的逻辑次序和物理次序不一定相同。为了能正确表示结点间的逻辑关系,在存储每个结点值的同时,还必须存储指示其后继结点的地址(或位置)信息(称为指针(pointer)或链(link))
注意:
链式存储是最常用的存储方式之一,它不仅可用来表示线性表,而且可用来表示各种非线性的数据结构。
2、链表的结点结构
┌───┬───┐
│data │next │
└───┴───┘
data域–存放结点值的数据域
next域–存放结点的直接后继的地址(位置)的指针域(链域)
注意:
①链表通过每个结点的链域将线性表的n个结点按其逻辑顺序链接在一起的。
②每个结点只有一个链域的链表称为单链表(Single Linked List)。
【例】线性表(bat,cat,eat,fat,hat,jat,lat,mat)的单链表示如示意图
3、头指针head和终端结点指针域的表示
单链表中每个结点的存储地址是存放在其前趋结点next域中,而开始结点无前趋,故应设头指针head指向开始结点。
注意:
链表由头指针唯一确定,单链表可以用头指针的名字来命名。
终端结点无后继,故终端结点的指针域为空,即NULL。
4、单链表注意点
①LinkList和ListNode是不同名字的同一个指针类型(命名的不同是为了概念上更明确)
②*LinkList类型的指针变量head表示它是单链表的头指针
③ListNode类型的指针变量p表示它是指向某一结点的指针
5、编写过程应了解的函数
①生成结点变量的标准函数
p=( ListNode *)malloc(sizeof(ListNode));
//函数malloc分配一个类型为ListNode的结点变量的空间,并将其首地址放入指针变量p中
②释放结点变量空间的标准函数
free(p);//释放p所指的结点变量空间
③结点分量的访问
利用结点变量的名字*p访问结点分量
方法一:(*p).data和(*p).next
方法二:p-﹥data和p-﹥next
④指针变量p和结点变量*p的关系
指针变量p的值——结点地址
结点变量*p的值——结点内容
(*p).data的值——p指针所指结点的data域的值
(*p).next的值——*p后继结点的地址
*((*p).next)——*p后继结点
注意:
① 若指针变量p的值为空(NULL),则它不指向任何结点。此时,若通过*p来访问结点就意味着访问一个不存在的变量,从而引起程序的错误。
② 有关指针类型的意义和说明方式的详细解释
可见,在链表中插入结点只需要修改指针。但同时,若要在第 i 个结点之前插入元素,修改的是第 i-1 个结点的指针。
因此,在单链表中第 i 个结点之前进行插入的基本操作为:
找到线性表中第i-1个结点,然后修改其指向后继的指针
代码如下:
#include <stdio.h> #include <stdlib.h> #include <time.h> #define Error 0 #define Ok 1 typedef int ElemType; typedef int Status; typedef struct Node { ElemType data; struct Node *next; }Node,*LinkList; typedef struct Node* LinkList; /** * 获得单链表的元素 */ Status GetElem_L(LinkList L, int i, ElemType *e) { //工作指针后移; int j = 1; LinkList p ; p = L->next; while (p && j < i) { p = p->next; ++j; } if (!p || j > i) { return Error; } *e = p->data; return Ok; } /** * 单链表的插入 */ LinkList ListInsert(LinkList *L, int i, ElemType e) { int j = 1; LinkList p,s; p = *L; while (p && j < i) { p = p->next; ++j; } if (!p || j > i) { return Error; } s = (LinkList)malloc(sizeof(Node)); s->data = e; s->next = p->next; p->next = s; return *L; } /** * 单链表的删除 */ LinkList ListDelete(LinkList *L, int i) { int j = 1; LinkList p; p = *L; while (p && j < i) { p = p->next; ++j; } if (!p || j > i) { return Error; } p->next = p->next->next; // e = p->data; free(p->next); return *L; } /** * 单链表的整表创建 动态生成 (头插法)始终让新节点插在第一的位置 */ LinkList CreatList_LH(LinkList L,int n) { LinkList p; int i ; L = (LinkList)malloc(sizeof(Node)); L->next = NULL; srand((unsigned)time(0)); for (i = 0; i < n; i++) { p = (LinkList)malloc(sizeof(Node)); p->data = rand()%100 + 1; //printf("%d ",p->data); p->next = L->next; L->next = p; } return L; } /** * 尾插法 */ LinkList CreatList_LD(LinkList *L,int n) { LinkList p,r; int i ; srand((unsigned)time(0)); *L = (LinkList)malloc(sizeof(Node)); //L->next = NULL; r = *L; for (i = 0; i < n; i ++) { p = (LinkList)malloc(sizeof(Node)); p->data = rand()%100 + 1; //printf("%d ",p->data); r->next = p; r = p; } r->next = NULL; return *L; } /** * 单链表的清除 */ Status ClearList(LinkList L) { LinkList q,p; p = L->next; while (p) { q = p->next; free(p); p = q; } L->next = NULL; return Ok; } Status LengthOfList(LinkList L) { int length; while (L->next != NULL) { length++; L = L->next; } return length; } ElemType GetMidNode(LinkList *L) { LinkList search,mid; mid = search = *L; while (search->next != NULL) { if (search->next->next != NULL) { search = search->next->next; mid = mid->next; } else { search = search->next; mid = mid->next; } } return mid->data; } int main() { LinkList list,start; /* printf("请输入单链表的数据:"); list = LinkedListCreatH(); for(start = list->next; start != NULL; start = start->next) printf("%d ",start->data); printf("/n"); */ printf("请输入单链表的个数:"); int j = 0; scanf("%d",&j); list = CreatList_LD(&list, j); for(start = list->next; start != NULL; start = start->next) printf("%d ",start->data); printf("\n"); int length = LengthOfList(list); printf("%d",length); printf("\n"); int i; ElemType x; printf("请输入插入数据的位置:"); scanf("%d",&i); while (i > j||i <= 0) { printf("请输入插入数据的位置:"); scanf("%d",&i); } printf("请输入插入数据的值:"); scanf("%d",&x); list = ListInsert(&list, i, x); for(start = list->next; start != NULL; start = start->next) printf("%d ",start->data); printf("\n"); ElemType k; k = GetMidNode(&list); printf("%d",k); printf("\n"); printf("请输入删除数据的位置:"); scanf("%d",&i); list = ListDelete(&list, i); for(start = list->next; start != NULL; start = start->next) { printf("%d ",start->data);} printf("\n"); ClearList(list); return 0; }
**用数组描述的链表,即称为静态链表。
· 在C语言中,静态链表的表现形式即为结构体数组,结构体变量包括数据域data和游标cur。
· 这种存储结构,仍需要预先分配一个较大的空间,但在作为线性表的插入和删除操作时不需移动元素,仅需修改指针,故仍具有链式存储结构的主要优点。
#include <stdio.h> #include <time.h> #include <stdlib.h> #define MaxSize 100 typedef int ElemType; typedef struct { ElemType data; int cur; }SList,StaticLinkList[MaxSize]; /** * 初始化 */ void init_sl(StaticLinkList space) { int i; for (i = 0; i < MaxSize - 1; i++) { space[i].cur = i +1; } space[MaxSize-1].cur = 0; } /** * 分配空闲结点 */ int malloc_sl(StaticLinkList space) { int i = space[0].cur; if (i) { space[0].cur = space[i].cur; } return i; } int GetListLength(StaticLinkList space) { int j = 0; int k = space[MaxSize - 1].cur; while (k) { j++; k = space[k].cur; } return j; } void ListInsert(StaticLinkList L, int i, ElemType e) { int k = MaxSize - 1; if (i < 1|| i > GetListLength(L) + 1) { return; } int v = malloc_sl(L); { for (int j= 0 ; j < i- 1; j++) { k = L[k].cur;//插入的前一个结点 } L[v].data = e; L[v].cur = L[k].cur; L[k].cur = v; } } void Free_SLL(StaticLinkList L,int j) { L[j].cur = L[0].cur; L[0].cur = j; } /** * 删除i位置的元素 */ void DeleteList(StaticLinkList L, int i) { int k = MaxSize - 1; if (i < 1|| i > GetListLength(L) + 1) { return; } for (int j = 0; j < i -1; j++) { k = L[k].cur; } int temp = L[k].cur; L[k].cur = L[temp].cur; Free_SLL(L, temp); } void Print(StaticLinkList L) //打印链表 { int k = L[MaxSize - 1].cur; while(k) { printf("%d ",L[k].data); k = L[k].cur; } printf("\n"); } int main(int argc, const char * argv[]) { srand((unsigned)time(0)); StaticLinkList L; init_sl(L); //初始化链表 for(int i = 0;i < 8;++i) ListInsert(L, i, rand()%100 + 1); Print(L); //输出链表 int i,j; printf("请输入插入的位置:"); scanf("%d",&j); printf("请输入插入的值:"); scanf("%d",&i); ListInsert(L,j,i); //在链表的第3个位置插入22 Print(L); printf("请输入删除的位置:"); scanf("%d",&j); DeleteList(L,j); Print(L); return 0; }
相关文章推荐
- NYOJ 14 会场安排问题
- 正则表达式 分类区别
- numpy安装
- php+mysql的utf-8中文乱码问题的解决方法
- 新手应该知道的流量概念
- Android实现登录功能demo示例
- 盒子模型
- uva 10970
- Ubuntu 11.10 GCC4.5 GCC4.6无缝切换
- Launcher3如何给桌面添加一页,并显示一个应用
- Apache集成tomcat windows
- 22-判断一个序列是否是另一个序列入栈的弹出序列
- Set Matrix Zeroes
- 推荐系统原理介绍
- 恩布企业 IM iOS端 1.1 发布, 开源手机 IM
- osg示例简介
- VMware Vsphere高可性(HA-FT群集)
- FoonSunCMS-Word图片上传功能-Xproer.WordPaster
- a标签 中调用js的几种方法
- acm CodeForces 546B