您的位置:首页 > 理论基础 > 数据结构算法

[C++]数据结构之单链表

2017-01-31 18:44 525 查看

2017/2/1 修改

///////////////////////////////////////
// LinkList.h : CLinkList 单链表类
//

#include <assert.h>

// 节点类
template <class Type>
class CNode {
// 方法
public :
CNode()
{
m_pNext = 0;
}

// 属性
public :
Type m_data;
CNode * m_pNext;
};

// 单链表类
template <class Type>
class CLinkList {
// 方法
public :
// 构造
CLinkList();
CLinkList(Type arrInitial[], int iLen);
// 析构
~CLinkList();

// 销毁
void Destroy();

// 是否为空
bool IsEmpty();
// 取链表长度
int GetSize();

// 以序号查找节点(-1表示根节点, 超出链表范围返回尾结点)
CNode<Type> * GetNodeFromID(int iIndex);
CNode<Type> * operator [] (int iIndex);
// 以内容查找节点
CNode<Type> * GetNodeFromData(Type data);
// 以内容查找序号(失败返回-1)
int Find(Type data);

// 插入
bool AddAt(int iIndex, Type data);
// 在末尾处加入
bool AddBack(Type data);
// 删除
bool Delete(int iIndex);
bool Delete(int iIndex, Type * data);

// 属性
private :
// 头结点,尾结点
CNode<Type> * m_pHead, * m_pTail;

// 链表长度
int m_iSize;
};

// 构造
template <class Type>
CLinkList<Type>::CLinkList()
{
m_pHead = new CNode<Type>();
m_pTail = m_pHead;
m_iSize = 0;
}

// 构造
template <class Type>
CLinkList<Type>::CLinkList(Type arrInitial[], int iLen)
{
m_pHead = new CNode<Type>();
m_pTail = m_pHead;
m_pHead->m_pNext = 0;
m_iSize = 0;

for (int i = 1; i <= iLen; i++)
AddBack(arrInitial[i - 1]);
}

// 析构
template <class Type>
CLinkList<Type>::~CLinkList()
{
Destroy();
delete m_pHead;
}

// 销毁
template <class Type>
void CLinkList<Type>::Destroy()
{
CNode<Type> * p, * q;
p = m_pHead;
while(p)
{
q = p;
p = p->m_pNext;
delete q;
}
m_iSize = 0;
}

// 是否为空
template <class Type>
bool CLinkList<Type>::IsEmpty()
{
return (!m_iSize);
//return (m_pHead->m_pNext == 0);
}

// 以序号查找节点
template <class Type>
CNode<Type> * CLinkList<Type>::GetNodeFromID(int iIndex)
{
// 我们经常会需要在链表尾部添加节点,
// 如果频繁地使用 GetNodeFromID() 获取尾部节点,可能耗时较长,
// 因此这样写
if (iIndex >= GetSize() - 1)
return m_pTail;

if (iIndex == -1)
return m_pHead;

assert(!IsEmpty());
if (IsEmpty())
return 0;

assert(iIndex >= 0);
assert(iIndex < GetSize());
if (iIndex < 0 || iIndex >= GetSize())
return 0;

CNode<Type> * pTmp = m_pHead->m_pNext;
while(pTmp && iIndex)
{
pTmp = pTmp->m_pNext;
iIndex--;
}

return pTmp;
}

// 以内容查找节点
template <class Type>
CNode<Type> * CLinkList<Type>::GetNodeFromData(Type data)
{
assert(!IsEmpty());
if (IsEmpty())
return 0;

CNode<Type> * pTmp = m_pHead->m_pNext;
while (pTmp)
{
if (pTmp->m_data != data)
pTmp = pTmp->m_pNext;
else
return pTmp;
}

return 0;
}

// 以内容查找序号
template <class Type>
int CLinkList<Type>::Find(Type data)
{
assert(!IsEmpty());
if (IsEmpty())
return 0;

CNode<Type> * pTmp = m_pHead->m_pNext;
int i = 0;
while (pTmp)
{
if (pTmp->m_data != data)
{
pTmp = pTmp->m_pNext;
i++;
}
else
return i;
}
return -1;
}

// 取链表长度
template <class Type>
int CLinkList<Type>::GetSize()
{
/*
int iSize = 0;
CNode<Type> * pTmp = m_pHead->m_pNext;
while (pTmp)
{
iSize++;
pTmp = pTmp->m_pNext;
}

return iSize;
*/

// 上面这种办法是可行的,但是有一个更简单的方法
return m_iSize;
}

// 以序号查找节点(运算符重载)
template <class Type>
CNode<Type> * CLinkList<Type>::operator [] (int iIndex)
{
return GetNodeFromID(iIndex);
}

// 插入
template <class Type>
bool CLinkList<Type>::AddAt(int iIndex, Type data)
{
CNode<Type> * p, * pLast;

pLast = GetNodeFromID(iIndex - 1);
assert(pLast);
if (!pLast)
return false;

p = new CNode<Type>();
p->m_data = data;
p->m_pNext = pLast->m_pNext;
pLast->m_pNext = p;

if (iIndex == GetSize())
m_pTail = p;

m_iSize++;
return true;
}

// 在末尾处加入
template <class Type>
bool CLinkList<Type>::AddBack(Type data)
{
return AddAt(GetSize(), data);
}

// 删除
template <class Type>
bool CLinkList<Type>::Delete(int iIndex)
{
CNode<Type> * pLast, * p;
pLast = GetNodeFromID(iIndex - 1);
assert(pLast);
if (!pLast)
return false;

p = pLast->m_pNext;
assert(p);
if (!p)
return false;

pLast->m_pNext = p->m_pNext;
delete p;

if (iIndex == GetSize())
m_pTail = pLast;

m_iSize--;
return true;
}

// 删除
template <class Type>
bool CLinkList<Type>::Delete(int iIndex, Type * data)
{
*data = GetNodeFromID(iIndex) -> m_data;
return Delete(iIndex);
}

///////////////////////////////////////
// test1.cpp : 测试程序
// 从A中去除B中已存在的元素,保存到C中
//

#include <iostream>
#include <cstdio>
#include "LinkList.h"
using namespace std;

int main()
{
int arrA[] = {1, 2, 3, 4, 5, 6, 7};
int arrB[] = {5, 7, 8, 9};

CLinkList<int> linkA(arrA, sizeof(arrA) / sizeof(int));
CLinkList<int> linkB(arrB, sizeof(arrB) / sizeof(int));

linkA.Delete(4);
linkB.AddAt(3, 2);

printf("单链表 A 中的元素个数:%d\n", linkA.GetSize());
printf("	");
for (int i = 1; i <= linkA.GetSize(); i++)
cout << linkA[i - 1]->m_data << "  ";
cout << endl;

printf("单链表 B 中的元素个数:%d\n", linkB.GetSize());
printf("	");
for (int i = 1; i <= linkB.GetSize(); i++)
cout << linkB[i - 1]->m_data << "  ";
cout << endl;

CLinkList<int> linkC;
for (int i = 1; i <= linkA.GetSize(); i++)
{
if (linkB.Find(linkA[i - 1]->m_data) == -1)
linkC.AddBack(linkA[i - 1]->m_data);
}

printf("单链表 A - B 中的元素个数:%d\n", linkC.GetSize());
printf("	");
for (int i = 1; i <= linkC.GetSize(); i++)
cout << linkC[i - 1]->m_data << "  ";
cout << endl;

return 0;
}




///////////////////////////////////////
// test2.cpp : 测试程序
// 合并链表
//

#include <iostream>
#include <cstdio>
#include "LinkList.h"
using namespace std;

template <class Type>
void PrintList(const char str[], CLinkList<Type> * list)
{
printf("链表 %s 共有 %d 个元素:\n", str, list->GetSize());
cout << "	";
for (int i = 1; i <= list->GetSize(); i++)
cout << list->GetNodeFromID(i - 1)->m_data << " ";
cout << endl;
}

int main()
{
int arr[] = {1, 8, 3, 4, 5};
CLinkList<int> list1(arr, 5);
PrintList("list1", &list1);

int iData;
list1.Delete(1, &iData);
cout << endl << "删除链表中的第二个节点:" << iData << endl;
PrintList("list1", &list1);

cout << endl << "在第一个元素值等于4的节点前插入一个元素值为7的节点。" << endl;
list1.AddAt(list1.Find(4), 7);
PrintList("list1", &list1);

cout << endl;
int arr2[] = {9, 8, 6, 5};
CLinkList<int> list2(arr2, 4);
PrintList("list2", &list2);

cout << endl << "把两条链表合并" << endl;
for (int i = 1; i <= list2.GetSize(); i++)
list1.AddBack(list2[i - 1]->m_data);
PrintList("list1 + list2", &list1);
}




-----------------------------------------------------------------------------------

下面是初始版本的代码:

不知道有没有错误。

///////////////////////////////////////
// LinkList.h : CLinkList 单链表类
//

#include <assert.h>

// 节点类
template <class Type>
class CNode {
// 方法
public :
CNode()
{
m_pNext = 0;
}

// 属性
public :
Type m_data;
CNode * m_pNext;
};

// 单链表类
template <class Type>
class CLinkList {
// 方法
public :
// 构造
CLinkList();
CLinkList(Type arrInitial[], int iLen);
// 析构
~CLinkList();

// 销毁
void Destroy();

// 是否为空
bool IsEmpty();
// 取链表长度
int GetSize();

// 以序号查找节点(-1表示根节点)
CNode<Type> * GetNodeFromID(int iIndex);
CNode<Type> * operator [] (int iIndex);
// 以内容查找节点
CNode<Type> * GetNodeFromData(Type data);
// 以内容查找序号(失败返回-1)
int Find(Type data);

// 插入
bool Insert(int iIndex, Type data);
// 在末尾处加入
bool Add(Type data);
// 删除
bool Delete(int iIndex);
bool Delete(int iIndex, Type * data);

// 属性
private :
// 头结点
CNode<Type> * m_pHead;
};

// 构造
template <class Type>
CLinkList<Type>::CLinkList()
{
m_pHead = new CNode<Type>();
m_pHead->m_pNext = 0;
}

// 构造
template <class Type>
CLinkList<Type>::CLinkList(Type arrInitial[], int iLen)
{
m_pHead = new CNode<Type>();
m_pHead->m_pNext = 0;

for (int i = 1; i <= iLen; i++)
Add(arrInitial[i - 1]);
}

// 析构
template <class Type>
CLinkList<Type>::~CLinkList()
{
Destroy();
delete m_pHead;
}

// 销毁
template <class Type>
void CLinkList<Type>::Destroy()
{
CNode<Type> * p, * q;
p = m_pHead;
while(p)
{
q = p;
p = p->m_pNext;
delete q;
}
}

// 是否为空
template <class Type>
bool CLinkList<Type>::IsEmpty()
{
return (m_pHead->m_pNext == 0);
}

// 以序号查找节点
template <class Type>
CNode<Type> * CLinkList<Type>::GetNodeFromID(int iIndex)
{
if (iIndex == -1)
return m_pHead;

assert(!IsEmpty());
if (IsEmpty())
return 0;

assert(iIndex >= 0);
assert(iIndex < GetSize());
if (iIndex < 0 || iIndex >= GetSize())
return 0;

CNode<Type> * pTmp = m_pHead->m_pNext;
while(pTmp && iIndex)
{
pTmp = pTmp->m_pNext;
iIndex--;
}

return pTmp;
}

// 以内容查找节点
template <class Type>
CNode<Type> * CLinkList<Type>::GetNodeFromData(Type data)
{
assert(!IsEmpty());
if (IsEmpty())
return 0;

CNode<Type> * pTmp = m_pHead->m_pNext;
while (pTmp)
{
if (pTmp->m_data != data)
pTmp = pTmp->m_pNext;
else
return pTmp;
}

return 0;
}

// 以内容查找序号
template <class Type>
int CLinkList<Type>::Find(Type data)
{
assert(!IsEmpty());
if (IsEmpty())
return 0;

CNode<Type> * pTmp = m_pHead->m_pNext;
int i = 0;
while (pTmp)
{
if (pTmp->m_data != data)
{
pTmp = pTmp->m_pNext;
i++;
}
else
return i;
}
return -1;
}

// 取链表长度
template <class Type>
int CLinkList<Type>::GetSize()
{
int iSize = 0;
CNode<Type> * pTmp = m_pHead->m_pNext;
while (pTmp)
{
iSize++;
pTmp = pTmp->m_pNext;
}

return iSize;
}

// 以序号查找节点(运算符重载)
template <class Type>
CNode<Type> * CLinkList<Type>::operator [] (int iIndex)
{
return GetNodeFromID(iIndex);
}

// 插入
template <class Type>
bool CLinkList<Type>::Insert(int iIndex, Type data)
{
CNode<Type> * p, * pLast;

pLast = GetNodeFromID(iIndex - 1);
assert(pLast);
if (!pLast)
return false;

p = new CNode<Type>();
p->m_data = data;
p->m_pNext = pLast->m_pNext;
pLast->m_pNext = p;

return true;
}

// 在末尾处加入
template <class Type>
bool CLinkList<Type>::Add(Type data)
{
return Insert(GetSize(), data);
}

// 删除
template <class Type>
bool CLinkList<Type>::Delete(int iIndex)
{
CNode<Type> * pLast, * p;
pLast = GetNodeFromID(iIndex - 1);
assert(pLast);
if (!pLast)
return false;

p = pLast->m_pNext;
assert(p);
if (!p)
return false;

pLast->m_pNext = p->m_pNext;
delete p;

return true;
}

// 删除
template <class Type>
bool CLinkList<Type>::Delete(int iIndex, Type * data)
{
*data = GetNodeFromID(iIndex) -> m_data;
return Delete(iIndex);
}


(顺便说一句,那个 GetNodeFromID() 和 GetNodeFromData() 不能写成重载函数,因为后者的参数 data 的类型有可能是 int )

测试代码(从A中去除B中已存在的元素,保存到C中):

#include <iostream>
#include <cstdio>
#include "LinkList.h"
using namespace std;

int main()
{
int arrA[] = {1, 2, 3, 4, 5, 6, 7};
int arrB[] = {5, 7, 8, 9};

CLinkList<int> linkA(arrA, sizeof(arrA) / sizeof(int));
CLinkList<int> linkB(arrB, sizeof(arrB) / sizeof(int));

linkA.Delete(4);

printf("单链表 A 中的元素个数:%d\n", linkA.GetSize());
printf("	");
for (int i = 1; i <= linkA.GetSize(); i++)
cout << linkA[i - 1]->m_data << "  ";
cout << endl;

printf("单链表 B 中的元素个数:%d\n", linkB.GetSize());
printf("	");
for (int i = 1; i <= linkB.GetSize(); i++)
cout << linkB[i - 1]->m_data << "  ";
cout << endl;

CLinkList<int> linkC;
for (int i = 1; i <= linkA.GetSize(); i++)
{
if (linkB.Find(linkA[i - 1]->m_data) == -1)
linkC.Add(linkA[i - 1]->m_data);
}

printf("单链表 A - B 中的元素个数:%d\n", linkC.GetSize());
printf("	");
for (int i = 1; i <= linkC.GetSize(); i++)
cout << linkC[i - 1]->m_data << "  ";
cout << endl;

return 0;
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C++ 单链表