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

数据结构之单向链表操作1-(插入,删除,交换,反转,排序等操作)

2015-09-08 14:07 651 查看
第一次写博客,也是为了激励自己学习,可能还不太懂(~ ̄▽ ̄)~,而且代码上可能还有些不太足,敬请赐教!!!

如标题所示,这次演示单向链表的一些基本的操作,有些地方可能没有考虑周到,ORZ~

首先是些基本的声明如下

template<typename T>
struct Node{		//结点
T data;
Node * next;
};

template<typename T>
class LinkList{
private:
Node<T> * head;		//头指针
public:
LinkList();				//创建容量为m的空表
~LinkList();
void CreateList(int n);		//创建表长为n的线性表
void Insert(int i, T e);	//在i位置插入值e
T Delete(int i);			//删除i位置的值并返回它
int Locate(T e);			//通过给定值查找线性表中第一个等于此值的数,返回其序列号
T GetElem(int i);			//获取i位置的值
T Prior(T e);				//返回元素e的前驱
int Length();				//返回表长
bool Empty();				//检查表是否为空
void Clear();				//清空表
void LinkListTraverse();	//遍历表中的元素
void Reverse();				//反转链表
Node<T> * FindNode(int i);	//通过给定序号返回结点
Node<T> * FindPro(int i);		//通过给定序号返回前驱结点
void Exchange(int i, int j);	//交换链表中的两个结点
void InsertSort();			//插入排序链表
};


函数的定义

template<typename T>
LinkList<T>::LinkList()
{
head = new Node<T>;
if (!head)
throw "内存分配失败 \n";
head->next = NULL;              //建立带头结点的链表
}

//删除结点,释放内存
template<typename T>
LinkList<T>::~LinkList()
{
Node<T> *p;		//临时结点指针,保存要释放的结点
while (head)
{
p = head;
head = head->next;        //通过让p保存当前要释放的结点,然后让head往下移动,再释放p指向的空间,循环如此达到完全释放
delete p;
}
}

//尾插法
template<typename T>
void LinkList<T>::CreateList(int n)
{
Node<T> *p = head, *s;		//p保存当前结点,s指向新结点
cout << "输入数据: ";
for (int i = 0; i < n; ++i)
{
s = new Node<T>;
cin >> s->data;
s->next = p->next;      //让p从头结点开始,再把新结点接到p结点后面
p->next = s;
p = s;                  //接完后,再让p结点指向新结点,循环
}
}

////头插法,比尾插法少了p保存新结点,这样让每次新结点都在头插入
//template<typename T>
//void LinkList<T>::CreateList(int n)
//{
//	cout << "输入数据: ";
//	for (int i = 0; i < n; ++i)
//	{
//		s = new Node<T>;
//		cin >> s->data;
//		s->next = head->next;
//		head->next = s;
//	}
//}

//返回表长(不包含头结点)
template<typename T>
int LinkList<T>::Length()
{
int i = 0;
Node<T> * p = head->next;	//p指向首结点开始计数
while (p)
{
++i;
p = p->next;
}

return i;
}

//在i位置插入值e
template<typename T>
void LinkList<T>::Insert(int i, T e)
{
Node<T> * p = head, * s;
int cnt = 1;		//计数
while (p && cnt < i)
{
p = p->next;		//定位到i-1的位置
cnt++;
}
if (!p || cnt > i)
throw "插入位置出错 \n";		//i大于表长或者小于0
s = new Node<T>;
if (!s)
throw "内存分配失败 \n";
s->data = e;
s->next = p->next;
p->next = s;
}

//删除i位置的值并返回它
template<typename T>
T LinkList<T>::Delete(int i)
{
if (Length() == 0)
throw "无元素存在,不需要删除 \n";
Node<T> *p = head;
int j = 1;
while (p && j < i)
{
p = p->next;
j++;
}
if (!p || j > i)
throw "插入位置出错 \n";
T e = p->next->data;
Node<T> *s = p->next;     //保存要释放的结点
p->next = p->next->next;
delete s;

return e;
}
//通过给定值查找线性表中第一个等于此数,返回其序列号
template<typename T>
int LinkList<T>::Locate(T e)
{
Node<T> *p = head->next;
int cnt = 0;
while (p)
{
cnt++;
if (p->data == e)
return cnt;			//返回序列号
p = p->next;
}
cout << "没有找到元素 \n";
return 0;				//返回0表示没有找到
}

//获取i位置的值
template<typename T>
T LinkList<T>::GetElem(int i)
{
Node<T> *p = head->next;
int j = 1;
while (p && j < i)
{
p = p->next;
j++;			//定位到i位置,注意和前面定位到i-1的区别
}
if (!p || j > i)
throw "插入位置出错 \n";
return p->data;
}

template<typename T>
//返回元素e的前驱
T LinkList<T>::Prior(T e)
{
Node<T> *p = head->next;
int cnt = 0;
while (p)
{
cnt++;
if (p->next->data == e)
return p->data;
p = p->next;
}
cout << "没有找到元素 \n";
return 0;				//返回0表示没有找到
}

//检查表是否为空
template<typename T>
bool LinkList<T>::Empty()
{
int len = Length();
return len == 0;
}

//清空表(和析构函数完全摧毁链表相比,保留头结点)
template<typename T>
void LinkList<T>::Clear()
{
Node<T> * p = head->next;
while (p)
{
Node<T> * s = p;
p = p->next;
delete s;
}
head->next = NULL;      //最后记得要将头结点的next置空
}

template<typename T>
//遍历表中的元素
void LinkList<T>::LinkListTraverse()
{
Node<T> *p = head->next;
while (p)
{
cout << p->data << " ";
p = p->next;
}
cout << endl;
}

//反转链表
template<typename T>
void LinkList<T>::Reverse()
{
if (head == NULL)
return;
Node<T> *curr, *p;		  //curr一直指向首结点
curr = head->next;
while (curr->next != NULL)
{
p = curr->next;
curr->next = p->next;
p->next = head->next;
head->next = p;
}
}

//通过给定序号返回结点
template<typename T>
Node<T> * LinkList<T>::FindNode(int i)
{
Node<T> *p = head;
int j = 0;
while (p && j < i)
{
j++;
p = p->next;		//当j = i时,j实际计数实在i后面一位
}						//此时p指向i位置的
if (!p || j > i)
throw"位置异常 \n";
return p;
}

//通过给定序号返回前驱结点
template<typename T>
Node<T> * LinkList<T>::FindPro(int i)
{

Node<T> *p = head;
int j = 1;
while (p && j < i)
{
j++;
p = p->next;
}
if (!p || j > i)
throw"位置异常 \n";
return p;		//返回前驱结点
}

//交换链表中的两个结点
template<typename T>
void LinkList<T>::Exchange(int i, int j)
{
/*1. 假如两个结点相等, 不交换
*2. 两个结点相邻特殊处理
*3. 一般情况直接处理
*/

//分别找到待交换结点的前驱与后继
Node<T> * node1 = FindNode(i), * node2 = FindNode(j);
Node<T> * prenode1 = FindPro(i), * prenode2 = FindPro(j);
Node<T> * postnode1 = node1->next, * postnode2 = node2->next;
if (node1 == node2)
{
cout << "两个结点相等 \n";
return;
}

//特殊情况处理
if (prenode2 == node1)		//结点1在结点2的前面
{
prenode1->next = node2;
node2->next = node1;
node1->next = postnode2;
return;
}
if (prenode1 == node2)
{
prenode2->next = node1;
node1->next = node2;
node2->next = postnode1;
return;
}

//一般情况直接交换两个结点
prenode1->next = node2;
node2->next = postnode1;
prenode2->next = node1;
node1->next = postnode2;

}

//插入排序链表
template<typename T>
void LinkList<T>::InsertSort()
{
Node<T> *first;			//作为无序链表的第一个结点
Node<T> *t;				//作为无序链表的待插结点
Node<T> *p, *q;			//作为临时变量
if (head->next == NULL)
return;				//保证有结点
first = head->next->next;	//first指向链表的第二个结点(不包含头结点)
head->next->next = NULL;

while (first != NULL)
{
for (t = first, q = head->next, p = head; q && q->data < t->data; p = q, q = q->next);		//找到第一个比t->data大的结点
first = first->next;	//往下移动
p->next = t;
t->next = q;
}
}


主函数

int main(){
int i, j;
LinkList<int> LList;

cout << "请输入你需要的链表表实际长度:";
cin >> i;
LList.CreateList(i);
cout << "表中元素为:";
LList.LinkListTraverse();
cout << "插入元素后: \n";
LList.Insert(2, 33);
LList.Insert(4, 66);
cout << "表中元素为:";
LList.LinkListTraverse();
cout << "表的长度为:" << LList.Length() << endl;
cout << "现在进行删除操作: \n";
9e9a

cout << "请输入你需要删除的位置:";
cin >> i;
cout << "删除的元素为:" << LList.Delete(i) << endl;
if (LList.Empty())
cout << "表为空 \n";
else
cout << "表不为空 \n";
cout << "表中元素为:";
LList.LinkListTraverse();
cout << "反转链表:";
LList.Reverse();
cout << "表中元素为:";
LList.LinkListTraverse();
cout << "输入要交换两个结点的序列号:";
cin >> i >> j;
LList.Exchange(i, j);		//交换两个结点
cout << "表中元素为:";
LList.LinkListTraverse();
cout << "获取位置4的元素为:" << LList.GetElem(4) << endl;
cout << "请输入一个链表中存在的数:";
cin >> i;
cout << "其序列号为:" << LList.Locate(i) << endl;
cout << "其前驱元素为:" << LList.Prior(i) << endl;
cout << "现在进行链表的排序(根据关键字数据大小排序) \n";
LList.InsertSort();
cout << "表中元素为:";
LList.LinkListTraverse();

LList.Clear();
cout << "将表中元素清空后: \n";
if (LList.Empty())
cout << "表为空 \n";
else
cout << "表不为空 \n";

return 0;
}
难点我觉得应该在于链表反转,排序,有时间再补上解释!(。・_・)/~~~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数据结构 链表 操作