最近本人开始为找工作做准备,于是想把几种常用的数据结构用自己的代码实现出来,在实现的过程中,发现问题多多,现将本人实现的过程中所犯的错误(相信也有不少和我一样的菜鸟犯过同样的错误),以及为什么会出现错误,如何解决该错误的过程记录于此,方便它人的同时,也方便自己日后查阅。
/******************************************************************************************************
* Description: 动态单向链表的实现
* Author: Sky
* Time: 2014.04.14
* Language: C/C++
* Note: 1、单向链表是由表头唯一确定的,因此单向链表可以用头指针/结点的名字来命名。
2、空链表表示只含有头结点的链表。注意区分链表销毁和链表清空操作。
******************************************************************************************************/
#include "stdafx.h"
#include <iostream>
using namespace std;
typedef int Elemtype;
struct ListNode
{
Elemtype Elem; // 数据域(不一定为int型,可以为任何用户自定义的类型、包括结构体、类、数组等)
ListNode* pNext; // 指针域(指向下一个结点)
};
bool ListInit(ListNode* L); // 单向链表初始化(构造一个空的单向链表,即仅含头结点的单向链表)void ListDestory(ListNode* L); // 单向链表的销毁
void ListClear(ListNode* L); // 单向链表的清空
bool ListInsert(ListNode* L, const int& i, const Elemtype& Elem); // 向链表中指定位置i之前插入一个元素
bool ListDelete(ListNode* L, const int& i, Elemtype& Elem); // 删除链表中指定位置i的一个元素,并返回删除元素
int ListFind(ListNode* L, const Elemtype& CurElem, bool (*compare)(const Elemtype&, const Elemtype&));// 返回链表中第一个满足关系compare()的数据元素的位序。
bool PriorElem(ListNode* L, const Elemtype& CurElem, Elemtype& PreElem); // 返回当前元素的前一元素
bool NextElem(ListNode* L, const Elemtype& CurElem, Elemtype& NextElem); // 返回当前元素的后一元素
bool GetElem(ListNode* L, const int& i, Elemtype& Elem); // 获取当前位序处的元素值
bool ListEmpty(ListNode* L); // 判断单向链表是否为空
int ListLength(ListNode* L); // 返回链表长度
void ListTravesal(ListNode* L); // 链表遍历
int _tmain(int argc, _TCHAR* argv[])
{
int a[] = {1,5,9,8,6,14,25,39,68,59,65,26,77,69};
ListNode* L = NULL;ListInit(L);
for(int i=0; i<7; i++)
ListInsert(L, i+1, a[i]);
ListTravesal(L);
while(true);
return 0;
}
/**************************************************************************************
* Author: Sky
* Functiuon: ListInit()
* Description: 动态单向链表的初始化,构造一个空的单向链表
* Access Level:NULL
* Input:
* Output: L: 待初始化的单向链表头结点
* Return: false/true
**************************************************************************************/
bool ListInit(ListNode* L) // 如果形参为ListNode* ,当传入一个ListNode的指针时,实际传入的是指针的拷贝,函数内部任何对L的操作与传入的实参无关
{
L = new ListNode;
if(NULL == L)
return false;
L->pNext = NULL;
return true;
}
/**************************************************************************************
* Author: Sky
* Functiuon: ListDestory()
* Description: 单向链表的销毁
* Access Level: NULL
* Input: L:待销毁的链表的头结点
* Output: NULL
* Return: NULL
**************************************************************************************/
void ListDestory(ListNode* L)
{
ListNode* pNextNode = NULL;
while(NULL != L)
{
pNextNode = L->pNext;
delete L;
L = pNextNode;
}
}
/**************************************************************************************
* Author: Sky
* Functiuon: ListClear()
* Description: 清空单向链表,即:将已有单向链表变为一个空链表
* Access Level: NULL
* Input: L: 待清空单向链表的头结点
* Output: NULL
* Return: NULL
**************************************************************************************/
void ListClear(ListNode* L)
{
ListNode* pNextNode = NULL;
L = L->pNext;
while(NULL != L)
{
pNextNode = L->pNext;
delete L;
L = pNextNode;
}
}
/**************************************************************************************
* Author: Sky
* Functiuon: ListInsert()
* Description: 向单向链表中指定位序处插入一个元素
* Access Level:NULL
* Input: L: 被插入的单向链表头结点
i: 待插入元素在链表中的位序
Elem: 待插入元素
* Output: NULL
* Return: false/true
**************************************************************************************/
bool ListInsert(ListNode* L, const int& i, const Elemtype& Elem)
{
bool bResult = false;
ListNode* pCurNode = L;
ListNode* pNewNode = NULL;
int j = 0;
if(i>=1 && i<=ListLength(L)+1)
{
for(j=0; j<i-1; j++)
{
pCurNode = pCurNode->pNext;
}
bResult = true;
pNewNode = new ListNode;
pNewNode->Elem = Elem;
pNewNode->pNext = pCurNode->pNext;
pCurNode->pNext = pNewNode;
}
return bResult;
}
/**************************************************************************************
* Author: Sky
* Functiuon: ListDelete()
* Description: 删除链表中指定位序处的结点,并返回删除结点的值
* Access Level: NULL
* Input: L: 待删除结点所在链表
i: 待删除结点在链表中的位序(1~Length(L))
* Output: Elem: 被删除的元素
* Return: false/true
**************************************************************************************/
bool ListDelete(ListNode* L, const int& i, Elemtype& Elem)
{
bool bResult = false;
ListNode* pCurNode = L;
ListNode* pNextNode = NULL;
int j = 0;
if(i>=1 && i<=ListLength(L))
{
for(j=0; j<i-1; j++)
{
pCurNode = pCurNode->pNext;
}
bResult = true;
pNextNode = pCurNode->pNext->pNext;
Elem = pCurNode->pNext->Elem;
delete pCurNode->pNext;
pCurNode->pNext = pNextNode;
}
return bResult;
}
/**************************************************************************************
* Author: Sky
* Functiuon: ListFind()
* Description: 找出链表中与指定元素CurElem满足条件compare()的元素,返回其在链表中的位序
* Access Level: NULL
* Input: L: 待检索链表
CurElem: 检索元素
compare: 函数指针,检索条件
* Output: NULL
* Return: -1: 查找失败
其它: 返回找到的元素在链表中的位序号。
**************************************************************************************/
int ListFind(ListNode* L, const Elemtype& CurElem, bool (*compare)(const Elemtype&, const Elemtype&))
{
ListNode* pCurNode = L;
int i = 0;
while(NULL != pCurNode)
{
if(compare(CurElem, pCurNode->Elem))
{
return i;
}
else
{
pCurNode = pCurNode->pNext;
i++;
}
}
return -1;
}
/**************************************************************************************
* Author: Sky
* Functiuon: PriorElem()
* Description: 返回单向链表中指定元素的前一个元素
* Access Level: NULL
* Input: L: 单向链表
CurElem:指定元素
* Output: PreElem:单向链表中指定元素的前一个元素
* Return: false/true
**************************************************************************************/
bool PriorElem(ListNode* L, const Elemtype& CurElem, Elemtype& PreElem)
{
bool bResult = false;
ListNode* pCurNode = NULL;
ListNode* pPreNode = NULL;
pCurNode = L->pNext->pNext; // pCurNode初始指向第二个结点
pPreNode = L->pNext; // pPreNode初始指向第一个结点
while(NULL != pCurNode) // 当前结点存在
{
if(CurElem == pCurNode->Elem)
{
PreElem = pPreNode->Elem;
bResult = true;
break;
}
else
{
pCurNode = pCurNode->pNext;
pPreNode = pPreNode->pNext;
}
}
return bResult;
}
/**************************************************************************************
* Author: Sky
* Functiuon: NextElem()
* Description: 返回单向链表中指定元素的后一个元素
* Access Level: NULL
* Input: L: 单向链表
CurElem: 指定元素
* Output: NextElem:单向链表中指定元素的后一个元素
* Return: false/true
**************************************************************************************/
bool NextElem(ListNode* L, const Elemtype& CurElem, Elemtype& NextElem)
{
bool bResult = false;
ListNode* pCurNode = NULL;
ListNode* pNextNode = NULL;
pCurNode = L->pNext;pNextNode = L->pNext->pNext;
while(NULL != pNextNode)
{
if(CurElem == pCurNode->Elem)
{
NextElem = pNextNode->Elem;
bResult = true;
break;
}
else
{
pCurNode = pCurNode->pNext;
pNextNode = pNextNode->pNext;
}
}
return bResult;
}
/**************************************************************************************
* Author: Sky
* Functiuon: GetElem()
* Description: 返回单向链表中指定位序处的元素
* Access Level: NULL
* Input: L: 单向链表
i: 待获取的元素在单向链表中的位序
* Output: Elem:单向链表中指定位序处的元素
* Return: fasle/true
**************************************************************************************/
bool GetElem(ListNode* L, const int& i, Elemtype& Elem)
{
bool bResult = false;
ListNode* pCurNode = NULL;
int j = 0;
pCurNode = L;
if(i>=1 && i<=ListLength(L))
{
for(j=0; j<i; j++)
{
pCurNode = pCurNode->pNext;
}
Elem = pCurNode->Elem;
bResult = true;
}
return bResult;
}
/**************************************************************************************
* Author: Sky
* Functiuon: ListEmpty()
* Description: 判断单向链表是否为空链表
* Access Level: NULL
* Input: L: 待判断单向链表头结点
* Output: NULL
* Return: false: 该单向链表不是空链表
true: 该单向链表是空链表
**************************************************************************************/
bool ListEmpty(ListNode* L)
{
bool bResult = false;
ListNode* pCurNode = L;
if(NULL == pCurNode->pNext)
bResult = true;
return bResult;
}
/**************************************************************************************
* Author: Sky
* Functiuon: ListLength()
* Description: 返回指定单向链表的长度
* Access Level: NULL
* Input: L: 单向链表头结点
* Output: NULL
* Return: 单向链表长度
**************************************************************************************/
int ListLength(ListNode* L)
{
ListNode* pCurNode = L->pNext;
int Len = 0;
while(NULL != pCurNode)
{
Len++;
pCurNode = pCurNode->pNext;
}
return Len;
}
/**************************************************************************************
* Author: Sky
* Functiuon: ListTravesal()
* Description: 从头结点到尾节点遍历一个单向链表
* Access Level: NULL
* Input: L: 待遍历单向链表
* Output: NULL
* Return: NULL
**************************************************************************************/
void ListTravesal(ListNode* L)
{
ListNode* pCurNode = L->pNext;
while(NULL != pCurNode)
{
cout<<pCurNode->Elem<<endl;
pCurNode = pCurNode->pNext;
}
}
运行程序后程序出现错误,调试单步跟踪发现是内存访问越界,L未被初始化,而主函数中我调用了ListInit(L),为什么没有初始化呢?原来在ListInit()函数中采用的非引用形参ListNode* ,当将指针L作为实参实际传递的是L的一个拷贝,该函数内部任何执行动作与L无关。因此我们应当传递指针的引用或者传递指针的指针。修改后的代码如下:
执行结果:/****************************************************************************************************** * Description: 动态单向链表的实现 * Author: Sky * Time: 2014.04.14 * Language: C/C++ * Note: 1、单向链表是由表头唯一确定的,因此单向链表可以用头指针/结点的名字来命名。 2、空链表表示只含有头结点的链表。注意区分链表销毁和链表清空操作。 3、对单链表的操作,为什么传入参数均为指向头结点指针的指针或头结点指针的引用,而不是头结点指针? ******************************************************************************************************/ #include "stdafx.h" #include <iostream> using namespace std; typedef int Elemtype; struct ListNode { Elemtype Elem; // 数据域(不一定为int型,可以为任何用户自定义的类型、包括结构体、类、数组等) ListNode *pNext; // 指针域(指向下一个结点) }; bool ListInit(ListNode *&L); // 单向链表初始化(构造一个空的单向链表,即仅含头结点的单向链表) void ListDestory(ListNode *&L); // 单向链表的销毁 void ListClear(ListNode *&L); // 单向链表的清空 bool ListInsert(ListNode *&L, const int &i, const Elemtype &Elem); // 向链表中指定位置i之前插入一个元素 bool ListDelete(ListNode *&L, const int &i, Elemtype &Elem); // 删除链表中指定位置i的一个元素,并返回删除元素 int ListFind(ListNode *&L, const Elemtype &CurElem, bool (*compare)(const Elemtype &, const Elemtype &));// 返回链表中第一个满足关系compare()的数据元素的位序。 bool PriorElem(ListNode *&L, const Elemtype &CurElem, Elemtype &PreElem); // 返回当前元素的前一元素 bool NextElem(ListNode *&L, const Elemtype &CurElem, Elemtype &NextElem); // 返回当前元素的后一元素 bool GetElem(ListNode *&L, const int &i, Elemtype &Elem); // 获取当前位序处的元素值 bool ListEmpty(ListNode *&L); // 判断单向链表是否为空 int ListLength(ListNode *&L); // 返回链表长度 void ListTravesal(ListNode *&L); // 链表遍历 int _tmain(int argc, _TCHAR* argv[]) { int a[] = {1,5,9,8,6,14,25,39,68,59,65,26,77,69}; ListNode *L = NULL; Elemtype e, Pre_e, Next_e; ListInit(L); for(int i=0; i<7; i++) ListInsert(L, i+1, a[i]); ListTravesal(L); GetElem(L, 4, e); cout<<"The 4th Elem is: "<<e<<endl; cout<<"ListLength(L) = "<<ListLength(L)<<endl; PriorElem(L, 9, Pre_e); NextElem(L, 9, Next_e); cout<<"Pre_e = "<<Pre_e<<endl; cout<<"Next_e = "<<Next_e<<endl; ListDelete(L, 3, e); ListTravesal(L); cout<<"ListLength(L) = "<<ListLength(L)<<endl; while(true); return 0; } /************************************************************************************** * Author: Sky * Functiuon: ListInit() * Description: 动态单向链表的初始化,构造一个空的单向链表 * Access Level: NULL * Input: * Output: L: 待初始化的单向链表头结点 * Return: false/true **************************************************************************************/ bool ListInit(ListNode *&L) // 如果形参为ListNode* ,即非引用形参,实际传入的是指针的拷贝,函数内部任何对 // 指针L的操作与传入的实参无关,因此此处需传入双重指针,或指针的引用 { // L = new ListNode; if(NULL == L) return false; L->pNext = NULL; return true; } /************************************************************************************** * Author: Sky * Functiuon: ListDestory() * Description: 单向链表的销毁 * Access Level: NULL * Input: L:待销毁的链表的头结点 * Output: NULL * Return: NULL **************************************************************************************/ void ListDestory(ListNode *&L) { ListNode *pNextNode = NULL; while(NULL != L) { pNextNode = L->pNext; delete L; L = pNextNode; } } /************************************************************************************** * Author: Sky * Functiuon: ListClear() * Description: 清空单向链表,即:将已有单向链表变为一个空链表 * Access Level: NULL * Input: L: 待清空单向链表的头结点 * Output: NULL * Return: NULL **************************************************************************************/ void ListClear(ListNode *&L) { ListNode *pNextNode = NULL; L = L->pNext; while(NULL != L) { pNextNode = L->pNext; delete L; L = pNextNode; } } /************************************************************************************** * Author: Sky * Functiuon: ListInsert() * Description: 向单向链表中指定位序处插入一个元素 * Access Level: NULL * Input: L: 被插入的单向链表头结点 i: 待插入元素在链表中的位序 Elem: 待插入元素 * Output: NULL * Return: false/true **************************************************************************************/ bool ListInsert(ListNode *&L, const int &i, const Elemtype &Elem) { bool bResult = false; ListNode *pCurNode = L; ListNode *pNewNode = NULL; int j = 0; if(i>=1 && i<=ListLength(L)+1) { for(j=0; j<i-1; j++) { pCurNode = pCurNode->pNext; } bResult = true; pNewNode = new ListNode; pNewNode->Elem = Elem; pNewNode->pNext = pCurNode->pNext; pCurNode->pNext = pNewNode; } return bResult; } /************************************************************************************** * Author: Sky * Functiuon: ListDelete() * Description: 删除链表中指定位序处的结点,并返回删除结点的值 * Access Level: NULL * Input: L: 待删除结点所在链表 i: 待删除结点在链表中的位序(1~Length(L)) * Output: Elem: 被删除的元素 * Return: false/true **************************************************************************************/ bool ListDelete(ListNode *&L, const int &i, Elemtype &Elem) { bool bResult = false; ListNode *pCurNode = L; ListNode *pNextNode = NULL; int j = 0; if(i>=1 && i<=ListLength(L)) { for(j=0; j<i-1; j++) { pCurNode = pCurNode->pNext; } bResult = true; pNextNode = pCurNode->pNext->pNext; Elem = pCurNode->pNext->Elem; delete pCurNode->pNext; pCurNode->pNext = pNextNode; } return bResult; } /************************************************************************************** * Author: Sky * Functiuon: ListFind() * Description: 找出链表中与指定元素CurElem满足条件compare()的元素,返回其在链表中的位序 * Access Level: NULL * Input: L: 待检索链表 CurElem: 检索元素 compare: 函数指针,检索条件 * Output: NULL * Return: -1: 查找失败 其它: 返回找到的元素在链表中的位序号。 **************************************************************************************/ int ListFind(ListNode *&L, const Elemtype &CurElem, bool (*compare)(const Elemtype &, const Elemtype &)) { ListNode *pCurNode = L; int i = 0; while(NULL != pCurNode) { if(compare(CurElem, pCurNode->Elem)) { return i; } else { pCurNode = pCurNode->pNext; i++; } } return -1; } /************************************************************************************** * Author: Sky * Functiuon: PriorElem() * Description: 返回单向链表中指定元素的前一个元素 * Access Level: NULL * Input: L: 单向链表 CurElem: 指定元素 * Output: PreElem:单向链表中指定元素的前一个元素 * Return: false/true **************************************************************************************/ bool PriorElem(ListNode *&L, const Elemtype &CurElem, Elemtype &PreElem) { bool bResult = false; ListNode *pCurNode = NULL; ListNode *pPreNode = NULL; if(2 <= ListLength(L)) { pCurNode = L->pNext->pNext; // pCurNode初始指向第二个结点 pPreNode = L->pNext; // pPreNode初始指向第一个结点 while(NULL != pCurNode) // 当前结点存在 { if(CurElem == pCurNode->Elem) { PreElem = pPreNode->Elem; bResult = true; break; } else { pCurNode = pCurNode->pNext; pPreNode = pPreNode->pNext; } } } return bResult; } /************************************************************************************** * Author: Sky * Functiuon: NextElem() * Description: 返回单向链表中指定元素的后一个元素 * Access Level: NULL * Input: L: 单向链表 CurElem: 指定元素 * Output: NextElem:单向链表中指定元素的后一个元素 * Return: false/true **************************************************************************************/ bool NextElem(ListNode *&L, const Elemtype &CurElem, Elemtype &NextElem) { bool bResult = false; ListNode *pCurNode = NULL; ListNode *pNextNode = NULL; if(2 <= ListLength(L)) { pCurNode = L->pNext; pNextNode = L->pNext->pNext; while(NULL != pNextNode) { if(CurElem == pCurNode->Elem) { NextElem = pNextNode->Elem; bResult = true; break; } else { pCurNode = pCurNode->pNext; pNextNode = pNextNode->pNext; } } } return bResult; } /************************************************************************************** * Author: Sky * Functiuon: GetElem() * Description: 返回单向链表中指定位序处的元素 * Access Level: NULL * Input: L: 单向链表 i: 待获取的元素在单向链表中的位序 * Output: Elem:单向链表中指定位序处的元素 * Return: fasle/true **************************************************************************************/ bool GetElem(ListNode *&L, const int &i, Elemtype &Elem) { bool bResult = false; ListNode *pCurNode = NULL; int j = 0; pCurNode = L; if(i>=1 && i<=ListLength(L)) { for(j=0; j<i; j++) { pCurNode = pCurNode->pNext; } Elem = pCurNode->Elem; bResult = true; } return bResult; } /************************************************************************************** * Author: Sky * Functiuon: ListEmpty() * Description: 判断单向链表是否为空链表 * Access Level: NULL * Input: L: 待判断单向链表头结点 * Output: NULL * Return: false: 该单向链表不是空链表 true: 该单向链表是空链表 **************************************************************************************/ bool ListEmpty(ListNode *&L) { bool bResult = false; ListNode *pCurNode = L; if(NULL == pCurNode->pNext) bResult = true; return bResult; } /************************************************************************************** * Author: Sky * Functiuon: ListLength() * Description: 返回指定单向链表的长度 * Access Level: NULL * Input: L: 单向链表头结点 * Output: NULL * Return: 单向链表长度 **************************************************************************************/ int ListLength(ListNode *&L) { ListNode *pCurNode = L->pNext; int Len = 0; while(NULL != pCurNode) { Len++; pCurNode = pCurNode->pNext; } return Len; } /************************************************************************************** * Author: Sky * Functiuon: ListTravesal() * Description: 从头结点到尾节点遍历一个单向链表 * Access Level: NULL * Input: L: 待遍历单向链表 * Output: NULL * Return: NULL **************************************************************************************/ void ListTravesal(ListNode *&L) { ListNode *pCurNode = L->pNext; while(NULL != pCurNode) { cout<<pCurNode->Elem<<endl; pCurNode = pCurNode->pNext; } }