一.简述

  ...由于链表在空间的合理利用上和插入、删除时不需要移动等的优点,因此在很多场合下,它是线性表的首选存储结构。然而,它也存在着实现某些基本操作,如求线性表的长度时不如顺序存储结构的缺点;另一方面,由于在链表中,结点之间的关系用指针来表示,则数据元素在线性表中的“位序”的概念已经淡化,而被数据元素在线性链表中的“位置”所代替。为此,从实际应用的角度重新定义线性链表及其基本操作。....(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重新定义线性链表及其基本操作的更多相关文章

  1. 数据结构算法C语言实现(六)---2.4一元多项式的表示及相加

    一.简述 利用链表表示稀疏多项式,并基于之前的一些操作(编程实现上还是有所不同的)组合新的操作实现一元多项式的表示及相加. 二.ADT 抽象数据类型一元多项式的定义 ADT Polyomail{ 数据 ...

  2. 数据结构算法C语言实现(一)---2.2线性表的顺序表示和实现

    注意: 虽然是用C语言实现,但是考虑到使用了一个C++的特性----引用以简化代码,所以所有的代码均以cpp作为后缀,用g++编译(以后不做说明). g++版本: 一.简述 本节主要讲述线性表的顺序实 ...

  3. 数据结构算法C语言实现(八)--- 3.2栈的应用举例:迷宫求解与表达式求值

    一.简介 迷宫求解:类似图的DFS.具体的算法思路可以参考书上的50.51页,不过书上只说了粗略的算法,实现起来还是有很多细节需要注意.大多数只是给了个抽象的名字,甚至参数类型,返回值也没说的很清楚, ...

  4. 数据结构算法C语言实现(十二)--- 3.4循环队列&队列的顺序表示和实现

    一.简述 空队列的处理方法:1.另设一个标志位以区别队列是空还是满:2.少用一个元素空间,约定以队列头指针在队尾指针下一位置上作为队列呈满的状态的标志. 二.头文件 //3_4_part1.h /** ...

  5. 数据结构算法C语言实现(十)--- 3.3栈与递归的实现

    一.简介 汉诺塔问题是递归的一个典型例子,而且书上的讲解很详细,对理解C语言函数及函数传参的工作机制很有帮助,值得一看.而且,递归在我看来和分治.DP.贪心等一样是十分优美的思想,值得学习!!! 二. ...

  6. 数据结构算法C语言实现(七)--- 3.1栈的线性实现及应用举例

    一.简述 栈,LIFO.是操作受限的线性表,和线性表一样有两种存储表示方法.下面以顺序存储为例,实现. 二.ADT 暂无. 三.头文件 //3_1.h /** author:zhaoyu email: ...

  7. 数据结构算法C语言实现(二)---2.3线性表的链式表示和实现之单链表

    一.简述 [暂无] 二.头文件 #ifndef _2_3_part1_H_ #define _2_3_part1_H_ //2_3_part1.h /** author:zhaoyu email:zh ...

  8. 数据结构算法C语言实现(二十七)--- 7.2图的遍历

    一.简述 栈与队列,DFS与BFS.仅以连接表为例实现. 二.头文件 BFS要用到的头文件 //3_4_part1.h /** author:zhaoyu email:zhaoyu1995.com@g ...

  9. 数据结构算法C语言实现(二十)--- 6.3.1遍历二叉树

    一.简述 二叉树的遍历主要是先序.中序.后序及对应的递归和非递归算法,共3x2=6种,其中后序非递归在实现上稍复杂一些.二叉树的遍历是理解和学习递归及体会栈的工作原理的绝佳工具! 此外,非递归所用的栈 ...

随机推荐

  1. ReactNative真机运行运行

    注意在iOS设备上运行React Native应用需要一个Apple Developer account并且把你的设备注册为测试设备.本向导只包含React Native相关的主题. 译注:从XCod ...

  2. 创建pathing jar

    pathing jar是一个特殊的jar: 该jar文件只包含manifest.mf文件 该manifest文件只包含Class-Path,列出了所有需要真正加到classpath中的jar,或者di ...

  3. 玉伯的一道课后题题解(关于 IEEE 754 双精度浮点型精度损失)

    前文 的最后给出了玉伯的一道课后题,今天我们来讲讲这题的思路. 题目是这样的: Number.MAX_VALUE + 1 == Number.MAX_VALUE; Number.MAX_VALUE + ...

  4. C#读取网络流,读取网络上的js文件

    写博客的目的就是让其他人少走弯路. C#读取网络上的流和js文件出现的问题 一开始看了今天博客园上的推荐文章,用C#+HtmlAgilityPack+XPath带你采集数据(以采集天气数据为例子),然 ...

  5. Python3 windows如何安装模块 setuptools

    下载的module解压后里面有setup.py文件,如果打开setup.py文件里面有这段代码: from setuptools import setup ... setup( ... 这种的都需要调 ...

  6. 解决问题:由于扩展配置问题而无法提供您请求的页面。如果该页面是脚本,请添加处理程序。如果应下载文件,请添加 MIME 映射。

    WindowServer2012服务器,添加角色安装完.netframework和iis之后,运行aspx页面就报如下错误: HTTP 错误 404.3 - Not Found 由于扩展配置问题而无法 ...

  7. Collections的应用

    Collection : 接口  Collections : 集合的工具类    Arrays (数组的工具类)  只能操作list集合    说出Collection和Collections 的区别 ...

  8. Java网络编程——TCP/UDP

    UDP:面向无连接 ☆ 将数据及源地址和目的地址封装成数据包中 ☆ 每个数据报的大小限制在64K ☆ 不可靠协议 ☆ 不需要建立连接,速度快 TCP:面向有连接 ☆ 建立连接,形成传输数据的通道 ☆ ...

  9. JVM学习之jstat使用方法

    Jstat是JDK自带的一个轻量级工具,主要用JVM内建的指令对java应用程序的资源和性能进行实时的监控. 基本语法 jstat <option> [-t] [-h] <pid&g ...

  10. elasticsearch-查询基础篇

    elasticsearch的查询有两部分组成:query and filter. 两者的主要区别在于:filter是不计算相关性的,同时可以cache.因此,filter速度要快于query. 先记录 ...