赞
踩
目录
青春的列车上,如果你要提前下车,请别推醒装睡的我
今天是周末,昨日一夜未眠,不知怎的失眠了,没事就爬起来谢谢博客吧,最近中年的焦虑慢慢蔓延上心头,浑身不舒服,或许坐在电脑屏幕前才能得到一丝宁静吧。今天来给大家分享的是数据结构的知识——单链表以及双向链表。
单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) +指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。
如下代码所示,双向链表的节点包含两个指向关系和一个数据空间,两个指向分别连接该节点的上一个和下一个节点,数据类型可以是一个结构体类型,也可以是其他类型。
- typedef struct node
- {
- int data;
- struct node *pre;
- struct node *next;
- }Node;
1.随机产生或键盘输入一组元素(不少于10个元素),建立一个带头结点的单链表。
2.把单链表中的元素逆置(不允许申请新的结点空间)。
3.删除单链表中所有的偶数元素结点。
4.编写在非递减有序链表中插入一个元素使链表元素仍有序的函数,利用该函数建立一个
非递减有序单链表。
5.利用算法4建立两个非递减有序单链表,然后合并成一个非递增链表。
6.把算法1建立的链表分解成两个链表,其中一个全部为奇数,另一个全部为偶数(尽量
利用已有存储空间)。
7.在主函数中设计一个简单菜单,调用上述算法。
1.结点类型定义
- typedef int ElemType; // 元素类型
- typedef struct LNode
- {
- ElemType data ;
- struct LNode * next ;
- } LNode, *pLinkList ;
2.为了简单,采用带头结点的单链表。
- #include <iostream>
- #include <time.h>
- #include <iomanip>
- #include <stdlib.h>
- using namespace std;
- typedef int ElemType;
-
- typedef struct LNode
- {
- ElemType data;
- struct LNode* next;
- }LNode, *pLinkList;
-
- pLinkList LinkList_Init() //单链表创建
- {
- int n;
- LNode *phead, *temp, *p;
- phead = new LNode;
-
- if (phead == NULL)
- {
- cout << "链表创建失败!" << endl;
- exit(0);
- }
- cout << "输入需要随机产生的元素的个数(不少于10个):";
- cin >> n;
- temp = phead;
- srand(unsigned(time(NULL)));
- for (int i = 0; i < n; i++)
- {
- p = new LNode;
- p->data = rand() % 100;
- temp->next = p;
- temp = p;
- }
- temp->next = NULL;
- return phead;
- }
- void LinkList_Display(pLinkList phead) //输出链表
- {
- phead = phead->next;
- while (phead)
- {
- cout << setw(4) << phead->data;
- phead = phead->next;
- }
- cout << endl;
- }
- void LinkList_Free(pLinkList phead) //链表释放
- {
- LNode *p;
- while (phead)
- {
- p = phead;
- phead = phead->next;
- delete p;
- }
- }
- void LinkList_Convert(pLinkList phead) //单链表中的元素逆置
- {
- LNode *p1, *p2, *p3; //p3为第一个结点,p2为第二个结点,p1为第三个结点
- if (phead->next == NULL)
- {
- cout << "链表为空!" << endl;
- return;
- }
- p3 = phead->next;
- p2 = p3->next;
- if (p2 == NULL)
- {
- return;
- }
- p1 = p2->next;
- p3->next = NULL;
- while (p1)
- {
- p2->next = p3;
- p3 = p2;
- p2 = p1;
- p1 = p1->next;
- }
- p2->next = p3;
- phead->next = p2;
- }
- void LinkLIst_Del_oushu(pLinkList phead) //删除单链表中所有的偶数元素结点
- {
- LNode *p1, *p2;
- p2 = phead;
- phead = phead->next;
- while (phead)
- {
- if (phead->data % 2 == 0)
- {
- p1 = phead;
- phead = phead->next;
- delete p1;
- p2->next = phead;
- continue;
- }
- p2 = phead;
- phead = phead->next;
- }
- }
- void LinkList_Sort(pLinkList phead) //排序
- {
- ElemType *num, temp;
- LNode *p;
- int count = 0, i = 0;
- if (phead->next == NULL)
- {
- cout << "链表为空!" << endl;
- return;
- }
- p = phead->next;
- while (p)
- {
- count++;
- p = p->next;
- }
- num = new ElemType[count];
- p = phead->next;
- while (p)
- {
- num[i++] = p->data;
- p = p->next;
- }
- for (int j = 0; j < count - 1; j++)
- for (int k = 0; k < count - j - 1; k++)
- if (num[k] > num[k + 1])
- {
- temp = num[k];
- num[k] = num[k + 1];
- num[k + 1] = temp;
- }
- p = phead->next;
- i = 0;
- while (p)
- {
- p->data = num[i++];
- p = p->next;
- }
- delete[] num;
- }
- void LinkList_Insert(pLinkList phead, ElemType elem) //插入一个元素
- {
- LNode *p1, *p2, *tmp = NULL;
- p1 = phead->next;
- p2 = phead;
- while (p1)
- {
- if (elem < p1->data)
- break;
- p2 = p1;
- p1 = p1->next;
- }
- tmp = new LNode;
- tmp->data = elem;
- p2->next = tmp;
- tmp->next = p1;
- }
- void LinkList_Divide(pLinkList L1, pLinkList L2) //链表分解成奇数和偶数两个链表
- {
- LNode *p1, *p2;
- p2 = L1;
- p1 = L1->next;
- while (p1)
- {
- if ((p1->data) % 2 == 0)
- {
- L2->next = p1;
- L2 = p1;
- p1 = p1->next;
- p2->next = p1;
- }
- else
- {
- p2 = p1; p1 = p1->next;
- }
- }
- L2->next = NULL;
- }
- void LinkList_Cat(pLinkList L1, pLinkList L2) //链表合并,
- {
- pLinkList p1, p2;
- p2 = L1;
- p1 = L1->next;
- while (p1)
- {
- p2 = p1; p1 = p1->next;
- }
- p2->next = L2->next;
- LinkList_Sort(L1);
- LinkList_Convert(L1);
- }
- int main()
- {
- LNode *L = NULL, *L1 = NULL, *L2 = NULL;
- int num;
- cout << "1:随机产生或键盘输入一组元素(不少于10个元素),建立一个带头结点的单链表" << endl;
- cout << "2:单链表中的元素逆置" << endl;
- cout << "3:单链表排序输出" << endl;
- cout << "4:删除单链表中所有的偶数元素结点" << endl;
- cout << "5:插入一个元素,用该函数建立一个非递减有序单链表(插入)" << endl;
- cout << "6:建立两个非递减有序单链表,然后合并成一个非递增链表(合并)" << endl;
- cout << "7:链表分解成两个链表,其中一个全部为奇数,另一个全部为偶数" << endl;
- cout << "8:退出" << endl;
- cout << endl;
- while (true)
- {
- cout << "请输入一个数字选项:";
- cin >> num;
- switch (num)
- {
- case 1:
- { L = LinkList_Init();
- cout << "L链表为:";
- LinkList_Display(L);
- cout << endl;
- }break;
- case 2:
- { LinkList_Convert(L);
- cout << "链表为:";
- LinkList_Display(L);
- cout << endl;
- }break;
- case 3:
- { LinkList_Sort(L);
- cout << "链表为:";
- LinkList_Display(L);
- cout << endl;
- }break;
- case 4:
- { LinkLIst_Del_oushu(L);
- cout << "链表为:";
- LinkList_Display(L);
- cout << endl;
- }break;
- case 5:
- { ElemType elem;
- cout << "输入要插入的元素:";
- cin >> elem;
- LinkList_Sort(L);
- LinkList_Insert(L, elem);
- cout << "链表为:";
- LinkList_Display(L);
- cout << endl;
- }break;
- case 6:
- {
- L1 = LinkList_Init();
- cout << "L1链表为:";
- LinkList_Display(L1);
- L2 = LinkList_Init();
- cout << "L2链表为:";
- LinkList_Display(L2);
- LinkList_Cat(L1, L2);
- cout << "合并的链表为:";
- LinkList_Display(L1);
- cout << endl;
- }break;
- case 7:
- {
- L2 = new LNode;
- LinkList_Divide(L1, L2);
- cout << "L1链表为:";
- LinkList_Display(L1);
- cout << "L2链表为:";
- LinkList_Display(L2);
- LinkList_Free(L2);
- cout << endl;
- }break;
- case 8:
- {
- LinkList_Free(L);
- delete L1;
- cout << endl;
- cout << "链表已释放并删除"<<endl;
- cout << endl;
- }break;
- default:
- cout << "输入错误!请重新输入!" << endl;
- cout << endl;
- }
- }
- return 0;
- }
双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。
头插法和尾插法只看代码比较难以与理解,建议画出插入节点时的链表变化图则会非常容易理解,另外,个人认为头插法较优,因为其插入逻辑一步到位,不像尾插法还需在后面完成双向链表的环状连接。
1.头插法
- Node * creatList()
- {
- Node * head = (Node*)malloc(sizeof(Node));
- Node * cur = NULL;
- head->next = head;
- head->pre = head;
- int data;
- scanf("%d",&data);
- while(data)
- {
- cur = (Node*)malloc(sizeof(Node));
- cur->data = data;
- cur->next = head->next;
- cur->pre = head;
- head->next = cur;
- cur->next->pre = cur;
- scanf("%d",&data);
- }
- return head;
- }
2.尾插法
- Node * creatList()
- {
- Node * head = (Node*)malloc(sizeof(Node));
- Node * phead = head;
- Node * cur = NULL;
- phead->next = NULL;
- phead->pre = NULL;
- int data;
- scanf("%d",&data);
- while(data)
- {
- cur = (Node*)malloc(sizeof(Node));
- cur->data = data;
- phead->next = cur;
- cur->pre = phead;
- phead = cur;
- scanf("%d",&data);
- }
- //完成回环
- cur->next = head;
- head->pre = cur;
- return head;
- }
1.利用尾插法建立一个双向链表。
2.遍历双向链表。
3.实现双向链表中删除一个指定元素。
4.在非递减有序双向链表中实现插入元素e仍有序的算法。
5.判断双向链表中元素是否对称,若对称返回 1,否则返回 0。
6.设元素为正整型,实现算法把所有奇数排列在偶数之前。
7.在主函数中设计一个简单菜单,调用上述算法。
双向链表的类型定义
- typedef int ElemType; // 元素类型
- typedef struct DuLNode
- {
- ElemType data;
- DuLNode *prior, *next;
- } DuLNode, *pDuLinkList;
- #include <iostream>
- #include <time.h>
- #include <stdlib.h>
- #include <iomanip>
- using namespace std;
-
- typedef int ElemType;
- typedef struct DuLNode
- {
- ElemType data;
- struct DuLNode *prior, *next;
- } DuLNode, *pDuLinkList;
-
- pDuLinkList DuLinkLinst_Init() //建立双向链表
- {
- int n;
- DuLNode *phead, *tmp, *p;
- srand(unsigned(time(NULL)));
- cout << "输入建立链表的元素个数:";
- cin >> n;
- phead = new DuLNode;
- phead->next = phead;
- phead->prior = phead;
- p = phead;
- for (int i = 0; i < n; i++)
- {
- tmp = new DuLNode;
- tmp->data = rand() % 100;
- tmp->prior = p;
- p->next = tmp;
- p = tmp;
- }
- p->next = phead;
- phead->prior = p;
- return phead;
- }
- void DuLinkList_Display(pDuLinkList phead) //输出双向链表
- {
- DuLNode *p;
- p = phead->next;
- while (p != phead)
- {
- cout << setw(4) << p->data;
- p = p->next;
- }
- cout << endl;
- }
- void DuLinkList_Free(pDuLinkList phead) //释放双链表
- {
- DuLNode *p, *t;
- p = phead->next;
- while (p != phead)
- {
- t = p;
- p = p->next;
- delete t;
- }
- delete p;
- }
- void DuLinkList_Del(pDuLinkList phead, ElemType x) //删除指定元素
- {
- DuLNode *p1, *p2;
- p1 = phead->next;
- p2 = phead;
- while (p1)
- {
- if (x == p1->data)
- {
- p2->next = p1->next;
- p1->next->prior = p2;
- delete p1;
- return;
- }
- p2 = p1;
- p1 = p1->next;
- }
- cout << "指定元素未找到!" << endl;
- }
- void DuLinkList_Sort(pDuLinkList phead) //排序
- {
- DuLNode *p;
- int count = 0, i = 0;
- ElemType *num, tmp;
- p = phead->next;
- if (p == phead)
- {
- cout << "双向链表为空!" << endl;
- return;
- }
- while (p != phead)
- {
- count++;
- p = p->next;
- }
- num = new ElemType[count];
- p = phead->next;
- while (p != phead)
- {
- num[i++] = p->data;
- p = p->next;
- }
- for (int k = 0; k < count - 1; k++)
- for (int j = 0; j < count - k - 1; j++)
- if (num[j] > num[j + 1])
- {
- tmp = num[j];
- num[j] = num[j + 1];
- num[j + 1] = tmp;
- }
- p = phead->next;
- i = 0;
- while (p != phead)
- {
- p->data = num[i++];
- p = p->next;
- }
- delete[] num;
- }
- void DuLinkList_Insert(pDuLinkList phead, ElemType elem) //插入一个元素
- {
- DuLNode *p, *tmp;
- p = phead->next;
-
- while (p != phead)
- {
- if (elem <= p->data)
- break;
- p = p->next;
- }
- tmp = new DuLNode;
- tmp->data = elem;
- tmp->next = p;
- tmp->prior = p->prior;
- p->prior->next = tmp;
- p->prior = tmp;
- }
- int DuLinkList_symmetry(pDuLinkList phead) //链表中元素是否对称
- {
- DuLNode *p1, *p2;
- p1 = phead->prior;
- p2 = phead->next;
- while (p1 != p2)
- {
- if (p1->data != p2->data)
- {
- return 0;
- }
- p1 = p1->prior;
- p2 = p2->next;
- }
- return 1;
- }
- void DuLinkList_jiousort(pDuLinkList phead) //奇数在偶数前面
- {
- DuLNode *p1, *p2;
- p1 = phead->next;
- p2 = p1->next;
- if (p1 == phead)
- {
- cout << "双向链表为空!" << endl;
- return;
- }
- if (p2 == phead)
- {
- return;
- }
- while (p1 != phead)
- {
- if ((p1->data) % 2 != 0)
- {
- p2 = p1;
- p1 = p1->next;
-
- p1->prior = p2->prior;
- p2->prior->next = p1;
-
- p2->next = phead->next;
- phead->next->prior = p2;
- phead->next = p2;
- p2->prior = phead;
- }
- else
- p1 = p1->next;
- }
- }
- int main()
- {
- DuLNode *L = NULL;
- ElemType t;
- int num;
- cout << "1:利用尾插法建立一个双向链表" << endl;
- cout << "2:遍历双向链表" << endl;
- cout << "3:双向链表中删除一个指定元素" << endl;
- cout << "4:在非递减有序双向链表中实现插入元素e仍有序的算法。" << endl;
- cout << "5:判断双向链表中元素是否对称,若对称返回 1,否则返回 0" << endl;
- cout << "6:设元素为正整型,实现算法把所有奇数排列在偶数之前" << endl;
- cout << "7:退出" << endl;
- while (true)
- {
- cout << "请输入一个数字选项:";
- cin >> num;
- switch (num)
- {
- case 1:
- {
- L = DuLinkLinst_Init();
- cout << "L双向链表为:";
- DuLinkList_Display(L);
- cout << endl;
- }break;
- case 2:
- {
- cout << "双向链表为:";
- DuLinkList_Display(L);
- cout << endl;
- }break;
- case 3:
- {
- cout << "输入需要删除的元素:";
- cin >> t;
- DuLinkList_Del(L, t);
- cout << "双向链表为:";
- DuLinkList_Display(L);
- cout << endl;
- }break;
- case 4:
- {
- cout << "输入要插入的元素:";
- cin >> t;
- DuLinkList_Sort(L);
- DuLinkList_Insert(L, t);
- cout << "双向链表为:";
- DuLinkList_Display(L);
- cout << endl;
- }break;
- case 5:
- {
- if(DuLinkList_symmetry(L)==1)
- cout << "双向链表中元素对称" << endl;
- else
- cout << "双向链表中元素不对称" << endl;
- cout << endl;
- }break;
- case 6:
- {
- DuLinkList_jiousort(L);
- cout << "双向链表为:";
- DuLinkList_Display(L);
- cout << endl;
- }break;
- case 7:
- {
- DuLinkList_Free(L);
- cout << endl;
- return 0;
- }break;
- default:
- cout << "输入错误!请重新输入!" << endl;
- cout << endl;
- }
- }
- return 0;
- }
如果把编程语言比作一个句子,那数据结构就好比是一篇文章。写好句子要意思清晰明确,写文章的话,更看重的是其传达的思想。马克吐温有句话是这样说的,当你手拿着锤子的时候,看见很多东西都是钉子。这句话原来的意思我不大想深究,毕竟这不是技术问题。而在读过了著名黑客雷蒙德的一篇经典文章《如何成 为一名黑客》,我对这个说法有一个新的感悟。他在文中写道:“做一名黑客会有很多乐趣,但却 是要费很多气力方能得到的乐趣。 这些努力需要动力。成功的运动员从锻炼身体、超越自我极限的愉悦中得到动力。 同样,做黑客,你得能从解决问题,磨练技术及锻炼智力中得到基本的乐趣。”锤子是工具,钉子是问题,当工具被用来解决你的问题的时候,享受那种满足的感觉, 是很难用言语来形容的。学习 C 语言不是光为了学习 C 语言,你是要用它来解决问题的。很遗憾在现实中,很多同学在大一大二学完了C 语言这门课程,甚至也考了一个不错的分数之后, 就把这门工具丢到一旁了,再也没理了。他们没有享受到这种乐趣,这是很可惜的。你是一个手拿锤子的人吗?握紧!
好叭。今天就到这里了,我也该去睡觉了,后续我还会发布更多的项目源或者学习资料,希望大家可以持续关注,有什么问题可以回帖留言。想要提前掌握的可以加群领取C/C++学习资料以及其他项目的源码的可以加群【1083227756】了解。想要对程序员的未来发展有兴趣的可以关注微信公众号:【狐狸的编码时光】,希望和大家一起学习进步!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。