1.给出提高要求2的函数实现
/*
* 函数名称: Concatenate
* 输 入:source,target
*source:需要连接的对象
*target:被连接的对象
* 输 出:
* 功能描述: 将对象source连接到单链表target的尾部
* 作 者:吴友强
* 日 期:2009年10月13日
* 修 改:
* 日 期:
*/
template <class T>
void Concatenate(LinkList<T>& target, LinkList<T>& source)
{
ListNode<T> *q = source.head;
while (q->next != NULL)
{
target.Insert(q->next->data, target.size);
q = q->next;
}
}
注意事项:实现时不要直接把两个链表连接起来就好了,这样造成同一块内存会释放两遍,造成运行完时报错,其实就是析构函数中出错。
而是需要用要到深拷贝的原理实现,就是取出source的数据插入到target中。上一篇中以给出测试程序。
2.提高要求2的实现:说明:本来只是修改上一篇中某些函数的实现就可以了,但是作为程序的完整性我在这里也全部给出
(1)ListNode.h结点类:
/*
* Copyright (c) 2009,FreshAir团队嵌入式软件研发组
* All rights reserved.
*
* 文件名称:ListNode.h
* 摘 要:节点类的定义
*
* 当前版本:1.0
* 作 者:吴友强
* 完成日期:2009年10月13日
*
* 取代版本:
* 原作者 :
* 完成日期:
*/
#include<iostream.h>
#include<stdio.h>
template<class T> class LinkList;//前视定义,否则,无法定义友元
template<class T> class ListNode
{
friend class LinkList<T>;//定义友元
private:
ListNode<T> *next;//指向下一个结点的指针
ListNode<T> *prev;//指向上一个结点的指针
public:
T data;
ListNode(ListNode<T> *ptrNext=NULL, ListNode<T> *ptrPrev=NULL);//构造函数,用于构造头结点
ListNode(const T& item, ListNode<T> *ptrNext, ListNode<T> *ptrPrev);//构造函数,非头结点
~ListNode() {};//析构函数
friend void Concatenate(LinkList<T>& target, LinkList<T>& souce);
};
template<class T>
ListNode<T>::ListNode(ListNode<T> *ptrNext, ListNode<T> *ptrPrev)
:next(ptrNext),prev(ptrPrev)
{
}
template<class T>
ListNode<T>::ListNode(const T &item, ListNode<T> *ptrNext, ListNode<T> *ptrPrev)
{
data = item;
next = ptrNext;
prev = ptrPrev;
}
(2)LinkList.h链表类定义与实现(双向循环链表):
/*
* Copyright (c) 2009,FreshAir团队嵌入式软件研发组
* All rights reserved.
*
* 文件名称:LinkList.h
* 摘 要:双向循环链表类的定义
*
* 当前版本:1.0
* 作 者:吴友强
* 完成日期:2009年10月13日
*
* 取代版本:
* 原作者 :
* 完成日期:
*/
#include "ListNode.h"
template <class T>
class LinkList
{
private:
ListNode<T> *head;//指向头结点的指针
int size;//单链表的元素个数
ListNode<T> *currPtr;//当前结点
public:
LinkList(void);//构造函数
~LinkList();//析构函数
//线性表操作要求的成员函数
int GetListSize(void) const;//返回链表的元素个数
int ListIsEmpty(void) const;//判断单链表是否为空
ListNode<T> *Index(int pos);//定位
void Insert(const T& item, int pos);//插入
T Delete(int pos);//删除
T GetData(int pos);//取元素
void ClearList(void);//清空链表
//遍历单链表的成员函数
ListNode<T> *Reset(int pos=0);//把第pos个结点设置为当前结点currPtr
ListNode<T> *Next(void);//currPtr指向下一个结点
int EndOfList(void) const;//currPtr是否指在链表尾
friend void Concatenate(LinkList<T>& target, LinkList<T>& souce);
};
/*
* Copyright (c) 2009,FreshAir团队嵌入式软件研发组
* All rights reserved.
*
* 文件名称:LinkList.cpp
* 摘 要:双向循环链表的各个功能函数的现实
*
* 当前版本:1.0
* 作 者:吴友强
* 完成日期:2009年10月13日
*
* 取代版本:
* 原作者 :
* 完成日期:
*/
template <class T>
LinkList<T>::LinkList(void)
{
size = 0;
head = new ListNode<T>();
head->next = head;
head->prev = head;
}
template <class T>
LinkList<T>::~LinkList()
{
ClearList();//释放所有非头结点的结点
delete head;//释放头结点
}
/*
* 函数名称: GetListSize
* 输 入:
* 输 出:
* 功能描述: 返回顺序表的元素个数size
* 作 者:吴友强
* 日 期:2009年10月13日
* 修 改:
* 日 期:
*/
template <class T>
int LinkList<T>::GetListSize(void) const
{
return size;
}
/*
* 函数名称: ListIsEmpty
* 输 入:
* 输 出:
* 功能描述: 判断是否为空,空返回1;非返回0
* 作 者:吴友强
* 日 期:2009年10月13日
* 修 改:
* 日 期:
*/
template <class T>
int LinkList<T>::ListIsEmpty(void) const
{
return size == 0 ? 1 : 0;
}
/*
* 函数名称: Index
* 输 入:pos
*pos:定位数据元素结点
* 输 出:
* 功能描述: 定位至第pos个数据元素结点,返回指向第pos个结点的指针
* 作 者:吴友强
* 日 期:2009年10月13日
* 修 改:
* 日 期:
*/
template <class T>
ListNode<T> *LinkList<T>::Index(int pos)
{
if (pos < -1 || pos > size)
{
cout << "参数pos越界出错!" << endl;
exit(0);
}
if (pos == -1)
{
return head;
}
ListNode<T> *p = head->next;
int i = 0;
while (p != NULL && i <pos)
{
p = p->next;
i++;
}
return p;
}
/*
* 函数名称: Insert
* 输 入:pos
*pos:插入数据元素结点的位置
*item:插入数据结点的数据
* 输 出:
* 功能描述: 在pos个结点之前插入一个data域为item的新结点
* 作 者:吴友强
* 日 期:2009年10月13日
* 修 改:
* 日 期:
*/
template <class T>
void LinkList<T>::Insert(const T& item, int pos)
{
if (pos < 0 || pos > size)
{
cout << "参数pos越界出错!" << endl;
exit(0);
}
ListNode<T> *p = Index(pos);
ListNode<T> *newNode = new ListNode<T>(item, NULL, NULL);
newNode->prev = p->prev;
newNode->next = p;
p->prev->next = newNode;
p->prev = newNode;
size++;
}
/*
* 函数名称: Delete
* 输 入:pos
*pos:删除数据元素结点的位置
* 输 出:
* 功能描述: 删除第pos个结点,并返回被删除结点的data
* 作 者:吴友强
* 日 期:2009年10月13日
* 修 改:
* 日 期:
*/
template <class T>
T LinkList<T>::Delete(int pos)
{
if (0 == size)
{
cout << "链表以空无元素可删!" << endl;
exit(0);
}
T temp;
if (pos < 0 || pos > size-1)
{
cout << "参数pos越界出错!" << endl;
exit(0);
}
ListNode<T> *p = Index(pos);
p->prev->next = p->next;
p->next->prev = p->prev;
temp = p->data;
delete p;
size--;
return temp;
}
/*
* 函数名称: ClearList
* 输 入:pos
*pos:删除数据元素结点的位置
* 输 出:
* 功能描述: 清空表为初始化状态
* 作 者:吴友强
* 日 期:2009年10月13日
* 修 改:
* 日 期:
*/
template <class T>
void LinkList<T>::ClearList(void)
{
ListNode<T> *p = head->next;
ListNode<T> *q;
while (p != head)
{
q = p;
p = p->next;
delete q;
}
size = 0;
}
/*
* 函数名称: Reset
* 输 入:pos
*pos:数据元素结点的位置
* 输 出:
* 功能描述: 使currPtr指向结点pos,并返回currPtr
* 作 者:吴友强
* 日 期:2009年10月13日
* 修 改:
* 日 期:
*/
template <class T>
ListNode<T> *LinkList<T>::Reset(int pos)
{
if (pos < -1 || pos > size - 1)
{
cout << "参数pos越界出错!" << endl;
exit(0);
}
if (pos == -1)
{
return head;
}
if (pos == 0)
{
currPtr = head->next;
}
else
{
currPtr = head->next;
ListNode<T> prevPtr = head;
for (int i=0; i<pos; i++)
{
prevPtr = currPtr;
currPtr = currPtr->next;
}
}
return currPtr;
}
/*
* 函数名称: Next
* 输 入:
* 输 出:
* 功能描述: 使currPtr指向下一个结点
* 作 者:吴友强
* 日 期:2009年10月13日
* 修 改:
* 日 期:
*/
template <class T>
ListNode<T> *LinkList<T>::Next(void)
{
if (currPtr != NULL)
{
currPtr = currPtr->next;
}
return currPtr;
}
/*
* 函数名称: EndOfList
* 输 入:
* 输 出:
* 功能描述: currPtr是否指在链表尾
* 作 者:吴友强
* 日 期:2009年10月13日
* 修 改:
* 日 期:
*/
template <class T>
int LinkList<T>::EndOfList(void) const
{
return currPtr == NULL ? 1 : 0;
}
/*
* 函数名称: GetData
* 输 入:pos
*pos:需要得到结点数据的位置
* 输 出:
* 功能描述: 获取pos处结点的数据
* 作 者:吴友强
* 日 期:2009年10月13日
* 修 改:
* 日 期:
*/
template <class T>
T LinkList<T>::GetData(int pos)
{
if (pos < 0 || pos > size-1)
{
cout << "参数pos越界出错!" << endl;
exit(0);
}
ListNode<T> *p = Index(pos);
return p->data;
}
/*
* 函数名称: Concatenate
* 输 入:source,target
*source:需要连接的对象
*target:被连接的对象
* 输 出:
* 功能描述: 将对象source连接到单链表target的尾部
* 作 者:吴友强
* 日 期:2009年10月13日
* 修 改:
* 日 期:
*/
template <class T>
void Concatenate(LinkList<T>& target, LinkList<T>& source)
{
ListNode<T> *q = source.head;
while (q->next != NULL)
{
target.Insert(q->next->data, target.size);
q = q->next;
}
}
(3)LinkListTest.cpp测试程序:
/*
* Copyright (c) 2009,FreshAir团队嵌入式软件研发组
* All rights reserved.
*
* 文件名称:LinkListTest.cpp
* 摘 要:双向循环链表类的定义
*
* 当前版本:1.0
* 作 者:吴友强
* 完成日期:2009年10月13日
*
* 取代版本:
* 原作者 :
* 完成日期:
*/
#include <iostream.h>
#include <stdlib.h>
#include "LinkList.h"
int main(int argc, char *argv[])
{
// LinkList<int> targetList, sourceList;
//
// for (int i=0; i<10; i++)
// {
// targetList.Insert(i+10, i);
// }
//
// for (i=0; i<5; i++)
// {
// sourceList.Insert(i+5, i);
// }
// cout << "测试GetData()成员函数结果如下:" << endl;
// int n = linkList.GetListSize();
// for (i=0; i<n; i++)
// {
// cout << linkList.GetData(i) << " ";
// }
//
// cout << endl << "测试遍历成员函数结果如下:" << endl;
// ListNode<int> *p = linkList.Reset(0);
//
// while (!linkList.EndOfList())
// {
// cout << p->data << " ";
// p = linkList.Next();
// }
//
// cout << endl << "测试Delete()成员函数结果如下:" << endl;
// n = linkList.GetListSize();
// for (i=n-1; i>=0; i--)
// {
// linkList.Delete(i);
// }
//
// cout << "测试GetData()成员函数结果如下:" << endl;
// n = linkList.GetListSize();
// for (i=0; i<n; i++)
// {
// cout << linkList.GetData(i) << " ";
// }
// Concatenate(targetList, sourceList);
//
// int n = targetList.GetListSize();
// for (i=0; i<n; i++)
// {
// cout << targetList.GetData(i) << " ";
// }
LinkList<int> myList;
for (int i=0; i<100; i++)
{
myList.Insert(i+10, i);
}
cout << "插入100个元素输出如下:" << endl;
int n = myList.GetListSize();
for (i=0; i<n; i++)
{
cout << myList.GetData(i) << " ";
}
for (i=99; i>=0; i--)
{
myList.Delete(i);
}
cout << endl << "删除100个元素输出如下:" << endl;
n = myList.GetListSize();
for (i=0; i<n; i++)
{
cout << myList.GetData(i) << " ";
}
return 0;
}
说明:注释部分测试基本功能函数,其他测试提高要求。
分享到:
相关推荐
zigbee初学到精通的一篇日志连载,粘贴为word格式与大家共享一下
access罗斯文数据库学习连载 access罗斯文数据库学习连载
框架设计学习资料 连载 连载不断更新框架设计框架设计学习资料 连载 连载不断更新学习资料 连载 连载不断更新
【连载三】一篇关于货币的神文:从宇宙哲学俯瞰统一货币秩序变革趋势中的国家大战略选择.doc
F2812学习笔记 --大家先大体上看一遍书,把大体的知识了解一下。其次就是看例子了,例子是关键,例子里有 你学的所有的东西,这次你再拿出一本书来看,这次是有针对性的看,比如你做的 spi 的,你就直接看 sp i 那张...
ACCESS经典案例 适合ACCESS初学者,ACCESS报表及窗体开发者
Qt个人学习笔记 记录整个学习过程的心得
罗斯文数据库学习连载2
行业教育软件-学习软件-软件下载_学习软件_等级考试_中高级口译应试技巧(连载一)免费下载
在对USB设备的驱动名字进行更改时,需要利用keil软件对固件进行修改,并生成 .iic 文件烧录到CY7C68013A所带的外部EEPROM中,keil生成的 .hex文件只能烧录到 Cypress的RAM中。
《学习MISRA C》系列连载讲座之二,共六讲。 第一讲:“‘安全第一’的C 语言编程规范”,简述MISRA C 的概况。 第二讲:“跨越数据类型的重重陷阱”,介绍规范的数据定义和操作方式,重点在隐式数据类型转换中的问题。 第...
ExtJS+2.2实现及应用连载,详细的讲解及实例
uCGUI3.32应用笔记连载 里面含有word文档,相应软件.以及连接等,自己整理的...嘿嘿...
第二讲:“跨越数据类型的重重陷阱”,介绍规范的数据定义和操作方式,重点在隐式数据类型转换中的问题。 第三讲:“指针、结构体、联合体的安全规范”,解析如何安全而高效地应用指针、结构体和联合体。 第四讲:“防范...
如何在.NET中实现脚本引擎 (CodeDom篇) .NET的插件机制的简单实现 我对J2EE和.NET的一点理解 难分难舍的DSO(一) InternalsVisibleToAttribute,友元程序集访问属性 Essential .NET 读书笔记 [第一部分] ...
ExtJS+2.2实现及应用连载.rar
邵贝贝-《学习 MISRA C》系列连载讲座之六 ,共六讲 第一讲 “: ‘安全第一’的 C 语言编程规范”,简述 MISRA C 的概况。 第二讲 “: 跨越数据类型的重重陷阱”,介绍规范的数据定义和操作方式 ,重点在隐式数据类型...
java学习源码,从初级开始(连载)http://www.tsp2c.cn/indextrans.htm
第一讲:“‘安全第一’的C 语言编程规范”,简述MISRAC 的概况。 第二讲:“跨越数据类型的重重陷阱”,介绍规范的数据定义和操作方式,重 点在隐式数据类型转换中的问题。 第三讲:“指针、结构体、联合体的安全...
access罗斯文数据库学习,通过经典例程罗斯文学习access。 access罗斯文数据库学习,通过经典例程罗斯文学习access