数据结构算法C语言实现(五)---2.3重新定义线性链表及其基本操作
一.简述
...由于链表在空间的合理利用上和插入、删除时不需要移动等的优点,因此在很多场合下,它是线性表的首选存储结构。然而,它也存在着实现某些基本操作,如求线性表的长度时不如顺序存储结构的缺点;另一方面,由于在链表中,结点之间的关系用指针来表示,则数据元素在线性表中的“位序”的概念已经淡化,而被数据元素在线性链表中的“位置”所代替。为此,从实际应用的角度重新定义线性链表及其基本操作。....(Page37)
此外,书上一些地方我认为存在错误,所以写代码时做了修改和注释。并且,由于一些基本操作书中没有具体使用的实例,所以我只实现了算法2.20和算法2.21中出现的基本操作,其他操作会在需要的时候 再做实现。
二.头文件
//LinkList.h
/**
《数据结构(C语言版)》 Page 37
....为此,从实际应用角度出发重新定义线性链表及其基本操作....
*/
/**
author:zhaoyu
email:zhaoyu1995.com@gmail.com
date:2016-6-4
note:realize my textbook <<数据结构(C语言版)>>
*/
#ifndef _LINKLIST_H_
#define _LINKLIST_H_
#include "head.h"
#include <cstdlib>
#define ElemType int
typedef struct LNode{
ElemType data;
struct LNode *next;
}*Link, *Position;
typedef struct{//链表类型
Link head, tail;//分别指向线性链表中的头结点和最后一个结点
int len;//指示线性链表中数据元素的个数
}LinkList;
Status MakeNode(Link &p, ElemType e)
{
//分配由 p 指向的值为 e 的结点,并返回 OK;若分配失败,则返回 ERROR
p = (Link)malloc(sizeof(struct LNode));
if (!p)
{
return ERROR;
}
p->data = e;
p->next = NULL;
return OK;
}
Status FreeNode(Link &p)
{
//释放 p 所指节点
p = NULL;//便于回收???释放后再次使用
free(p);
}
Status InitList(LinkList &L)
{
//构造一个空的线性表L
L.head = (Link)malloc(sizeof(struct LNode));
L.head->data = ;
L.head->next = NULL;
L.tail = L.head->next;
L.len = ;
}
Status ClearList(LinkList &L)
{
//将线性链表置为空表并释放原链表的结点空间
}
Status InsFirst(LinkList &L, Link &h, Link &s)
{
//已知 h 指向线性链表的头结点,将 s 所指节点插入在第一个结点之前
//note:这里的参数与书上有些不一样,LinkList &L是我添加的
//因为插入新的元素之后,链表长度应该同步变化
//链表的插入是基于地址的,所以我全部加了引用
//这一个函数与书上参数完全不同
//更新 2016-5-5 16:46
//通过分析算法2.20发现 h 不是绝对的头结点,而是接受一个 h
//就以它为头结点作参考操作其它元素
//这个函数花了不少时间,值得反复思考
if (NULL == h)
{
return ERROR;
}
else
{
s->next = h->next;
h->next = s;
}
L.len++;
return OK;
}
Status DelFirst(Link &h, Link &q)
{
//已知 h 指向线性链表的头结点,删除链表中的第一个节点并以 q 返回
if (h == NULL)
{
return ERROR;
}
q = h->next;
h->next = q->next;
q->next = NULL;
return OK;
}
Status Append(LinkList &L, Link &s)
{
//将指针 s 所指(彼此以指针相链)的一串结点
//链接在线性链表 L 最后一个结点
Link q = L.head;
while (q->next != NULL)
{
q = q->next;
}
q->next = s;
int cnt = ;
Link temp = s;
while (temp != NULL)
{
cnt++;
if (NULL == temp->next)
{
L.tail = temp;//注意更新尾指针
}
temp = temp->next;
} L.len += cnt;
//注意要根据这一串结点长度增加链表长度
return OK;
}
Status Remove(LinkList &L, Link &q)
{
//删除线性链表 L 中的尾结点并以 q 返回,改变链表的尾指针指向新的尾结点
}
Status InsBefore(LinkList &L, Link &p, Link s)
{
//已知 p 指向线性链表 L 中的一个结点,将 s 所指结点插入 p 所指节点之前
//并修改指针 p 指向新插入的节点
}
Status InsAfter(LinkList &L, Link &p, Link s)
{
//已知 p 指向线性链表 L 中的一个结点,将 s 所指结点插入 p 所指节点之后
//并修改指针 p 指向新插入的节点
}
Status SetCurElem(Link &p, ElemType e)
{
//已知 p 指向线性链表中的一个结点,用 e 更新 p 所指结点中数据元素的值
}
ElemType GetCurElem(Link p)
{
//已知 p 指向线性链表中的一个节点,返回 p 所指结点中数据元素的值
if (p != NULL)
{
return p->data;
}
else
{
exit(ERROR);
}
}
Status ListEmpty(LinkList L)
{
//若线性链表 L 为空,则返回 TRUE,否则返回 FALSE
}
int ListLength(LinkList L)
{
//返回线性链表 L 中元素的个数 }
Position GetHead(LinkList L)
{
//返回线性链表 L 中头结点的位置
return L.head;
}
Position GetLast(LinkList L)
{
//返回线性链表 L 中最后一个结点的位置
}
Position PriorPos(LinkList L, Link p)
{
//已知 p 指向线性链表 L 中的一个结点,返回 p 所指结点直接前驱的位置
//若无前驱,则返回NULL
}
Position NextPos(LinkList L, Link p)
{
//已知 p 指向线性链表 L 中的一个节点,返回 p 所指结点
//的直接后继的位置,若无后继,返回 NULL
Link q = L.head;
while (q != NULL)
{
if(q == p)
{
return p->next;
}
q = q->next;
}
return NULL;
}
Status LocatePos(LinkList L, int i, Link &p)
{
//返回 p 指示线性链表 L 中第 i 个结点的位置并返回 OK
//i 值不合法时返回ERROR
int cnt = ;
p = L.head;
if (i > L.len || i < )
{
return ERROR;
}
while (cnt <= i)
{
p = p->next;
cnt++;
}
return OK; }
Position LocateElem(LinkList L, ElemType e, Status (* compare)(ElemType, ElemType))
{
//返回线性链表中第一个与 e 满足函数compare() 判定关系的元素的位置
//若不存在这样的元素,返回 NULL
}
Status ListTraverse(LinkList L, Status (* visit)())
{
//依次对 L 中每个元素调用函数 visit(),一旦visit() 失败,则操作失败。
}
/**
My Code
*/
void PrintList(LinkList L)
{
Link p = L.head->next;
int cnt = ;
while (p != NULL && cnt <= L.len)
{
printf("%d\t", p->data);
p = p->next;
cnt++;
}
printf("\n");
}
int compare(ElemType a, ElemType b)
{
if (a < b)
{
return -;
}
else if (a == b)
{
return ;
}
else
{
return ;
}
}
#endif
三.CPP文件
//LinkList.h
/**
《数据结构(C语言版)》 Page 37
....为此,从实际应用角度出发重新定义线性链表及其基本操作....
*/
/**
author:zhaoyu
email:zhaoyu1995.com@gmail.com
date:2016-6-4
note:realize my textbook <<数据结构(C语言版)>>
*/
#ifndef _LINKLIST_H_
#define _LINKLIST_H_
#include "head.h"
#include <cstdlib>
#define ElemType int
typedef struct LNode{
ElemType data;
struct LNode *next;
}*Link, *Position;
typedef struct{//链表类型
Link head, tail;//分别指向线性链表中的头结点和最后一个结点
int len;//指示线性链表中数据元素的个数
}LinkList;
Status MakeNode(Link &p, ElemType e)
{
//分配由 p 指向的值为 e 的结点,并返回 OK;若分配失败,则返回 ERROR
p = (Link)malloc(sizeof(struct LNode));
if (!p)
{
return ERROR;
}
p->data = e;
p->next = NULL;
return OK;
}
Status FreeNode(Link &p)
{
//释放 p 所指节点
p = NULL;//便于回收???释放后再次使用
free(p);
}
Status InitList(LinkList &L)
{
//构造一个空的线性表L
L.head = (Link)malloc(sizeof(struct LNode));
L.head->data = ;
L.head->next = NULL;
L.tail = L.head->next;
L.len = ;
}
Status ClearList(LinkList &L)
{
//将线性链表置为空表并释放原链表的结点空间
}
Status InsFirst(LinkList &L, Link &h, Link &s)
{
//已知 h 指向线性链表的头结点,将 s 所指节点插入在第一个结点之前
//note:这里的参数与书上有些不一样,LinkList &L是我添加的
//因为插入新的元素之后,链表长度应该同步变化
//链表的插入是基于地址的,所以我全部加了引用
//这一个函数与书上参数完全不同
//更新 2016-5-5 16:46
//通过分析算法2.20发现 h 不是绝对的头结点,而是接受一个 h
//就以它为头结点作参考操作其它元素
//这个函数花了不少时间,值得反复思考
if (NULL == h)
{
return ERROR;
}
else
{
s->next = h->next;
h->next = s;
}
L.len++;
return OK;
}
Status DelFirst(Link &h, Link &q)
{
//已知 h 指向线性链表的头结点,删除链表中的第一个节点并以 q 返回
if (h == NULL)
{
return ERROR;
}
q = h->next;
h->next = q->next;
q->next = NULL;
return OK;
}
Status Append(LinkList &L, Link &s)
{
//将指针 s 所指(彼此以指针相链)的一串结点
//链接在线性链表 L 最后一个结点
Link q = L.head;
while (q->next != NULL)
{
q = q->next;
}
q->next = s;
int cnt = ;
Link temp = s;
while (temp != NULL)
{
cnt++;
temp = temp->next;
if (NULL == temp->next)
{
L.tail = temp;//注意更新尾指针
}
} L.len += cnt;
//注意要根据这一串结点长度增加链表长度
return OK;
}
Status Remove(LinkList &L, Link &q)
{
//删除线性链表 L 中的尾结点并以 q 返回,改变链表的尾指针指向新的尾结点
}
Status InsBefore(LinkList &L, Link &p, Link s)
{
//已知 p 指向线性链表 L 中的一个结点,将 s 所指结点插入 p 所指节点之前
//并修改指针 p 指向新插入的节点
}
Status InsAfter(LinkList &L, Link &p, Link s)
{
//已知 p 指向线性链表 L 中的一个结点,将 s 所指结点插入 p 所指节点之后
//并修改指针 p 指向新插入的节点
}
Status SetCurElem(Link &p, ElemType e)
{
//已知 p 指向线性链表中的一个结点,用 e 更新 p 所指结点中数据元素的值
}
ElemType GetCurElem(Link p)
{
//已知 p 指向线性链表中的一个节点,返回 p 所指结点中数据元素的值
if (p != NULL)
{
return p->data;
}
else
{
exit(ERROR);
}
}
Status ListEmpty(LinkList L)
{
//若线性链表 L 为空,则返回 TRUE,否则返回 FALSE
}
int ListLength(LinkList L)
{
//返回线性链表 L 中元素的个数 }
Position GetHead(LinkList L)
{
//返回线性链表 L 中头结点的位置
return L.head;
}
Position GetLast(LinkList L)
{
//返回线性链表 L 中最后一个结点的位置
}
Position PriorPos(LinkList L, Link p)
{
//已知 p 指向线性链表 L 中的一个结点,返回 p 所指结点直接前驱的位置
//若无前驱,则返回NULL
}
Position NextPos(LinkList L, Link p)
{
//已知 p 指向线性链表 L 中的一个节点,返回 p 所指结点
//的直接后继的位置,若无后继,返回 NULL
Link q = L.head;
while (q != NULL)
{
if(q == p)
{
return p->next;
}
q = q->next;
}
return NULL;
}
Status LocatePos(LinkList L, int i, Link &p)
{
//返回 p 指示线性链表 L 中第 i 个结点的位置并返回 OK
//i 值不合法时返回ERROR
int cnt = ;
p = L.head;
if (i > L.len || i < )
{
return ERROR;
}
while (cnt <= i)
{
p = p->next;
cnt++;
}
return OK; }
Position LocateElem(LinkList L, ElemType e, Status (* compare)(ElemType, ElemType))
{
//返回线性链表中第一个与 e 满足函数compare() 判定关系的元素的位置
//若不存在这样的元素,返回 NULL
}
Status ListTraverse(LinkList L, Status (* visit)())
{
//依次对 L 中每个元素调用函数 visit(),一旦visit() 失败,则操作失败。
}
/**
My Code
*/
void PrintList(LinkList L)
{
Link p = L.head->next;
int cnt = ;
while (p != NULL && cnt <= L.len)
{
printf("%d\t", p->data);
p = p->next;
cnt++;
}
printf("\n");
}
int compare(ElemType a, ElemType b)
{
if (a < b)
{
return -;
}
else if (a == b)
{
return ;
}
else
{
return ;
}
}
#endif
四.测试

数据结构算法C语言实现(五)---2.3重新定义线性链表及其基本操作的更多相关文章
- 数据结构算法C语言实现(六)---2.4一元多项式的表示及相加
一.简述 利用链表表示稀疏多项式,并基于之前的一些操作(编程实现上还是有所不同的)组合新的操作实现一元多项式的表示及相加. 二.ADT 抽象数据类型一元多项式的定义 ADT Polyomail{ 数据 ...
- 数据结构算法C语言实现(一)---2.2线性表的顺序表示和实现
注意: 虽然是用C语言实现,但是考虑到使用了一个C++的特性----引用以简化代码,所以所有的代码均以cpp作为后缀,用g++编译(以后不做说明). g++版本: 一.简述 本节主要讲述线性表的顺序实 ...
- 数据结构算法C语言实现(八)--- 3.2栈的应用举例:迷宫求解与表达式求值
一.简介 迷宫求解:类似图的DFS.具体的算法思路可以参考书上的50.51页,不过书上只说了粗略的算法,实现起来还是有很多细节需要注意.大多数只是给了个抽象的名字,甚至参数类型,返回值也没说的很清楚, ...
- 数据结构算法C语言实现(十二)--- 3.4循环队列&队列的顺序表示和实现
一.简述 空队列的处理方法:1.另设一个标志位以区别队列是空还是满:2.少用一个元素空间,约定以队列头指针在队尾指针下一位置上作为队列呈满的状态的标志. 二.头文件 //3_4_part1.h /** ...
- 数据结构算法C语言实现(十)--- 3.3栈与递归的实现
一.简介 汉诺塔问题是递归的一个典型例子,而且书上的讲解很详细,对理解C语言函数及函数传参的工作机制很有帮助,值得一看.而且,递归在我看来和分治.DP.贪心等一样是十分优美的思想,值得学习!!! 二. ...
- 数据结构算法C语言实现(七)--- 3.1栈的线性实现及应用举例
一.简述 栈,LIFO.是操作受限的线性表,和线性表一样有两种存储表示方法.下面以顺序存储为例,实现. 二.ADT 暂无. 三.头文件 //3_1.h /** author:zhaoyu email: ...
- 数据结构算法C语言实现(二)---2.3线性表的链式表示和实现之单链表
一.简述 [暂无] 二.头文件 #ifndef _2_3_part1_H_ #define _2_3_part1_H_ //2_3_part1.h /** author:zhaoyu email:zh ...
- 数据结构算法C语言实现(二十七)--- 7.2图的遍历
一.简述 栈与队列,DFS与BFS.仅以连接表为例实现. 二.头文件 BFS要用到的头文件 //3_4_part1.h /** author:zhaoyu email:zhaoyu1995.com@g ...
- 数据结构算法C语言实现(二十)--- 6.3.1遍历二叉树
一.简述 二叉树的遍历主要是先序.中序.后序及对应的递归和非递归算法,共3x2=6种,其中后序非递归在实现上稍复杂一些.二叉树的遍历是理解和学习递归及体会栈的工作原理的绝佳工具! 此外,非递归所用的栈 ...
随机推荐
- java JAXB 学习
JAXB(Java Architecture for XML Binding)是JDK的一部分,用于Object <-> XML的转换(有点类似于.NET中的XML序列化). 1.创建XS ...
- ubuntu-12.10-server中打开终端的方式
ubuntu-12.10-server系统在图形界面的任务栏上找不到终端的踪影,可以使用以下两种方式调出 1.在图形界面中点击Dash Home 点击后搜索terminal即可 2.可以通过快捷键CT ...
- .clear 万能清除浮动
html body div.clear, html body span.clear { background: none; border: 0; clear: both; display: block ...
- 更好的逐帧动画函数 — requestAnimationFrame 简介
本文将会简单讲讲 requestAnimationFrame 函数的用法,与 setTimeout/setInterval 的区别和联系,以及当标签页隐藏时 requestAnimationFrame ...
- 如何用 fiddler 捕获 https 请求
安装完 Fiddler 后,我们每次打开浏览器输入 url,Fiddler 便会捕获到我们的 http 请求(Fiddler 是以代理 web 服务器的形式工作的,它使用代理地址:127.0.0.1, ...
- WordPress使用固定链接
WordPress安装后我们会发现,文章默认的url是很丑的,http://example.com/?p=N,其中N是文章ID,一串数字.默认链接在所有的环境下都运转良好,但和其他的类型比起来却没那么 ...
- ModernUI教程:处理内容导航事件
Modern UI包含了一个机遇uri的内容导航框架用来处理区域加载.卸载和处理访问记录页面间的导航. 如果你希望你的页面具有这些处理事件,你需要继承一个IContent接口,该接口位于FirstFl ...
- 在nginx中配置如何防止直接用ip访问服务器web server及server_name特性讲解
看了很多nginx的配置,好像都忽略了ip直接访问web的问题,不利于SEO优化,所以我们希望可以避免直接用IP访问网站,而是域名访问,具体怎么做呢,看下面. 官方文档中提供的方法: If you d ...
- c/c++模板的定义和实现分开的问题及其解决方案
注意c/c++模板的定义和实现- - 定义一个类一般都是在头文件中进行类声明,在cpp文件中实现,但使用模板时应注意目前的C ...
- Yii2初级入门教程
下载安装 Yii挺火的,也是MVC的Web框架.国内占有率,相当不错.值得一学. 网络上提供了两个版本模板的下载, advanced, 和 basic, 使用起来一致, 提供的模块支持不同. Adva ...