实验2:单链表基本操作一、实验目的1.学会定义单链表的结点类型,实现对单链表的一些基本操作和具体的函数定义,了解并掌握单链表的类定义以及成员函数的定义与调用。
2.掌握单链表基本操作及两个有序表归并、单链表逆置等操作的实现。
二、实验要求1.预习C语言中结构体的定义与基本操作方法。
2.对单链表的每个基本操作用单独的函数实现。
3.编写完整程序完成下面的实验内容并上机运行。
4.整理并上交实验报告。
三、实验内容1.编写程序完成单链表的下列基本操作:(1)初始化单链表La。
(2)在La中第i个元素之前插入一个新结点。
(3)删除La中的第i个元素结点。
(4)在La中查找某结点并返回其位置。
(5)打印输出La中的结点元素值。
2 .构造两个带有表头结点的有序单链表La、Lb,编写程序实现将La、Lb合并成一个有序单链表Lc。
合并思想是:程序需要3个指针:pa、pb、pc,其中pa,pb分别指向La表与Lb表中当前待比较插入的结点,pc 指向Lc表中当前最后一个结点。
依次扫描La和Lb中的元素,比较当前元素的值,将较小者链接到*pc 之后,如此重复直到La或Lb结束为止,再将另一个链表余下的内容链接到pc所指的结点之后。
3.构造一个单链表L,其头结点指针为head,编写程序实现将L逆置。
(即最后一个结点变成第一个结点,原来倒数第二个结点变成第二个结点,如此等等。
)四、思考与提高1.如果上面实验内容2中合并的表内不允许有重复的数据该如何操作?2.如何将一个带头结点的单链表La分解成两个同样结构的单链表Lb,Lc,使得Lb中只含La表中奇数结点,Lc中含有La表的偶数结点?/*----------------------------------------* 02_单链表.cpp -- 单链表基本操作* 对单链表的每个基本操作都用单独的函数来实现* 水上飘2009年写----------------------------------------*/// ds02.cpp : 定义控制台应用程序的入口点。
//#include "stdafx.h"#include<iostream>#include<iomanip>#include<ctime>using namespace std;typedef int ElemType;typedef struct LNode{ElemType data;struct LNode *next;}LNode, *LinkList;//确保输入的数据正确int Oncemore(){int n ;cout << "输入错误,请重新输入:" ;cin >> n ;cout << endl ;if( n <= 2 )n = Oncemore( ) ;return n ;}//初始化单链表Lvoid InitList(LinkList &L){L = (LinkList)malloc(sizeof(LNode));L->next = NULL;}//逆位序创建一个带头结点的单链线性表LinkList CreateList( LinkList &L, int n ){LinkList p ;for( int i = 0; i < n; i++ ){p = (LinkList)malloc(sizeof(LNode)) ;p->data = (int)(rand()%100) ; //给新生成的结点随机赋一个值p->next = L->next ; L->next = p ; //插入到表头}return L;}//在L中第i个元素之前插入一个新结点void Insert(LinkList &L, int i){LNode *p;LNode *p1;int m;p1 = L->next ;p = (LinkList)malloc(sizeof(LNode)) ;p->data = (int)(rand()%100) ; //给新生成的结点随机赋一个值for(m = 2; m < i; m++)p1 = p1->next ;if(m == i){p->next = p1->next ;p1->next = p;cout << "在L中第i个元素之前插入一个新结点成功.";}else cout << "在L中第i个元素之前插入一个新结点失败.";}//删除La中的第i个元素结点void Delete(LinkList &L, int j){LNode *p;LNode *p1;int m;p1 = L->next ;for(m = 1; m < j; m++){p1 = p1->next ;if(m == (j-2))p = p1; //p指向欲删除结点的前一个结点}if(m == j){p->next = p1->next ; //p结点指向欲删除结点的下一个结点delete p1;cout << "删除L中的第j个元素结点成功.";}else cout << "删除La中的第j个元素结点失败.";}//在L中查找某结点并返回其值int Lookup(LinkList &L, int k){LNode *p;p = L->next ;int i;for(i = 1; i < k; i++)p = p->next ;if(i == k){cout << "在L中查找第i个结点并返回其值成功.";return p->data ;}else{cout << "在L中查找i个结点并返回其值失败.";return 0;}}/*LinkList mix(LinkList &L){LinkList p1,p2,p3;p1 = L->next ;p2 = L->next ;p3 = L->next ;while(p1->next != NULL){if(p1->data > p1->next->data)p2 = p1->next ;p1 = p1->next ;}if(p3->next = NULL){L->next = NULL;return p1;}else{p3 = L->next ;while(p3->next != p2 && !p3->next)p3 = p3->next ;p3->next = p2->next ;p2->next = NULL ;return p2;}}void Union(LinkList &La,LinkList &Lb,LinkList &Lc) {LinkList pa,pb,pc;pc = Lc;while(La->next != NULL && Lb->next != NULL) {pa = mix(La);pb = mix(Lb);if(pa->data < pb->data){pc->next = pa ;pc = pa;}else{pc->next = pb ;pc = pb;}}if(La->next != NULL)pc->next = La->next ;if(Lb->next != NULL)pc->next = Lb->next ;}*///使线性表按值非递减排列void Notdegression( LinkList &L, int n ){int m ;LinkList pa;while(n){pa = L->next ;while( pa->next ) //当pa不为最后一个结点{if( pa->data > pa->next->data ) //交换两个结点的值{m = pa->data ;pa->data = pa->next->data ;pa->next->data = m ;pa = pa->next ; //移向下一个结点}else{pa = pa->next ; //移向下一个结点continue ;}}n-- ;}}//归并La和Lb,得到元素也按非递减排列的Lcvoid Merger( LinkList &La, LinkList &Lb, LinkList &Lc ){Lc = (LinkList)malloc(sizeof(LNode));LinkList pa, pb, pc ;pa = La->next ;pb = Lb->next ;Lc->next = NULL ; //初始化pc = Lc ;while(pa && pb) //当pa或pb没有到最后一个结点{if(pa->data < pb->data) //pa结点插入到Lc表的末端{pc->next = pa ;pc = pa ;pa = pa->next;}else{ //pb结点插入到Lc表的末pc->next = pb ;pc = pb;pb = pb->next ;}}pc->next = pa ? pa : pb ; /*判断La表和Lb表是否已插入完,若没有,则剩下的插入到Lc的末端*/delete La;delete Lb; //释放头结点}//将L逆置(即最后一个结点变成第一个结点,原来倒数第二个结点变成第二个结点,如此等等。
)void CutBack(LinkList &L){LinkList p1,p2,p3;p1 = L->next ;p3 = L ;while(p1->next) //p1指向最后一个结点,p3指向倒数第二个结点{p1 = p1->next ;p3 = p3->next ;}p2 = p1; //p2指向最后一个结点while(p3 != L) //实现倒置{p2->next = p3;p3->next = NULL ;p2 = L->next ; //指向第一个结点p3 = L ; //指向头结点while(p2->next) //p2指向新表的最后一个结点,p3指向倒数第二个结点{p2 = p2->next ;p3 = p3->next ;}}p2->next = NULL ; //让新表最后一个结点指向空p3->next = p1 ; //让p3即L头结点指向新表的第一个结点}//输出单链表Lvoid OutputList( LinkList &L ){cout << endl;LNode *L1 ;int i = 0 ;L1 = L->next ; //L1指向第一个结点while(L1->next != NULL){cout << setw(5) << L1->data ;L1 = L1->next ;i++ ;if( i % 5 == 0)cout << endl ;}cout << setw(5) << L1->data ; //输出最后一个结点的值cout << endl << endl ;}//第一题void FirstTitle(){cout << "第一题开始:" << endl;LinkList L;int n;cout << "输入表的元素个数:";cin >> n;if(n <= 2)n = Oncemore();InitList(L);CreateList(L,n);OutputList(L);int i,j;cout << "输入插入的位置:";cin >> i;Insert(L,i);OutputList(L);cout << "输入删除的位置:";cin >> j;Delete(L,j);OutputList(L);int k,m;cout << "输入要查找的结点的序号:";cin >> k;m = Lookup(L,k);cout << endl << "第" << k << "个结点的值是:" << m << endl;}//第二题void SecondTitle(){cout << "第二题开始:" << endl;LinkList La,Lb,Lc;int a,b;cout << "输入La的元素个数:";cin >> a;InitList(La);CreateList(La,a);OutputList(La);cout << "输入Lb的元素个数:";cin >> b;InitList(Lb);CreateList(Lb,b);OutputList(Lb);//Union(La,Lb,Lc); //第二题的第二种方法Notdegression(La,a);cout << "La按非递减排序后:" << endl ;OutputList(La);Notdegression(Lb,b);cout << "Lb按非递减排序后:" << endl ;OutputList(Lb);Merger(La,Lb,Lc);cout << "最后结果:" << endl;OutputList(Lc);}//第三题void ThirdTitle(){cout << "第三题开始:" << endl ;LinkList L;int a;cout << "输入L的元素个数:";cin >> a;InitList(L);CreateList(L,a);OutputList(L);CutBack(L);cout << "改变后的链表为:" << endl;OutputList(L);}void main(){srand(time(NULL));FirstTitle();cout << "---------------------------------------------------" << endl;SecondTitle();cout << "---------------------------------------------------" << endl;ThirdTitle();}。