一.简述

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

    Unique Binary Search Trees II Given n, generate all structurally unique BST's (binary search trees) ...

  2. lecture15-自动编码器、语义哈希、图像检索

    Hinton第15课,本节有课外读物<Semantic Hashing>和<Using Very Deep Autoencoders for Content-Based Image ...

  3. Theano1.1-安装

    之前一直想弄theano,可是python不是很懂,在学习了一段时间之后开始安装theano.当然官网上的安装资料是全,可是也太繁琐了.这里介绍的是最简单,最方面的安装theano的方法.官网首页:h ...

  4. Tensorflow学习笔记4:分布式Tensorflow

    简介 Tensorflow API提供了Cluster.Server以及Supervisor来支持模型的分布式训练. 关于Tensorflow的分布式训练介绍可以参考Distributed Tenso ...

  5. AMDJS编译工具

    amdjs-build可以将amdjs标准的js代码编译成原生的js代码,从而在发布时去除多余的模块加载器代码. 比如像这样的代码: define("a/b", ["b& ...

  6. ASP.NET Web API 安全验证之摘要(Digest)认证

    在基本认证的方式中,主要的安全问题来自于用户信息的明文传输,而在摘要认证中,主要通过一些手段避免了此问题,大大增加了安全性. 1.客户端匿名的方式请求 (无认证) HTTP/ Unauthorized ...

  7. [BZOJ1564][NOI2009]二叉查找树(区间DP)

    题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1564 分析: 首先因为每个点的数据值不变,所以无论树的形态如何变,树的中序遍历肯定不变 ...

  8. Firefox about

    在firefox的地址栏输入about:about,然后看一下各个链接.有的链接有具体的用途,有的链接疯言疯语,并无软用. about:about集中了火狐浏览器的全部用户界面,平时常见的prefer ...

  9. morris的用法

    參數選項說明: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 ...

  10. Linux(Ubuntu)下如何安装JDK

    一.下载 首先,当然是要下载了. 按照需要选择不同的版本.笔者选择的是 jdk-7u45,如图: 二. 解压 将下载下来的 .tar.gz 文件解压. 使用如下命令解压: sudo tar zxvf ...