数据结构学习笔记2:双向链表和静态链表
1. 双向链表的简介&概念
双向链表可以简称为双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。
双向链表示意图:
一个完整的双向链表应该是头结点的pre指针指为空,尾结点的next指针指向空,其余结点前后相链。
2. 双向链表的结点设计
结点示意:
DATA表示数据,其可以是简单的类型(如int,double等等),也可以是复杂的结构体(struct类型);
pre代表的是前驱指针,它永远指向当前结点的前一个结点,如果当前结点是头结点,则pre指针为空;
next代表的是后继指针,它永远指向当前结点的下一个结点,如果当前结点是尾结点,则next指针为空。
3.创建双向链表
typedef struct DuLnode{
int data;
struct DuLnode *prior, *next;
}DuLnode, *DuLinkList;
4.初始化双链表
DuLinkList initLinkList(){DuLinkList tH = (DuLinkList)malloc(sizeof(DuLnode));tH->prior = NULL;tH->next = NULL;return tH;
}
5.插入
在表头插入示意图如下:
void insertElement(DuLinkList pH, int paraData, int paraPosition){ DuLinkList p, q, r;if(paraPosition < 0){printf("位置为负,不行!\n"); return;} p = pH;for (int i = 0; i < paraPosition; i ++) {p = p->next;if (p == NULL) {printf("这位置有点太大了", paraPosition);return;}}q = (DuLinkList)malloc(sizeof(DuLnode));q->data = paraData;r = p->next;q->next = p->next;q->prior = p;p->next = q;if (r != NULL) {r->prior = q;}
}
6.删除指定元素
示意图如下:
代码如下:
void deleteElement(DuLinkList pH, int paraData){ //删除这个元素 DuLinkList p;p = pH;while(p){if(p->data == paraData){if(p->prior == NULL){printf("azaz\n");pH = pH->next;pH->next = NULL;free(p);return;}else if(p->next == NULL){p->prior->next = NULL;free(p);return;}else{p->next->prior = p->prior;p->prior->next = p->next;free(p);return;} }p = p->next;}printf("找不到这个元素哦\n");return;
}
7.总代码
#include<stdio.h>
#include <malloc.h>#define ERROR 0;
#define OK 1;
#define isMyFaith maintypedef int Status;
typedef int Kurumi;typedef struct DuLnode{ int data;struct DuLnode *prior, *next; }DuLnode, *DuLinkList; DuLinkList initLinkList(){DuLinkList tH = (DuLinkList)malloc(sizeof(DuLnode));tH->prior = NULL;tH->next = NULL;return tH;
}void printList(DuLinkList pH){ DuLinkList p = pH;while (p->next != NULL) {p = p->next;printf("%d", p->data);}printf("\n");}void insertElement(DuLinkList pH, int paraData, int paraPosition){ //在一个位置上插入元素 DuLinkList p, q, r;//判断位置合不合理if(paraPosition < 0){printf("位置为负,不行!\n"); return;} p = pH;for (int i = 0; i < paraPosition; i ++) {p = p->next;if (p == NULL) {printf("这位置有点太大了", paraPosition);return;}}q = (DuLinkList)malloc(sizeof(DuLnode));q->data = paraData;r = p->next;q->next = p->next;q->prior = p;p->next = q;if (r != NULL) {r->prior = q;}
}void deleteElement(DuLinkList pH, int paraData){ DuLinkList p;p = pH;while(p){if(p->data == paraData){if(p->prior == NULL){printf("azaz\n");pH = pH->next;pH->next = NULL;free(p);return;}else if(p->next == NULL){p->prior->next = NULL;free(p);return;}else{p->next->prior = p->prior;p->prior->next = p->next;free(p);return;} }p = p->next;}printf("找不到这个元素哦\n");return;
}void insertDeleteTest(){DuLinkList tempList = initLinkList(); insertElement(tempList, 5, 0);insertElement(tempList, 7, 1);insertElement(tempList, 0, 2);insertElement(tempList, 4, 3);insertElement(tempList, 9, 4);insertElement(tempList, 6, 5);insertElement(tempList, 6, -5);printList(tempList);deleteElement(tempList, 0);deleteElement(tempList, 555);printList(tempList);}void basicAddressTest(){DuLnode p1, p2;p1.data = 4;p1.next = NULL;p2.data = 6;p2.next = NULL;printf("The first node: %d, %d, %d\r\n", &p1, &(p1.data), &(p1.next));printf("The second node: %d, %d, %d\r\n", &p2, &(p2.data), &(p2.next));
}Kurumi isMyFaith()
{insertDeleteTest();basicAddressTest();return 0;}
静态链表
1.概念:逻辑结构上相邻的数据元素,存储在指定的一块内存空间中,数据元素只允许在这块内存空间中随机存放,这样的存储结构生成的链表称为静态链表。
2.静态链表和动态链表的区别:静态链表限制了数据元素存放的位置范围;动态链表是整个内存空间。
3.结构体定义
#include <stdio.h>
#include <malloc.h>#define DEFAULT_SIZE 5typedef struct StaticLinkedNode{char data;int next;
} *NodePtr;typedef struct StaticLinkedList{NodePtr nodes;int* used;
} *ListPtr;
4.初始化
/*** 初始化头节点。* @return 返回头节点的指针。*/
ListPtr initLinkedList(){// 指向整个链表空间的指针ListPtr tempPtr = (ListPtr)malloc(sizeof(struct StaticLinkedList));// 分配总空间tempPtr->nodes = (NodePtr)malloc(sizeof(struct StaticLinkedNode) * DEFAULT_SIZE);tempPtr->used = (int*)malloc(sizeof(int) * DEFAULT_SIZE);// 第一个节点是头结点tempPtr->nodes[0].data = '\0';tempPtr->nodes[0].next = -1;// 初始化时只有头结点使用tempPtr->used[0] = 1;for (int i = 1; i < DEFAULT_SIZE; i ++){tempPtr->used[i] = 0;}return tempPtr;
}
5.打印
/*** 打印链表。* @param paraHeader 是链表的头结点。*/
void printList(ListPtr paraListPtr){int p = 0;while (p != -1) {printf("%c", paraListPtr->nodes[p].data);p = paraListPtr->nodes[p].next;}printf("\r\n");
}
6.在指定位置插入元素
void insertElement(ListPtr paraListPtr, char paraChar, int paraPosition){int p, q, i;// Step 1. 搜索位置p = 0;for (i = 0; i < paraPosition; i ++) {p = paraListPtr->nodes[p].next;if (p == -1) {printf("The position %d is beyond the scope of the list.\r\n", paraPosition);return;}} // Step 2. 创建一个新的节点for ( i; i < DEFAULT_SIZE; i ++){if (paraListPtr->used[i] == 0){printf("Space at %d allocated.\r\n", i);paraListPtr->used[i] = 1;q = i;break;}}if (i >= DEFAULT_SIZE){printf("No space.\r\n");return;}paraListPtr->nodes[q].data = paraChar;// Step 3. 链接节点printf("linking\r\n");paraListPtr->nodes[q].next = paraListPtr->nodes[p].next;paraListPtr->nodes[p].next = q;
}
7.删除元素
/**
* 删除链表中的元素。
* @param paraHeader 是链表的头结点。
* @param paraChar 给定的char元素。
*/
void deleteElement(ListPtr paraListPtr, char paraChar){
int p, q;
p = 0;
while ((paraListPtr->nodes[p].next != -1) && (paraListPtr->nodes[paraListPtr->nodes[p].next].data != paraChar)){
p = paraListPtr->nodes[p].next;
}
if (paraListPtr->nodes[p].next == -1) {
printf("Cannot delete %c\r\n", paraChar);
return;
}
q = paraListPtr->nodes[p].next;
paraListPtr->nodes[p].next = paraListPtr->nodes[paraListPtr->nodes[p].next].next;
// 此语句和free(q)功能相同
paraListPtr->used[q] = 0;
}
完整代码
#include <stdio.h>
#include <malloc.h>/*** 定义字符双向链表。*/
typedef struct DoubleLinkNode{char data;struct DoubleLinkNode *previous;struct DoubleLinkNode *next;
} DLNode, *DLNodePtr;/*** 初始化头节点。* @return 返回头节点的指针。*/
DLNodePtr initLinkList(){DLNodePtr tempHeader = (DLNodePtr)malloc(sizeof(struct DoubleLinkNode));tempHeader->data = '\0';tempHeader->previous = NULL;tempHeader->next = NULL;return tempHeader;
}/*** 打印链表。* @param paraHeader 是链表的头结点。*/
void printList(DLNodePtr paraHeader){DLNodePtr p = paraHeader->next;if(p == NULL){printf("The list is empty.");}while(p != NULL){printf("%c", p->data);p = p->next;}printf("\r\n");
}/*** 在给定的位置加入元素。* @param paraHeader 是链表的头结点。* @param paraChar 给定的char元素。* @param paraPosition 给定的位置。*/
void insertElement(DLNodePtr paraHeader, char paraChar, int paraPosition){DLNodePtr p, q, r;// Step 1. 搜索给定的位置。p = paraHeader;for(int i = 0; i < paraPosition; i ++){p = p->next;if(p == NULL){printf("The position %d is beyond the scope of the list.", paraPosition);return;}}// Step 2. 创建一个新节点q = (DLNodePtr)malloc(sizeof(struct DoubleLinkNode));q->data = paraChar;// Step 3. 链接链表和节点。printf("linking\r\n");r = p->next;q->next = p->next;q->previous = p;p->next = q;if (r != NULL){r->previous = q;}
}/*** 删除链表中的元素。* @param paraHeader 是链表的头结点。* @param paraChar 给定的char元素。*/
void deleteElement(DLNodePtr paraHeader, char paraChar){DLNodePtr p, q, r;p = paraHeader;// Step 1. 定位while((p->next != NULL) && (p->next->data != paraChar)){p = p->next;}// Step 2. 检查错误if(p->next == NULL){printf("The char %c does not exist.\r\n", paraChar);return;}// Step 3. 改变链接q = p->next;r = q->next;p->next = r;if(r != NULL){r->previous = p;}// Step 4. 释放内存free(q);
}/*** 找到双向链表中特定的数据的位置*/
void locateElement(DLNodePtr paraHeader, char paraChar){DLNodePtr p;p = paraHeader;while(p->next != NULL){p = p->next;if(p->data == paraChar){printf("Found the char %c\r\n", paraChar);return;}}printf("The char %c is not been found.\r\n", paraChar);return ;
}void LinkDestory(DLNodePtr paraHeader){DLNodePtr p;p = paraHeader;p->next = NULL;printf("The list has been destoryed.\r\n");return;
}/*** 功能测试。*/
void insertDeleteTest(){// Step 1. 初始化一个空链表。DLNodePtr tempList = initLinkList();printList(tempList);// Step 2. 加入一些字符。insertElement(tempList, 'H', 0);printList(tempList);insertElement(tempList, 'e', 1);printList(tempList);insertElement(tempList, 'l', 2);printList(tempList);insertElement(tempList, 'l', 3);printList(tempList);insertElement(tempList, 'o', 4);printList(tempList);insertElement(tempList, '!', 5);printList(tempList);// Step 3. 删除一些字符(第一次出现的)。deleteElement(tempList, 'e');printList(tempList);deleteElement(tempList, 'a');printList(tempList);deleteElement(tempList, 'o');printList(tempList);// Step 4. 在链表给定位置插入特定元素。insertElement(tempList, 'o', 1);//首位插入printList(tempList);insertElement(tempList, 'o', 5);//末位插入printList(tempList);insertElement(tempList, 'o', 3);//中间插入printList(tempList);// Step 5. 查找指定元素locateElement(tempList, 'H');locateElement(tempList, 'l');locateElement(tempList, 'o');locateElement(tempList, 'a');// Step 6. 清空链表LinkDestory(tempList);printList(tempList);
}/*** 地址测试.*/
void basicAddressTest(){DLNode tempNode1, tempNode2;tempNode1.data = 4;tempNode1.next = NULL;tempNode2.data = 6;tempNode2.next = NULL;printf("The first node: %d, %d, %d\r\n",&tempNode1, &tempNode1.data, &tempNode1.next);printf("The second node: %d, %d, %d\r\n",&tempNode2, &tempNode2.data, &tempNode2.next);tempNode1.next = &tempNode2;
}/*** 程序入口。*/
int main(){insertDeleteTest();basicAddressTest();
}
运行结果
Space at 1 allocated.
linking
Space at 2 allocated.
linking
Space at 3 allocated.
linking
Space at 4 allocated.
linking
No space.
No space.
Hlel
Deleting 'e'.
Deleting 'a'.
Cannot delete a
Deleting 'o'.
Cannot delete o
Hll
Space at 2 allocated.
linking
Hxll
静态链表和单链表的区别和联系 :
静态链表:
使用静态链表存储数据,需要预先申请足够大的一整块内存空间,也就是说,静态链表存储数据元素的个数从其创建的那一刻就已经确定,后期无法更改。
不仅如此,静态链表是在固定大小的存储空间内随机存储各个数据元素,这就造成了静态链表中需要使用备用链表来记录空间存储空间的位置,以便后期分配给新添加元素使用。
动态链表:
使用动态链表存储数据,不需要预先申请内存空间,而是在需要的时候才向内存申请。也就是说,动态链表存储数据元素的个数是不限的,想存多少就存多少。
同时,使用动态链表的整个过程,你也只需操控一条存储数据的链表。当表中添加或删除数据元素时,你只需要通过 malloc 或 free 函数来申请或释放空间即可,实现起来比较简单。
数据结构学习笔记2:双向链表和静态链表相关推荐
- C语言数据结构学习(4):静态链表
一.静态链表概念 用数组描述的链表,即称为静态链表. 在C语言中,静态链表的表现形式即为结构体数组,结构体变量包括数据域data和游标. 优点: 这种存储结构,仍需要预先分配一个较大的空间,但在作为线 ...
- 数据结构学习笔记(一):链表(linked list)
目录 1 链表的概念和分类 2 链表对于数据的增删查操作(以单向链表为例) 2.1 增删查操作的描述 2.2 增删查操作的代码实现(JAVA) 1 链表的概念和分类 链表,又称线性表或线性链表,是若干 ...
- Python数据结构学习笔记——链表:无序链表和有序链表
目录 一.链表 二.无序链表 实现步骤分析 三.无序链表的Python实现代码 四.有序链表 实现步骤分析 五.有序链表的Python实现代码 结语 一.链表 链表中每一个元素都由为两部分构成:一是该 ...
- 数据结构学习笔记:实现链表
数据结构学习笔记:实现链表 1.结点结构 结点结构是由数据域和指针域组成,数据域是存放数据的,而指针域存放下一结点的地址. 2.链表结构 通过数据域访问到我们要的数据,而通过指针域访问到当前结点以后的 ...
- 数据结构学习笔记(王道)
数据结构学习笔记(王道) PS:本文章部分内容参考自王道考研数据结构笔记 文章目录 数据结构学习笔记(王道) 一.绪论 1.1. 数据结构 1.2. 算法 1.2.1. 算法的基本概念 1.2.2. ...
- 数据结构学习笔记(3-5):树
附录:所有blog的链接 数据结构学习笔记(1):基本概念 数据结构学习笔记(2):线性结构 数据结构学习笔记(3-5):树 数据结构学习笔记(6-8):图 数据结构学习笔记(9-10):排序 数据结 ...
- Windows进程与线程学习笔记(四)—— 等待链表调度链表
Windows进程与线程学习笔记(四)-- 等待链表&调度链表 要点回顾 33个链表 等待链表 实验:分析等待链表中的线程所属的进程 第一步:查看所属线程结构体: 第二步:查看所属进程结构体 ...
- 数据结构学习笔记(七):哈希表(Hash Table)
目录 1 哈希表的含义与结构特点 1.1 哈希(Hash)即无序 1.2 从数组看哈希表的结构特点 2 哈希函数(Hash Function)与哈希冲突(Hash Collision) 2.1 哈希函 ...
- 数据结构学习笔记(六):二叉树(Binary Tree)
目录 1 背景知识:树(Tree) 2 何为二叉树(Binray Tree) 2.1 二叉树的概念与结构 2.2 满二叉树与完全二叉树 2.3 二叉树的三种遍历方式 3 二叉树及其遍历的简单实现(Ja ...
- 数据结构学习笔记(五):重识字符串(String)
目录 1 字符串与数组的关系 1.1 字符串与数组的联系 1.2 字符串与数组的区别 2 实现字符串的链式存储(Java) 3 子串查找的简单实现 1 字符串与数组的关系 1.1 字符串与数组的联系 ...
最新文章
- 两个ListBox中的项互相移动及上下移动
- 读博难?DeepMind科学家Ruder提出读博/做研究的十条锦囊
- BCompare注册文件+密钥被撤销解决方案
- AI公开课:19.04.04李航—字节跳动AILab总监《深度学习与自然语言处理:评析与展望》课堂笔记以及个人感悟
- WebRTC大会火爆上演,网易云信谈音视频研发三大突破点
- git reset 回退以前某个版本_远程仓库版本回退方法--Git(二)
- ppt上的倒计时小工具_办公小技巧:轻松玩转PPT秒针倒计时
- 数据持久化------Archiving(归档,解档)
- 现代软件工程 第五章 【团队和流程】练习与讨论
- sparkR介绍及安装
- oracle+rac+ogg部署,RAC环境下配置OGG同步
- python-装饰器的使用详解
- python如何将数据写入excel_使用python将数据写入excel
- iOS-Core-Animation-Advanced-Techniques(一)
- 执行matlab 部分程序
- 千锋教育威哥学Java——爆破专栏丨Spring Security系列教程之解决Spring Security环境中的跨域问题
- 汇编语言-CPU如何区分指令和数据
- 如何优雅的研究 RGSS3 (三) 调整窗口的细节
- 网站ftp上传工具,六款值得你去使用的网站ftp上传工具
- 【STM32】通用定时器的PWM输出(实例:PWM输出)
热门文章
- 嵌入式常用裸机编程框架
- FileOutputStream方法创建文件并写入数值
- 三、非编码体细胞突变肿瘤基因组学 -- 突变暗物质(Analyses of non-coding somatic drivers in 2,658 cancer whole genomes)
- 二分法查找——绝对值最小的数
- 工行u盾显示316_工行U盾无法被电脑识别(方法全集)
- 100部最佳美国影片
- Fluent材料属性之比热容计算方法
- 计算机配置时能关机吗,怎么设置时间让电脑自动关机?
- Java中涉及到和金钱有关的属性的类型
- 什么是青藤零域·微隔离安全平台?