当前位置: 首页 > wzjs >正文

大学营销型网站建设实训课程搭建集团网站

大学营销型网站建设实训课程,搭建集团网站,开发一个app的步骤,公共空间设计网站目录 一、链表的分类 1. 单向或者双向 2. 带头或者不带头 3. 循环或者非循环 二、双向链表 1.双向链表内部定义 2.双向链表的初始化(void LTPrint(LTNode* phead);) 3.双向链表的销毁(void LTDataDestroy(LTNode* phead);&#xff09…

目录

一、链表的分类

1. 单向或者双向

2. 带头或者不带头

3. 循环或者非循环

二、双向链表

1.双向链表内部定义

2.双向链表的初始化(void LTPrint(LTNode* phead);)

3.双向链表的销毁(void LTDataDestroy(LTNode* phead);)

4.双向链表的尾插(void LTPushBack(LTNode* phead, LTDataType x);)

5.判断链表是否为空(bool LTEmpty(LTNode* phead);)

6.双向链表的尾删(void LTPopBack(LTNode* phead);)

7.双向链表的头插( void LTPushFront(LTNode* phead, LTDataType x); )

8.双向链表的头删(void LTPopFront(LTNode* phead);)

9.双向链表的查找(LTNode* LTFind(LTNode* phead, LTDataType x);)

10.双向链表的删除(void LTErase(LTNode* pos);)

11.双向链表在pos位置之前插入一个值(void LTInsert(LTNode* pos,LTDataType x);)

三、双向链表的完整代码

List.h

List.c

test.c

四、顺序表和链表的对比

一、链表的分类

实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:

1. 单向或者双向

2. 带头或者不带头

带头的为哨兵位置头结点,特点:不存储有效数据 优点:插入数据时不需要探空

3. 循环或者非循环

虽然有这么多的链表的结构,但是我们实际中最常用还是两种结构:

1. 无头单向非循环链表: 结构简单 ,一般不会单独用来存数据。实际中更多是作为 其他数据结
构的子结构 ,如哈希桶、图的邻接表等等。另外这种结构在 笔试面试 中出现很多。
2. 带头双向循环链表: 结构最复杂 ,一般用在单独存储数据。实际中使用的链表数据结构,都
是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带
来很多优势,实现反而简单了,后面我们代码实现了就知道了。

二、双向链表

1.双向链表内部定义

#pragma once
typedef int LTDataType;
typedef struct ListNode
{struct ListNode* next;struct ListNode* prev;LTDataType data;
}LTNode;

2.双向链表的初始化(void LTPrint(LTNode* phead);)

//双链表的初始化
LTNode* LTInit()
{LTNode* phead = BuyListNode(-1);phead->next = phead;phead->prev = phead;return phead;
}

3.双向链表的销毁(void LTDataDestroy(LTNode* phead);)

// 双链表的销毁
void LTDataDestroy(LTNode* phead) {assert(phead);  // 确保头节点不为空LTNode* cur = phead->next;  // 从第一个节点开始while (cur != phead) {      // 遍历链表,直到回到头节点LTNode* next = cur->next;  // 保存下一个节点free(cur);                 // 释放当前节点cur = next;                // 移动到下一个节点}free(phead);  // 释放头节点phead = NULL; // 将头节点指针置为 NULL(注意:这里只是局部修改,外部需要手动置空)
}

4.双向链表的尾插(void LTPushBack(LTNode* phead, LTDataType x);)

//双链表的尾插
void LTPushBack(LTNode* phead, LTDataType x)
{LTNode* newnode = BuyListNode(x);LTNode* tail = phead->prev;//phead           tail  newnodetail->next = newnode;newnode->prev = tail;newnode->next = phead;phead->prev = newnode;tail = tail->next;
}

这里不需要用二级指针,因为这个函数里面没有修改phead的值,因为有哨兵结点,那么就不需要考虑链表为空的情况,这里对比单链表的尾插:在单链表的尾插中如果链表为空那么就有一个这个操作:*pphead = newnode;这里修改了形参的值那么就必须传递二级指针

void SLTPushBack(SLTNode** pphead, SLTDataType x)
{SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));if (newnode == NULL){perror("malloc fail");}newnode->data = x;newnode->Next = NULL;if (*pphead == NULL){*pphead = newnode;}。else{//找尾SLTNode* tail = *pphead;while (tail->Next != NULL){tail = tail->Next;}tail->Next = newnode;}

5.判断链表是否为空(bool LTEmpty(LTNode* phead);)

//判断链表是否为空
bool LTEmpty(LTNode* phead)
{assert(phead);return phead->next == phead;//等价于/*if (phead->next == phead){return true;}else{return false;}*/
}

6.双向链表的尾删(void LTPopBack(LTNode* phead);)

//判断链表是否为空
bool LTEmpty(LTNode* phead)
{assert(phead);return phead->next == phead;//等价于/*if (phead->next == phead){return true;}else{return false;}*/
}

7.双向链表的头插( void LTPushFront(LTNode* phead, LTDataType x); )

双链表的头插需要注意,不要一上来就phead->next=newnode  newnode->pre=phead;这样就不能找到原来的第一个了

//双链表的头插
void LTPushFront(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode = BuyListNode(x);newnode->next = phead->next;//newnode->next要指向d1,d1就是phead->nextphead->next->prev = newnode;phead->next = newnode;newnode->prev = phead;
}

8.双向链表的头删(void LTPopFront(LTNode* phead);)

//双链表的头删
void LTPopFront(LTNode* phead)
{assert(phead);assert(!LTEmpty(phead));LTNode* head = phead->next;LTNode* headnext = head->next;phead->next = headnext;head->prev = phead;free(head);head = NULL;
}

9.双向链表的查找(LTNode* LTFind(LTNode* phead, LTDataType x);)

//双链表的查找
LTNode* LTFind(LTNode* phead, LTDataType x)
{assert(phead);LTNode* cur = phead->next;//不能从哨兵位开始走,一定要从哨兵位的下一位开始走while (cur != phead){if (cur->data = x){return cur;}cur = cur->next;}return NULL;
}

10.双向链表的删除(void LTErase(LTNode* pos);)

//删除
void LTErase(LTNode* pos)
{//prev   pos   nextassert(pos);LTNode* p = pos->prev;LTNode* n = pos->next;p->next = n;n->prev = p;free(pos);pos = NULL;//这行代码其实没有特别大的意义
}

11.双向链表在pos位置之前插入一个值(void LTInsert(LTNode* pos,LTDataType x);)

//在pos位置之前插入一个值
void LTInsert(LTNode* pos,LTDataType x)
{assert(pos);LTNode* prev = pos->next;LTNode* newnode = BuyListNode(x);//prev   newnode    posprev->next = newnode;newnode->prev = prev;newnode->next = pos;pos->prev = newnode;
}

思考一个问题:有了Insert还需不需要头插?

答:不用 LTInsert(phead->next,x)就是头插,尾插也一样LTInsert(phead,x)

三、双向链表的完整代码

List.h

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<errno.h>
#include<stdbool.h>
typedef int LTDataType;
typedef struct ListNode
{struct ListNode* next;struct ListNode* prev;LTDataType data;
}LTNode;
//双链表的打印
void LTPrint(LTNode* phead);
//双链表的初始化
LTNode* LTInit();
//双链表的销毁
void LTDataDestroy(LTNode* phead);
//双链表的尾插
void LTPushBack(LTNode* phead, LTDataType x);
//双链表的尾删
void LTPopBack(LTNode* phead);
//判断链表是否为空
bool LTEmpty(LTNode* phead);
//双链表的头插
void LTPushFront(LTNode* phead, LTDataType x);
//双链表的头删
void LTPopFront(LTNode* phead);
//在pos位置之前插入一个值
void LTInsert(LTNode* pos,LTDataType x);
//删除
void LTErase(LTNode* pos);
//双链表的查找
LTNode* LTFind(LTNode* phead, LTDataType x);

List.c

#include"List.h"
LTNode* BuyListNode(LTDataType x)
{LTNode* node = (LTNode*)malloc(sizeof(LTNode));if (node == NULL){perror("malloc fail");return NULL;}node->next = NULL;node->prev = NULL;node->data = x;return node;
}
//双链表的打印
void LTPrint(LTNode* phead)
{assert(phead);LTNode* cur = phead->next;while (cur != phead){printf("%d<->", cur->data);cur = cur->next;}
}
//双链表的初始化
LTNode* LTInit()
{LTNode* phead = BuyListNode(-1);phead->next = phead;phead->prev = phead;return phead;
}
// 双链表的销毁
void LTDataDestroy(LTNode* phead) {assert(phead);  // 确保头节点不为空LTNode* cur = phead->next;  // 从第一个节点开始while (cur != phead) {      // 遍历链表,直到回到头节点LTNode* next = cur->next;  // 保存下一个节点free(cur);                 // 释放当前节点cur = next;                // 移动到下一个节点}free(phead);  // 释放头节点phead = NULL; // 将头节点指针置为 NULL(注意:这里只是局部修改,外部需要手动置空)
}
//双链表的尾插
void LTPushBack(LTNode* phead, LTDataType x)
{LTNode* newnode = BuyListNode(x);LTNode* tail = phead->prev;//phead           tail  newnodetail->next = newnode;newnode->prev = tail;newnode->next = phead;phead->prev = newnode;tail = tail->next;//这里不需要用二级指针// 用二级指针是因为要改变结构体里面的指针// 而双链表改的都是结构体里面的变量,用结构体的指针即可//
}
//判断链表是否为空
bool LTEmpty(LTNode* phead)
{assert(phead);return phead->next == phead;//等价于/*if (phead->next == phead){return true;}else{return false;}*/
}
//双链表的尾删
void LTPopBack(LTNode* phead)
{//找到尾和尾的前一个,让尾的前一个称为新的尾,不需要遍历assert(phead);assert(!LTEmpty(phead));LTNode* tail=phead -> prev;LTNode* tailprev = tail->prev;tailprev->next = phead;phead->prev = tailprev;free(tail);tail = NULL;
}
//双链表的头插
void LTPushFront(LTNode* phead, LTDataType x)
{//双链表的头插需要注意,不要一上来就phead->next=newnode  newnode->pre=phead;这样就不能找到原来的第一个了assert(phead);LTNode* newnode = BuyListNode(x);newnode->next = phead->next;//newnode->next要指向d1,d1就是phead->nextphead->next->prev = newnode;phead->next = newnode;newnode->prev = phead;
}
//双链表的头删
void LTPopFront(LTNode* phead)
{assert(phead);assert(!LTEmpty(phead));LTNode* head = phead->next;LTNode* headnext = head->next;phead->next = headnext;head->prev = phead;free(head);head = NULL;
}
//在pos位置之前插入一个值
void LTInsert(LTNode* pos,LTDataType x)
{assert(pos);LTNode* prev = pos->next;LTNode* newnode = BuyListNode(x);//prev   newnode    posprev->next = newnode;newnode->prev = prev;newnode->next = pos;pos->prev = newnode;
}//思考一个问题:有了Insert还需不需要头插?答:不用 LTInsert(phead->next,x)就是头插,尾插也一样LTInsert(phead,x)
//删除
void LTErase(LTNode* pos)
{//prev   pos   nextassert(pos);LTNode* p = pos->prev;LTNode* n = pos->next;p->next = n;n->prev = p;free(pos);pos = NULL;//这行代码其实没有特别大的意义
}
//双链表的查找
LTNode* LTFind(LTNode* phead, LTDataType x)
{assert(phead);LTNode* cur = phead->next;//不能从哨兵位开始走,一定要从哨兵位的下一位开始走while (cur != phead){if (cur->data = x){return cur;}cur = cur->next;}return NULL;
}

test.c

#include"List.h"
void TestList1()
{LTNode* plist = LTInit();//尾插测试LTPushBack(plist,1);LTPushBack(plist,2);LTPushBack(plist,3);LTPushBack(plist,4);LTPrint(plist);//尾删测试printf("\n");LTPopBack(plist);LTPopBack(plist);LTPrint(plist);//头插测试printf("\n");LTPushFront(plist,5);LTPushFront(plist,8);LTPrint(plist);//头删测试printf("\n");LTPopFront(plist);LTPrint(plist);
}
int main()
{TestList1();return 0;
}

四、顺序表和链表的对比

顺序表和链表的对比
不同点
顺序表
链表
存储空间上
物理上一定连续
逻辑上连续,但物理上不一定
连续
随机访问
支持O(n)不支持O(n)
任意位置插入或者删除
元素
可能需要搬移元素,效率低
O(N)
只需修改指针指向
插入
动态顺序表,空间不够时需要 扩容
没有容量的概念
应用场景
元素高效存储 + 频繁访问
任意位置插入和删除频繁
缓存利用率

http://www.dtcms.com/wzjs/542305.html

相关文章:

  • jsp 网站开发教程做照片模板下载网站好
  • 最新新闻热点事件2023年4月厦门百度seo排名
  • 手机网站跟pc网站有什么不同百度网站建设哪家公司好
  • 华为官方商城网站建设方案进入网站前如何做环境检测
  • 门户网站建设技术要求joomla wordpress drupal
  • 什么是网站组件招标网址
  • 天蝎网站推广优化微网站后台录入
  • 湖州 网站建设中文 wordpress插件
  • 大连网站建设仟亿单位做好安全生产举报奖励宣传工作的总结
  • 网站建设需求调研计划表珠海市建设工程质量监督检测站网站
  • 求生之路2怎么做非官方网站重庆seo网络推广关键词
  • 网站注册免费永久广州市建设局官方网站
  • wordpress需要伪静态吗优化师培训
  • wordpress网站维护如何自己建一个微网站
  • 久安网络微信网站建设免费咨询妇科医生在线
  • 电大网上作业代做网站wordpress 迁移 新目录
  • 网站建设服务合同需要哪些资料建设一个公司网站需要什么知识
  • 做优惠卷网站倒闭了多少境外网址app
  • 部队网站建设招标全国企业信息网上公示系统
  • 网站建设开发方式包括一l丫wordpress批量定时发布
  • 网站建设与网页设计案例教程 重庆大学出版社西宁网站建设开发公司
  • 景征网站建设如何制作个人网页页
  • 汕头网站推广费用百度抓取网站图片
  • 龙文国土局漳滨村新农村建设网站自建站电商外贸
  • 网站如何推广运营官网大全
  • anker 网站建设wordpress男性模板
  • 网站qq 微信分享怎么做的wordpress图片优化插件
  • 珍岛做网站怎么样wordpress计划本
  • 绵阳建设局网站十大高端网站设计
  • 开发手机网站在深圳帮人做网站