数据结构之单向链表操作1-(插入,删除,交换,反转,排序等操作)
2015-09-08 14:07
651 查看
第一次写博客,也是为了激励自己学习,可能还不太懂(~ ̄▽ ̄)~,而且代码上可能还有些不太足,敬请赐教!!!
如标题所示,这次演示单向链表的一些基本的操作,有些地方可能没有考虑周到,ORZ~
首先是些基本的声明如下
函数的定义
主函数
如标题所示,这次演示单向链表的一些基本的操作,有些地方可能没有考虑周到,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; }难点我觉得应该在于链表反转,排序,有时间再补上解释!(。・_・)/~~~
相关文章推荐
- [C/C++]反转链表
- Flex字符串比较 还有Flex字符串操作
- C#实现基于链表的内存记事本实例
- Lua教程(七):数据结构详解
- ASP Cookies操作的详细介绍与实例代码
- perl数据库添加、删除、更新、查询操作例子
- 总结的5个C#字符串操作方法分享
- 解析从源码分析常见的基于Array的数据结构动态扩容机制的详解
- C#操作XML文件实例汇总
- C#数据结构揭秘一
- C#中父窗口和子窗口之间控件互操作实例
- C#操作PowerPoint的方法
- SQL语句 操作全集 学习mssql的朋友一定要看
- C#模拟window操作鼠标的方法
- linux mysql 安装与操作
- 数据结构之Treap详解
- C语言实现带头结点的链表的创建、查找、插入、删除操作
- C++实现简单的学生管理系统
- 使用PHPExcel操作Excel用法实例分析
- 防火墙基本操作