静态链表、循环链表、双向链表(C代码实现)

静态链表

对于没有指针的编程语言,可以用数组替代指针,来描述链表。让数组的每个元素由data和cur两部分组成,其中cur相当于链表的next指针,这种用数组描述的链表叫做静态链表,这种描述方法叫做游标实现法。我们对数组的第一个和最后一个元素做特殊处理,不存数据。让数组的第一个元素cur存放第一个备用元素(第一个未被占用的元素)下标,而数组的最后一个元素cur存放第一个有值的元素下标,相当于头结点作用。空的静态链表如下图

当存放入一些数据时("甲""乙""丁""戊""己""庚"),静态链表为:

静态链表的插入操作

在静态链表第三个位置插入"丙"后,结果如下:

静态链表中要解决的是:如何用静态模拟动态链表结构的存储空间的分配,需要时申请,无用时释放。

其主要的思想:(以我们如果要在乙 和 丁 中间插入一个丙 )

我们自己定义一个内存分配函数,如Malloc_SLL(StaticLinkList space)

1 //插入元素时,分配空间的下标(从备用链表中去取出)
2 int Malloc(StaticLinkList L)
3 {
4     int i = L[0].cur;               //获取备用链表的下表
5     if (i)                           //链表不为空
6         L[0].cur = L[i].cur;       //将第一位的游标改成备用链表的下表+1
7     return i;
8 }

然后再修改游标表示,如上图

代码附上:

 1 //静态链表中i位置插入一个元素
 2 bool StaticLinkListInsert(StaticLinkList L, int i, int key)
 3 {
 4     //判断插入点是否合理
 5     if (i<1 || i>StaticLinkListLength(L)+1)
 6     {
 7         return false;
 8     }
 9     int j = Malloc(L);
10     int k = MAXSIZE - 1;
11     if (j)
12     {
13         for (int l = 1; l <= j - 1; l++)
14         {
15             k = L[k].cur;
16         }
17         L[j].data = key;
18         L[j].cur = L[k].cur;
19         L[k].cur = j;
20         return true;
21     }
22     return false;
23
24 }

静态链表的删除操作

删除操作其实就是插入操作的逆操作

我们同样要自己定义一个Free函数

void Free(StaticLinkList L, int k)
{
    L[k].cur = L[0].cur;
    L[0].cur = k;
}

获取要删除的元素下标后,开始修改游标

 1 bool StaticLinkListDelete(StaticLinkList L,int i, int *key)
 2 {
 3     if (i < 1 || i >= StaticLinkListLength(L))
 4     {
 5         return false;
 6     }
 7     int k = MAXSIZE - 1;
 8     for (int l = 1; l <= i-1; l++)
 9     {
10         k = L[k].cur;
11     }
12     int j = L[k].cur;
13     *key = L[j].data;
14     L[k].cur = L[j].cur;
15     Free(L, j);
16     return true;
17 }

删除"甲"后,静态链表如下:

总结一下静态链表的优缺点:

优点:在插入和删除时,只需要修改游标,不需要移动元素。从而改进了在顺序存储结构中的插入和删除需要移动大量元素的特点。

缺点:没有解决连续存储分配带来的表长难以确定的问题;失去了顺序存储结构随机存储的特性。

Copy 了大佬一些些文字和图片:

https://www.cnblogs.com/zhaoxy/p/7754906.html

静态链表实现的一些基本操作:(附上代码)

  1 #include<stdio.h>
  2
  3 #define MAXSIZE 7
  4 #define true 1
  5 #define false 0
  6
  7 typedef int bool;
  8
  9 typedef struct
 10 {
 11     int data;
 12     int cur;
 13 }StaticLinkList[MAXSIZE];
 14
 15 //初始化静态链表,0位置cur指向1位置,1位置cur指向2位置...MAXSIZE-1位置指向0位置
 16 void InitStaticLinkList(StaticLinkList L)//本来想用小写l的,但是小写l看起来太怪了
 17 {
 18     for (int i = 0; i < MAXSIZE - 2; i++)
 19     {
 20         L[i].cur = i + 1;//最后一个元素指向的是尾节点
 21     }
 22     L[MAXSIZE - 2].cur = 0;//备用链表的最后一个空元素的cur指向0,这一行不能省。
 23     L[MAXSIZE - 1].cur = 0;
 24 }
 25
 26
 27 //求静态链表中元素个数,不包括头尾节点
 28 int StaticLinkListLength(StaticLinkList L)
 29 {
 30     int i = L[MAXSIZE - 1].cur;
 31     int j = 0;
 32     while (i)
 33     {
 34         j++;
 35         i = L[i].cur;
 36     }
 37     return j;
 38 }
 39
 40 //插入元素时,分配空间的下标
 41 int Malloc(StaticLinkList L)
 42 {
 43     int i = L[0].cur;
 44     if (i)
 45         L[0].cur = L[i].cur;
 46     return i;
 47 }
 48
 49
 50 //静态链表中i位置插入一个元素
 51 bool StaticLinkListInsert(StaticLinkList L, int i, int key)
 52 {
 53     //判断插入点是否合理
 54     if (i<1 || i>StaticLinkListLength(L)+1)
 55     {
 56         return false;
 57     }
 58     int j = Malloc(L);
 59     int k = MAXSIZE - 1;
 60     if (j)
 61     {
 62         for (int l = 1; l <= j - 1; l++)
 63         {
 64             k = L[k].cur;
 65         }
 66         L[j].data = key;
 67         L[j].cur = L[k].cur;
 68         L[k].cur = j;
 69         return true;
 70     }
 71     return false;
 72
 73 }
 74
 75
 76 void Free(StaticLinkList L, int k)
 77 {
 78     L[k].cur = L[0].cur;
 79     L[0].cur = k;
 80 }
 81
 82 //删除第i个元素
 83
 84 bool StaticLinkListDelete(StaticLinkList L,int i, int *key)
 85 {
 86     if (i < 1 || i >= StaticLinkListLength(L))
 87     {
 88         return false;
 89     }
 90     int k = MAXSIZE - 1;
 91     for (int l = 1; l <= i-1; l++)
 92     {
 93         k = L[k].cur;
 94     }
 95     int j = L[k].cur;
 96     *key = L[j].data;
 97     L[k].cur = L[j].cur;
 98     Free(L, j);
 99     return true;
100 }
101
102 //遍历
103 void StaticLinkListTraverse(StaticLinkList L)
104 {
105     int k = MAXSIZE - 1;
106     while (L[k].cur)
107     {
108         k = L[k].cur;
109         printf("%d ", L[k].data);
110     }
111     printf("\n");
112 }
113
114 int main(void)
115 {
116     StaticLinkList L;
117     printf("初始化链表:\n");
118     InitStaticLinkList(L);
119     printf("初始化链表之后,链表的长度为:%d\n", StaticLinkListLength(L));
120     printf("插入1,2,3,4,5\n");
121     StaticLinkListInsert(L, 1, 1);
122     StaticLinkListInsert(L, 1, 2);
123     StaticLinkListInsert(L, 1, 3);
124     StaticLinkListInsert(L, 1, 4);
125     StaticLinkListInsert(L, 1, 5);
126     printf("遍历链表:\n");
127     StaticLinkListTraverse(L);
128     printf("链表长度为:%d\n", StaticLinkListLength(L));
129     printf("删除第二个元素:\n");
130     int key;
131     StaticLinkListDelete(L, 2, &key);
132     printf("删除的元素值为:%d\n", key);
133     printf("遍历链表:\n");
134     StaticLinkListTraverse(L);
135
136 }

并且附上代码来源:

https://blog.csdn.net/hhhhhyyyyy8/article/details/81027728

循环链表

1、循环链表:

      这个就是在单链表的基础上头尾相接了,将最后一个结点的指针指向了L->next;这里我们也不多做赘述,它的大部分操作和单链表是相似的。

      还有一点要注意的就是判断一个循环链表是否为空条件是看头结点是否指向其本身。

双向链表

所谓双向就是说有两个方向,其实就是在单链表的基础上,多了一个前驱的指针域,用来指向前驱元素,其解决了单链表单向性这一缺点(只能顺着后继元素遍历)

双向循环链表,与循环链表类似,带头结点的双向循环空链表如下图(左),非空如下图(右边)

那么入定义一个双向链表呢?

1  typedef struct DulNode
2 {
3      struct DulNode *prior;                      //前驱指针
4      struct DulNode *next;                       //后继指针
5      ElemType e;                                 //数据域
6 }DulNode,*DuLinkList;

插入操作

对比单链表学习,复杂并且灵活

插入关键代码:

1  s->prior = p;           //把p赋值给s的前驱,s的前驱指向p
2  s->next = p->next;      //把p->next赋值给s的后继
3  p->next->prior = s;     //把s赋值给p-next的前驱
4 p->next = s;            //把s赋值给p的后继

删除操作

删除操作关键代码:

1 P->prior->next = p->next; //把p->next的值赋给p->prior的后继
2 p->next->prior = P->prior;//把p=>prior赋值给p->next的前驱

复习回顾:

我们对线性表的两大结构进行了学习,先是学习了比较容易的顺序存储结构,,指的是用一段地址连续的存储单元依次存储线性表中的元素,我们通常使用数组来实现。

后面则是学习了链式存储结构。它具有不收存储空间的限制,可以比较快捷的插入和删除的特点被广为使用。然后还学习了动态链表的单链表、双链表、循环链表,以及最后我们还学习了如何不使用指针处理链式结构的数据关系---静态链表。

总的来说,线性表就包含了顺序存储结构和链式存储结构两大结构。

原文地址:https://www.cnblogs.com/liuzeyu12a/p/10301672.html

时间: 2024-10-07 02:37:06

静态链表、循环链表、双向链表(C代码实现)的相关文章

【数据结构】单链表&amp;&amp;静态链表详解和代码实例

喜欢的话可以扫码关注我们的公众号哦,更多精彩尽在微信公众号[程序猿声] 01 单链表(Singly Linked List ) 1.1 什么是单链表? 单链表是一种链式存储的结构.它动态的为节点分配存储单元.当有节点插入时,系统动态的为结点分配空间.在结点删除时,应该及时释放相应的存储单元,以防止内存泄露.由于是链式存储,所以操作单链表时,必须知道头结点或者头指针的位置.并且,在查找第i个节点时,必须找到第i-1个节点. 1.2 单链表的存储结构代码描述 对于链式存储,通过上一节的讲解相信大家已

静态链表过程演示及代码实现(A - B) U (B - A)

静态链表说明 使用数组来实现链式存储结构,目的是方便在不设指针类型的高级程序设计语言中使用链式结构 c语言定义数据结构 #define MAX_SIZE 1000 // 所有的类型都统一定义为ElemType typedef int ElemType; typedef struct { ElemType data; int cur; } component, LinkList[MAX_SIZE]; 存储结构如下图所示 静态链表的工作原理 静态链表重点是在构建两个链表:备用链表(空闲的节点)和数据

能判断是否还有剩余空间的静态链表

第一次系统的学习数据结构是在半年前,看小甲鱼的数据结构与算法视频,自学的话有许多不懂得地方,什么AVL树,红黑树,图的最短路径,最小生成树...但总归对数据结构与算法有一个大体的印象,到现在随着不断写代码,做OJ题,愈发认识到数据结构与算法的重要性,打算再看一遍,现在看着:大话数据结构(程杰著),数据结构(C语言版严蔚敏著),不推荐新手使用 数据结构与算法分析(Mark Allen Weiss 著)这本书真的很难懂. 回归正题,我看了许多书有关静态链表的描述和代码发现都没有判断是否还有剩余空间,

静态链表(C++实现)

用数组描述的链表,即称为静态链表. 在C语言中,静态链表的表现形式即为结构体数组,结构体变量包括数据域data和游标cur. 这种存储结构,仍需要预先分配一个较大的空间,但在作为线性表的插入和删除操作时不需移动元素,仅需修改指针,故仍具有链式存储结构的主要优点. 下图表示了静态链表的一中存储结构: 图中用彩色途上的是两个头结点,不存放数据,分别用来记录第一个备用节点和第一个数据节点的下标. 下面给出静态链表的C++实现代码: 首先给出头文件:StaticList.h: #include<iost

静态链表 C++实现

<span style="font-size:12px;">用数组描述的链表,即称为<strong>静态链表</strong>. 在C语言中,静态链表的表现形式即为结构体数组,结构体变量包括数据域data和游标cur. 这种存储结构,仍需要预先分配一个较大的空间,但在作为线性表的插入和删除操作时不需移动元素,仅需修改指针,故仍具有链式存储结构的主要优点. 下图表示了静态链表的一中存储结构: 图中用彩色途上的是两个头结点,不存放数据,分别用来记录第一个

[读书笔记]-大话数据结构-3-线性表(三)-静态链表、循环链表和双向链表

静态链表 对于没有指针的编程语言,可以用数组替代指针,来描述链表.让数组的每个元素由data和cur两部分组成,其中cur相当于链表的next指针,这种用数组描述的链表叫做静态链表,这种描述方法叫做游标实现法.我们对数组的第一个和最后一个元素做特殊处理,不存数据.让数组的第一个元素cur存放第一个备用元素(未被占用的元素)下标,而数组的最后一个元素cur存放第一个有值的元素下标,相当于头结点作用.空的静态链表如下图 当存放入一些数据时("甲""乙""丁&q

单链表,双向链表,循环链表

数据结构: 定义: 特定的数据类型(个体)和特定的存储结构(个体的关系) 数据如何存储在内存中 分类: 线性结构: 数据元素之间存在一对一的线性关系.线性结构拥有两种不同的存储结构,即顺序存储结构和链式存储结构. 数组与列表:顺序存储结构 相同点: 需要申请一块连续的内存空间 不同点: 列表或者数组中的元素是如何存储的,以及两者的区别? 在其他语言中(C/C++)数组申请的内存空间是一定的, 比如申请10M的内存空间,如果数据超过10M会溢出,需要手动申请和释放 在python中不会出现溢出报错

看数据结构写代码(5)静态链表

静态链表用于 不能使用 指针的 编程语言中. 下面奉上代码: // StaticLinkList.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <stdlib.h> //静态链表的 实现 typedef int Element; #define INIT_SIZE 10 //为了测试,故意将值设置的很小 enum E_STATE { E_STATE_ERROR = 0, E_STATE_OK = 1, }; str

数据结构之线性表代码实现顺序存储,链式存储,静态链表(选自大话数据结构)

一,线性表顺序存储 #include <stdio.h> #include <string.h> #include <ctype.h> #include <stdlib.h> #include <io.h> #include <math.h> #include <time.h> #define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0 #define MAXSI