数据结构实验——实验二链表实验

一、 实验任务

编写算法实现下列问题的求解。

(1)在第i个结点位置插入值为x的结点。

实验测试数据基本要求:

第一组数据:单链表长度n≥10,x=100,  i分别为5,n,n+1,0,1,n+2

第二组数据:单链表长度n=0,x=100,i=5

(2)删除单链表中第i个元素结点。

实验测试数据基本要求:

第一组数据:单链表长度n≥10,i分别为5,n,1,n+1,0

第二组数据:单链表长度n=0, i=5

(3)在一个递增有序的单链表L中插入一个值为x的元素,并保持其递增有序特性。

实验测试数据基本要求:

单链表元素为 (10,20,30,40,50,60,70,80,90,100),

x分别为25,85,110和8

(4)将单链表L中的奇数项和偶数项结点分解开(元素值为奇数、偶数),分别放入新的单链表中,然后原表和新表元素同时输出到屏幕上,以便对照求解结果。

实验测试数据基本要求:

第一组数据:单链表元素为 (1,2,3,4,5,6,7,8,9,10,20,30,40,50,60)

第二组数据:单链表元素为 (10,20,30,40,50,60,70,80,90,100)

(5)求两个递增有序单链表L1和L2中的公共元素,放入新的单链表L3中。

实验测试数据基本要求:

第一组

第一个单链表元素为 (1,3,6,10,15,16,17,18,19,20)

第二个单链表元素为 (1,2,3,4,5,6,7,8,9,10,18,20,30)

第二组

第一个单链表元素为 (1,3,6,10,15,16,17,18,19,20)

第二个单链表元素为 (2,4,5,7,8,9,12,22)

第三组

第一个单链表元素为 ()

第二个单链表元素为 (1,2,3,4,5,6,7,8,9,10)

(6)删除递增有序单链表中的重复元素,要求时间性能最好。

实验测试数据基本要求:

第一组数据:单链表元素为 (1,2,3,4,5,6,7,8,9)

第二组数据:单链表元素为 (1,1,2,2,2,3,4,5,5,5,6,6,7,7,8,8,9)

第三组数据:单链表元素为 (1,2,3,4,5,5,6,7,8,8,9,9,9,9,9)

(7)递增有序单链表L1、L2,不申请新结点,利用原表结点对两表进行合并,并使得合并后成为一个集合,合并后用L1的头结点作为头结点,删除多余的结点,删除L2的头结点。要求时间性能最好。

实验测试数据基本要求:

第一组

第一个单链表元素为 (1,3,6,10,15,16,17,18,19,20)

第二个单链表元素为 (1,2,3,4,5,6,7,8,9,10,18,20,30)

第二组

第一个单链表元素为 (1,3,6,10,15,16,17,18,19,20)

第二个单链表元素为 (2,4,5,7,8,9,12,22)

第三组

第一个单链表元素为 ()

第二个单链表元素为 (1,2,3,4,5,6,7,8,9,10)

二、 顺序表扩展实验

非必做内容,有兴趣的同学选做,

(1)(递增有序)单链表表示集合A、B,实现:

C=AB,C=AB,C=A-B

A=AB,A=AB,A=A-B

(2)(递增有序)单链表表示集合A、B,判定A是否B的子集。

(3)(2009)(15分)已知一个带有表头结点的单链表,结点结构如下图。假设该链表只给出了头指针list。在不改变链表的前提下,请设计一个尽可能高效的算法,查找链表中倒数第k个位置上的结点(k为正整数)。若查找成功,算法输出该结点的data值,并返回1;否则,只返回0。要求:

        描述算法的基本设计思想

        描述算法的详细实现步骤

        根据设计思想和实现步骤,采用程序设计语言描述算法(使用C 或C++语言实现),关键之处请给出简要注释。

  1. 三、算法设计

(3)递增插入:从前往后搜索,同时当前指针为前一个结点,当该节点的数小于x时,插入该元素。

(4)分为奇偶:建立两个新表1和2,对原表进行处理。在遍历过程中,当找到奇数时尾插入到新表1中;找到偶数时用尾插法插入到新表2中。

(5)有序C = A交B:每次取A和B中的一个最小元素,依次插入 C表即可。

当A->data < B->data时,A表中当前元素较小,插入C表。A表指针后移, 继续取A表的下一个元素,而B表指针不变;

当A->data > B->data时,B表中当前元素较小,插入C表。B表指针后移, 继续取B表的下一个元素,而A表指针不变;

当A->data == B->dat时,A、B表元素相同,或同时插入C表,或插入 一个。同时插入,执行A、B表指针后移,同时取下一 个元素。

重复执行上述判断、插入过程,直到A和B表中 有一个结束。

(6)删除重复元素:将元素分成:已经处理元素和待处理元素。分别用p, q表示。初始化         p = L->next, q = p->next。

      当p->data == q->data,说明q指示的是p的重复元素,继续处理 q 的下一个元素,即执行q = q->next。

当p->data < q->data时,因为 L 递增,所以剩下情况只能是p->data < q->data,q为目标元素。如果 p->next = q,说明q紧随 p,无需移动元素,直接pq后移即可。若不同q元素复制到 p->next。无论那种情况,都需要同时后移pq。循环执行上述操作,直到表尾。

(7)A = A 并 B:p,q分别指向L1,L2,u指向被删除的节点;

       当p->next->data > q->next->data时,A表中当前元素较小,q向后移一位。

当p->next->data < q->next->data时,B表中当前元素较小,因为递增性,B指示的元素不可能在A中,将该元素留在原表中。

当p->next->data == q->next->data时,A、B表元素相同删除B中的重复元素

重复执行上述判断、插入过程,直到A和B表中 有一个结束。若A表剩余直接就在其中,若B表剩余,则全满足。A尾结点p连接B首节点,删除B头结点

(8)A = A 并 B(见第7题)

A = A 交 B设置两个指针pa、pb分别指向A、B表当前处理的元素

当pa->next->data==pb->data时,pa->next 是交集结点,同时后移 pa、pb。

当pa->next->data<pb->data时,pa->next 不是交集结点,删除 pa->next 结点,pa 和 pb 不变

当pa->next->data>pb->data时,pa->next 可能在 pb 后面,pa 不变pb 后移。

重复以上过程,直至 A、B 中至少一个表结束。 如果 A 表未结束,pa->next 及后面所有结点都是非交集结点,删除

A = A 差 B设置两个指针p,q分别指向 A、B 表当前处理的元素

当p->next->data == q->next->data,则是交集元素,不是A-B 中元素,直接               删除A表元素。

当p->next->data > q->next->data, A的元素可能在 B 表的元素后面,p不动,移动q。

当p->next->data < q->next->data,A指示的元素不可能在 B 中出现,故比为 A-B 中元素。直接后移p。

重复以上过程,直至 A、B 中至少一个表结束。若B 表已结束,剩下元素全为 A-B 中元素。若A表已结束,则直接结束。

C = A 并 B设置三个指针p, q, R分别指向A、B、C表当前处理的元素;

                  当p->data < q->data时,A表中当前元素较小,因为递增性,p指示的元素

不可能在B中,将该元素插入C表,A表后移。

当p->data > q->data时,B表中当前元素较小,因为递增性,q指示的元素

              不可能在A中,将该元素加入C中,B表后移。

当p->data == q->data时,A、B表元素相同,插入一个到C中,同时取下一个元素。

重复执行上述判断、插入过程,直到A和B表中 有一个结束。若A表剩余直接插入C中,若B表剩余,则直接插入C中。

C = A 交 B(见第5题)。

C = A 差 B设置三个指针p, q, R分别指向A、B、C表当前处理的元素;

当p->data == q->data,则是交集元素,不是A-B 中元素,直接跳过,p,q后移。

当p->data > q->data,p指示的元素可能在 B 表 q指示的元素后面,p不动,移动q。

当p->data < q->data,p指示的元素不可能在 B 中出现,故比为 A-B 中元素。需要写入C中,然后p后移。

重复以上过程,直至 A、B 中至少一个表结束。若B 表已结束,剩下元素全为 A-B 中元素,全部迁移到目标位置。若A表已结束,则直接结束。

(9)是否为子集:设用pa和pb分别为A和B中元素的结点

当pa->data > pb->data时,即A表中当前元素大于B表中当前元素,因而需要继续 在B表中搜索,即要执行pb后移一个元素并继续搜索。

当pa->data == pb->data时,A表中当前元素在B表中,即查找成功, 同时后移。

当pa->data < pb->data时,即A表中当前元素小于B表中当前元素,因而肯定小于 其后面的所有元素,所以该元素肯定不在B中,所以不是子集,返回0。

重复执行上述判断过程,直到pa和pb中至少有一个指向表尾之后为止。此时,A表未结束。可返回结论1。若B表结束,可返回0。

(10)算法设计:利用双指针,使得第一个指针先向下走k个位置,此时两个指针之间间距为k。然后,让两个指针一起走,每次都向下移动一个位置,当先走的指针走到链表尾,后走的指针所处位置即为倒数第k个位置。
算法详细实现:定义两个指针p和q,都指向头节点。定义一个变量i=0,代表p走了几步;在p不为空并且i<k时,让p向下走k步。判断i是否等于k,如果不等于,返回0,否则让p和q一起向后走,直到p到达链表尾,q所处位置即为倒数第k个位置。

#define MAXLEN 100
#include <iostream>

using namespace std;
typedef struct slNode{
	int data;
	struct slNode *next;
}node;
typedef struct lNode{
	int data;
	struct lNode *link;
}Node;
//初始化一个新单链表 
void initList(node *&L){
	L = new node;
	L->next = NULL;
}
//读取数组元素到单链表中 
void creatList(node *&L, int a[], int n){
	int i;
	L = new node;
	node * R;
	R = L; 
	L->next = NULL; 
	for(i = 0; i < n; i++){	//将数组元素读入单链表中 
		node *s = new node;
		s->next = R->next;
		s->data = a[i];
		R->next = s;
		R = s;	
	}
}
void destroyList(node *&L){
    node *p,*q;
    p = L;          //初始化时p指向头结点
    while(p!=NULL) //p不为空时执行
    {
        q = p->next; //q变量记录p的下一个节点
        delete p;  //释放p结点
        p = q;       //把q赋值给p
    } 
}
//展示单链表元素 
void displayL(node *L){
	node *p = L->next;
	if(p == NULL){
		cout << "表为空!"; 
	} 
	while(p != NULL){	//遍历打印出单链表元素 
		cout << p->data << " ";
		p = p->next; 
	}
	cout << endl;
}
//基本插入元素 
bool listInsert(node *L, int x, int i){
	bool flag = 0;
	node *s, *p = L;
	int j = 0;
	while(j != i -1 && p != NULL){
		p = p->next;
		j++;
	}
	if(p == NULL){
		cout << "序号错误!" << endl;
	}else{
		s = new node;
		s->data = x;
		s->next = p->next;
		p->next = s;
		flag = 1;
	}
	return flag;
}
//基本删除元素 
bool listDelete(node *L, int i){
	bool flag = 0;
	node *s, *p = L;
	int j = 0;
	while(j != i -1 && p != NULL){
		p = p->next;
		j++;
	}
	if(p == NULL || p->next == NULL)
		cout << "序号" << i << "超出范围,删除失败!" << endl;		//超出范围,不能删除
	else{
		s = p->next;
		p->next = s->next;
		delete s;
		flag = 1;
	}
	return flag;
}
//递增有序插入 
void Insert(node *L, int x){
		node *s, * p = L;
		while(p->next != NULL && p->next->data<x){
			p = p->next;
		}
		s = new node;
		s->data = x;
		s->next = p->next;
		p->next = s;
}
//分为奇偶单链表 
void part(node *L, node *A, node *B){
	node *s, * p = L->next;
	node *R, *Q;
	R = A;
	Q = B;
	while(p != NULL){		
		if(p->data % 2 == 0)	//为偶数,进入A中 
		{
			s = new node;
			s->data = p->data;
			s->next = R->next;
			R->next = s;
			R = s;
			p = p->next; 
		}else{		//为奇数,进入B中 
			s = new node;
			s->data = p->data;
			s->next = Q->next;
			Q->next = s;
			Q = s;
			p = p->next;
		} 
	}
}
//C = A 交 B 
void merge(node *A, node *B, node *C){
	node *p, *q, *s, *R;
	p = A->next;
	q = B->next;
	R = C;
	while (p != NULL && q != NULL){
		if (p->data < q->data){//A小于B,A元素可能在B元素后面,A元素后移 
			p = p->next;
		}else if (p->data > q->data){
			q = q->next;//B小于A,B元素可能在A元素后面,B元素后移
		}else{//交集元素,加入C 
			s = new node;
			s->data = q->data;
			s->next = R->next;
			R->next = s;
			R = s;
			p = p->next;
			q = q->next;
		}
	}
}
//删除重复元素 
int DeleteRepeatData(node *&L){
	int sum; 
	sum = 0;
	node *s, *q, *p = L->next;
	q = p->next;
	while(q != NULL){
		if(p->data == q->data) //为重复元素,q 后移
			q = q->next;
		else{ //因为 L 递增,所以剩下情况即 p->data < q->data
			if((p->next) != q){//如果p->next = q,说明q紧随 p,无需移动元素,直接两指针后移 
				p->next->data = q->data; 
				sum++;
			}
			p = p->next; //无论那种情况,都需要同时后移pq 
			q = q->next;
			
		}
	}
	destroyList(p->next); 
	p->next = NULL;
	return sum;
}
//A = A 并 B 
void Add(node *L1, node *L2){
	node *p,*q,*u;        //p,q分别指向L1,L2,u指向被删除的节点
    p = L1;                 //初始化时指向头结点L1
    q = L2;                 //初始化时指向头结点L2
    while(p->next != NULL && q->next != NULL)
    {
        if(p->next->data == q->next->data)
        {
            u = q->next;       //把要删除的节点指针赋值给u
            q->next = u->next; //连接要删除结点的前后结点
            delete u;         //如果L1,L2有重复元素,删除L2中的重复元素
            p = p->next;       //p向后移一位,q不移
        }
        else if((p->next->data) > (q->next->data))
        {
            q = q->next;       //如果(p->next->data)>(q->next->data),q向后移一位
        }
        else{
            p = p->next;       //如果(p->next->data)<(q->next->data),p向后移一位
        }
    }
    if(p->next != NULL)        //如果p没有指向尾结点,使它指向尾结点
    {
        while(p->next != NULL)
        {
            p = p->next;
        }
    }
    p->next = L2->next;         //L1尾结点p连接L2首节点
    delete L2;                 //删除L2头结点
}
//A = A 交 B 
void InterSet(node *A, node *B){
	node* pa, *pb, *u, *p;
	pa=A; //Pa 指向 A
	pb=B->next; //pb 指向 B 的首元素结点
	while(pa->next && pb) //A、B 都有结点,循环处理
	{
		if(pa->next->data<pb->data){ //pa->next 不是交集结点,删除 pa->next 结点,pa 和 pb 不变
			u=pa->next;
			pa->next=u->next;
			delete u;
		}else if(pa->next->data>pb->data) //pa->next 可能在 pb 后面,pa 不变,pb 后移
			pb=pb->next;
		else //pa->next->data==pb->data 情况,pa->next 是交集结点,同时后移 pa、pb
		{
			pa=pa->next;
			pb=pb->next;
		}
	}
 //如果 A 表未结束,pa->next 及后面所有结点都是非交集结点,删除
	if(pa->next) //置 A 表结束
	{
		u=pa->next;
		pa->next=NULL;
		p=u;
 //删除 A 表剩下的非交集结点
		while(p){
			u=p;
			p=p->next;
			delete u;
		}
	}

}
//A = A 差 B 
void SetSubtraction(node *&A, node *&B){
	node *s;
	node *p = A;
	node *q = B; 
	while(p->next != NULL && q->next != NULL){
		if(p->next->data == q->next->data){
			s = p->next;
			p->next = s->next;
			delete s;
		}else if(p->next->data > q->next->data){
			q = q->next;
		}else{
	 		p = p->next;	
		}
	}
}
//C = A 并 B
void MergeList(node *A, node *B, node *C){
	node *p, *q, *s, *R;
	p = A->next;
	q = B->next;
	R = C;
    while(p != NULL && q != NULL){
        if(p->data == q->data){	//A、B表元素相同,插入一个。同时后移 
			s = new node;
			s->data = q->data;
			s->next = R->next;
			R->next = s;
			R = s;
			p = p->next;
			q = q->next;
		}else if(p->data < q->data){	//A表中当前元素较小,插入C表。A表后移 ,
			s = new node;
			s->data = p->data;
			s->next = R->next;
			R->next = s;
			R = s;
			p = p->next;	//继续取A表的下一个元素,而B表不变;
		}else{								//B表中当前元素较小,插入C表。B表后移,
			s = new node;
			s->data = q->data;
			s->next = R->next;
			R->next = s;
			R = s;
			q = q->next;	//继续取B表的下一个元素,而A不变;	
        }
    }
    //下面处理一个表结束,另一个表未结束情况
    while(p){
		s = new node;
		s->data = p->data;
		s->next = R->next;
		R->next = s;
		R = s;
		p = p->next;
    }
    while(q){
		s = new node;
		s->data = q->data;
		s->next = R->next;
		R->next = s;
		R = s;
		q = q->next;
	}
}
//C = A 差 B
void cha(node *A, node *B, node *C){
   node *p, *q, *s, *R;
	p = A->next;
	q = B->next;
	R = C;
	while (p != NULL && q != NULL){
		if (p->data < q->data){//A小于B,A元素不可能在B元素后面,插入C,A元素后移 
			s = new node;
			s->data = p->data;
			s->next = R->next;
			R->next = s;
			R = s;
			p = p->next;
		}else if (p->data > q->data){
			q = q->next;//B小于A,B元素可能在A元素后面,B元素后移
		}else{
			p = p->next;
			q = q->next;
		}
	}
	while(p != NULL){
		s = new node;
		s->data = p->data;
		s->next = R->next;
		R->next = s;
		R = s;
		p = p->next;
	}
}
//判断是否为子集 
bool ZiJi(node *A, node *B){ 
	node *pa, *pb;
	pa = A->next; //pa 和 pb 分别指向 A 和 B 表的首元素结点
	pb = B->next;
	while(pa != NULL && pb != NULL){
		if(pa->data == pb->data){ //pa 指示元素在 B 中,因是集合,pa、pb 同时后移一个结点
			pa = pa->next;
			pb = pb->next;
		}else if(pa->data > pb->data) 
			pb = pb->next; //pa 指示元素可能在 B 中 pb 指示的元素后面,后移 pb
		else
			return 0; //此时,pa->data<pb->data,pa 指示元素不可能在 B 中,A 非 B子集
	}
 //下面根据 A、B 的结束情况,判定 A 是否 B 的自己
	if(pa == NULL)
		return 1; //A 到表尾,不管 B 表如何,A 全部元素在 B 中,是 B 的子集
	else
		return 0; //B 到表尾,A 未到表尾,A 后面元素不在 B 中,A 非 B 的子集
}
int function(Node *list, int k){
	Node *p , *q;
	p = list;
	q = list->link;
	int i = 0;
	while(i < k && p->link){
		p = p->link;
		i++;	
	}
	// 链表不够长,没等p走k步就结束了 
	if(!p){
		return 0;
	}
	while(p->link){
		p = p->link;
		q = q->link;
	} 
	cout << q->data << endl;;
	return 1;
	
} 
void creatList2(Node *&L, int a[], int n){
	int i;
	L = new Node;
	Node * R;
	R = L; 
	L->link = NULL; 
	for(i = 0; i < n; i++){	//将数组元素读入单链表中 
		Node *s = new Node;
		s->link = R->link;
		s->data = a[i];
		R->link = s;
		R = s;	
	}
}


 

  • 15
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值