数据结构——线性表的简单应用

一、链表的相关操作

1、单链表

1、单链表的存储结构
//单链表
typedef int ElemType;
typedef struct PNode {
	ElemType data;
	struct PNode* next;
}PNode, * PN;
2、创建递增的单链表
//创建递增的有序链表
void CreateP(PN& P, int n) {
	P = new PNode;
	P->next = NULL;
	for (int i = 0; i < n; ++i) {
		PN S = new PNode;
		cin >> S->data;
		PN pre = P;
		PN q = P->next;
		while(q && q->data < S->data) {
			pre = pre->next;//pre=q;
			q = q->next;
		}
		S->next = q;
		pre->next = S;

	}
}
3、展示链表各结点值
//展示链表各结点值
void Display(PN& P) {
	PN p = P->next;
	while (p)
	{
		cout << p->data << " ";
		p = p->next;
	}
	cout << endl;
}
4、按输入的顺序建立链表
//创建链表(按输入的顺序存储)
void Create(PN& P) {
	P = new PNode;
	P->next = NULL;
	PN p = P;
	int n;
	while (cin>>n) {
		PN M = new PNode;
		M->next = NULL;
		M->data = n;
		p->next = M;
		p = p->next;
		if (cin.get() == '\n') break;
	}
}
5、链表的分解

将一个带头结点的单链表A分解为两个具有相同结构的链表B和C, 其中B表的结点为A表中值小于0的结点,而C表的结点为A表中值大于0的结点(A中元素为非0整数,要求B、C表利用A的结点)

法一:后插法
//链表的分解
void Decompose(PN& Pa,PN&Pb) {
	PN p = Pa;
	PN p1 = Pa->next;
	PN p2 = Pb;
	while (p1) {
		if (p1->data > 0) {
			p = p->next;
			p1 = p1->next;
		}
		else if (p1->data < 0) {
			PN r = p1;
			p->next = p1->next;
			p1 = p1->next;
			r->next = NULL;
			p2->next = r;
			p2 = p2->next;
		}
	}
}
法二:前插法
//将一个带头结点的单链表A分解为两个具有相同结构的链表B和C(前插法)
void Decompose2(PN& A, PN& B,PN&C) {
	PN p = A->next;//提前保存
	B = A;
	B->next = NULL;
	C = new PNode;
	C->next = NULL;
	while (p) {
		PN r = p->next;
		if (p->data < 0) {
			p->next = B->next;
			B->next = p;
		}
		else if(p->data > 0) {
			p->next = C->next;
			C->next = p;
		}
		p = r;
	}
}
6、确定长度为n的单链表中值最大的结点。
//一趟遍历确定长度为n的单链表中值最大的结点
ElemType LocateMaxElem(PN& P) {
	PN pMax = P->next;
	PN p = pMax->next;
	while (p) {
		if (pMax->data < p->data)
			pMax = p;
			p = p->next;
		
	}
	return pMax->data;
}
7、将链表中所有结点的连接方向逆转。
//将链表的次序颠倒
void ReverseP(PN& P)
{
	PN pre = P->next;
	PN p = pre->next;
	PN r =NULL;
	while (p) {
		r = p;
		pre->next = r->next;
		p = p->next;
		r->next = P->next;
		P->next = r;
	}
}
8、递归解决单链表问题
//递归算法求链表(存储整型数据)中的最大整数
int GetMax(PN& p) {
	if (!p->next)return p->data;//终止条件:链表只有一个结点
	else {
		int max=GetMax(p->next);//递归
		return max >= p->data ? max : p->data;
	}
}
//递归求解链表结点个数
int GetLength(PN& p) {
	if (!p->next)return 1;
	else {
		return GetLength(p->next)+1;
	}
}
//递归求所有整数的平均值
double GetAverage(PN& p,int n) {
	
	if (!p->next)return p->data;
	else {
		double l=GetAverage(p->next, n - 1);
		return (l * (n - 1) + p->data) / n;
	}
}

2、双向链表

1、双向循环循环链表的存储结构
//双向链表
typedef struct DNode {
	ElemType data;
	struct DNode* prior;
	struct DNode* next;
}DNode, * DN;
2、建立递增的双向循环链表
//建立递增的双向循环链表
void CreateD(DN& D, int n) {
	D = new DNode;
	D->next = D;
	D->prior = D;
	for (int i = 0; i < n; ++i) {
		DN S = new DNode;
		cin >> S->data;
		DN q = D->next;
		while (q != D && q->data < S->data) {
			q = q->next;
		}
		S->prior = q->prior;
		q->prior->next = S;
		S->next = q;
		q->prior = S;
		
	}
}
3、按输入值建立双向循环链表
//按输入值建立双向循环链表
void CreateDN(DN& D) {
	D = new DNode;
	D->next = D;
	D->prior = D;
	DN d = D;
	int n;
	while (cin >> n) {
		DN nd = new DNode;
		nd->data = n;
		d->next = nd;
		nd->prior = d;
		D->prior = nd;
		nd->next = D;
		d = d->next;
		if (cin.get() == '\n') break;
	}
}
4、展示双向循环链表的结点
//展示双向循环链表的结点
void DisplayD(DN& D) {
	DN p = D->next;
	while (p != D) {
		cout << p->data << " ";
		p = p->next;
	}
	cout << endl;
}
5、交换p所指向的结点及其前驱结点的顺序(p指向双向循环链表中的一个结点)
//交换p所指向的结点及其前驱结点的顺序(p指向双向循环链表中的一个结点)
void change(DN& p) {
	DN r = p->prior;
	p->prior = r->prior;
	r->prior->next = p;
	r->prior = p;
	r->next = p->next;
	p->next->prior = r;
	p->next = r;
}

 二、有序链表的相关操作(单链表实现)

1.将两个递增的有序链表合并为一个递增的有序链表。

要求结果链表仍使用原来两个链表的存储空间,不另外占用其他的存储空间。表中不允许有重复的数据。

void MergeP(PN& Pa, PN& Pb) {
	PN p1 = Pa->next;
	PN p2 = Pb->next;
	PN p = Pa;
	while (p1 && p2) {
		if (p1->data < p2->data) {
			p->next = p1;
			p = p1;
			p1 = p1->next;
		}
		else if (p1->data > p2->data) {
			p->next = p2;
			p = p2;
			p2 = p2->next;
		}
		else if(p1->data== p2->data) {
			p->next = p1;
			p = p1;
			p1 = p1->next;
			PN r = p2;
			p2 = p2->next;
			delete r;//删除重复数据
		}
	}
	p->next = p1 ? p1 : p2;
	delete Pb;
}

2.将两个非递减的有序链表合并为一个非递增的有序链表。

要求结果链表仍使用原来两个链表的存储空间,不另外占用其他的存储空间。表中允许有重复的数据。

法一:思路:可以先考虑颠倒链表的次序,再按第一题思路合并。其余步骤一致。

1.将链表的次序颠倒

//将链表的次序颠倒
void ReverseP(PN& P)
{
	PN pre = P->next;
	PN p = pre->next;
	PN r =NULL;
	while (p) {
		r = p;
		pre->next = r->next;
		p = p->next;
		r->next = P->next;
		P->next = r;
	}
}

2.将两个递减的有序链表合并为一个递减的有序链表(表中允许重复的数据)

//将两个递减的有序链表合并为一个递减的有序链表(表中允许重复的数据)
void MergeP2(PN& Pa, PN& Pb) {
    PN p1 = Pa->next;
    PN p2 = Pb->next;
    PN p = Pa;
    while (p1 && p2) {
        if (p1->data >= p2->data) {
            p->next = p1;
            p = p1;
            p1 = p1->next;
        }
        else if (p1->data < p2->data) {
            p->next = p2;
            p = p2;
            p2 = p2->next;
        }
    }
    p->next = p1 ? p1 : p2;
    delete Pb;
}

法二:前插法(不用颠倒次序)

//法二:前插法(不用颠倒次序):将两个递增的有序链表合并为一个递增的有序链表(表中不允许重复的数据)
void MergeP3(PN& Pa, PN& Pb) {
	PN p1 = Pa->next;
	PN p2 = Pb->next;
	PN P, p;P=p = Pa;
	P->next = NULL;//不要遗忘
	while (p1||p2) {
		if (!p1) {
			p = p2;
			p2 = p2->next;
		}
		else if (!p2) {
			p = p1;
			p1 = p1->next;
		}
		else if (p1->data <= p2->data) {
			p = p1;
			p1 = p1->next;
		}
		else if (p1->data > p2->data) {
			p = p2;
			p2 = p2->next;
		}
		p->next = P->next;
		P->next = p;
	}
	
	delete Pb;
}

3、删除递增有序链表中值大于mink,小于maxk的所有元素(mink,maxk是给定的两个参数)

//删除递增有序链表中值大于mink,小于maxk的所有元素(mink,maxk是给定的两个参数)
void DeleteP(PN& P,int mink,int maxk) {
	PN pre = P;
	PN p = P->next;
	while (p) {
		if (p->data > mink && p->data < maxk) {
			PN r = p;
			pre->next = p->next;
			p = p->next;
			delete r;
		}
		else
		{
			pre = pre->next;
			p = p->next;
		}
	}
}

三、集合相关运算

1、求集合的交集

已知两个链表A和B分别表示两个集合,其元素递增排列。请设计一个算法,用于求出A和B的交集,并存放在A链表中。

//求交集,并存放在A链表中
void Conjunction(PN& Pa, PN& Pb) {
	PN p1 = Pa->next;
	PN p2 = Pb->next;
	PN P, p; P = p = Pa;
	P->next = NULL;
	while (p1 && p2) {
		if (p1->data == p2->data) {
			p->next = p1;
			p = p1;
			p1 = p1->next;
			PN r = p2;
			p2 = p2->next;
			delete r;
		}
		else if (p1->data < p2->data)//删除较小元素
		{
			PN r = p1;
			p1 = p1->next;
			delete r;
		}
		else if (p1->data > p2->data) {
			PN r = p2;
			p2 = p2->next;
			delete r;
		}
	}
	while (p1) {
		PN r = p1;
		p1 = p1->next;
		delete r;
	}
	while (p2) {
		PN r = p2;
		p2 = p2->next;
		delete r;
	}
	delete Pb;
	
}

2、求集合的差

已知两个链表A和B分别表示两个集合,其元素递增排列。请设计算法求出两个集合A和B的差集,并以同样的形式存储,同时返回该集合的元素个数。

法一:

1.集合中元素个数

int Count(PN& P) {
	int j = 0;
	PN p = P->next;
	while (p) {
		p = p->next;
		j++;
	}
	return j;
}

2.求集合A和B的差集,并以同样的形式存储,同时返回该集合的元素个数。

//求集合A和B的差集,并以同样的形式存储,同时返回该集合的元素个数。
int Subtract(PN& Pa, PN& Pb) {
	PN p1 = Pa->next;
	PN p2 = Pb->next;
	PN p = Pa;
	int n = Count(Pa);
	while (p1) {
		p2 = Pb->next;
		while (p2) {

			if (p1&&p1->data == p2->data) {
				n--;
				PN r = p1;
				p->next = p1->next;
				p1 = p1->next;
				delete r;
			}
			p2 = p2->next;
		}
		if (p1 != NULL)
		{
			p = p1;
			p1 = p1->next;
		}
	}
	return n;
}

法二:

void Subtract(PN& Pa, PN& Pb,int &n) {
	PN p1 = Pa->next;
	PN p2 = Pb->next;
	PN p = Pa;
	while (p1 && p2) {
		if (p1->data < p2->data) {
			n++;
			p = p1;
			p1 = p1->next;
		}
		else if (p1->data >p2->data) {
			p2 = p2->next;
		}
		else {
			PN r = p1;
			p->next = p1->next;
			p1 = p1->next;
			delete r;
		}
	}
	while (p1) {
		n++;
		p1 = p1->next;
	}
}

四、顺序表的相关操作

1、顺序表的存储结构

//顺序表的存储结构
typedef struct {
	ElemType* elem;
	int length;
}L;

2、顺序表的初始化

//顺序表的初始化
Status InitList(L& l) {
	l.elem = new ElemType[MAXSIZE];
	if (!l.elem)exit(OVERFLOW);
	l.length = 0;
	return OK;
}

3、按输入值顺序存储

//按输入值顺序存储
void CreateL(L&l) {
	int m;
	while (cin >> m) {
		l.elem[l.length++] = m;
		if (cin.get()=='\n')break;
	}
}

 4、展示全部数据元素

//展示
void DisplayL(L& l) {
	for (int i = 0; i < l.length; i++) {
		cout << l.elem[i] << " ";
	}
	cout << endl;
}

5、删除线性表中所有值为item的数据元素

//删除顺序表中所有值为item的数据元素
void DeleteItem(L& l,int item) {
	int count =0;
	for (int i = 0; i < l.length; i++) {
		if (l.elem[i] != item) {
			l.elem[count++] = l.elem[i];
		}
	}
	l.length = count;
}

 五、附:前面所有题的完整代码

#include<iostream>
using namespace std;
//单链表
typedef int ElemType;
typedef struct PNode {
	ElemType data;
	struct PNode* next;
}PNode, * PN;
//创建链表(按输入的顺序存储)
void Create(PN& P) {
	P = new PNode;
	P->next = NULL;
	PN p = P;
	int n;
	while (cin>>n) {
		PN M = new PNode;
		M->next = NULL;
		M->data = n;
		p->next = M;
		p = p->next;
		if (cin.get() == '\n') break;
	}
}
//创建递增的有序链表
void CreateP(PN& P, int n) {
	P = new PNode;
	P->next = NULL;
	for (int i = 0; i < n; ++i) {
		PN S = new PNode;
		cin >> S->data;
		PN pre = P;
		PN q = P->next;
		while(q && q->data < S->data) {
			pre = pre->next;//pre=q;
			q = q->next;
		}
		S->next = q;
		pre->next = S;

	}
}
//将两个递增的有序链表合并为一个递增的有序链表(表中不允许重复的数据)
void MergeP(PN& Pa, PN& Pb) {
	PN p1 = Pa->next;
	PN p2 = Pb->next;
	PN p = Pa;
	while (p1 && p2) {
		if (p1->data < p2->data) {
			p->next = p1;
			p = p1;
			p1 = p1->next;
		}
		else if (p1->data > p2->data) {
			p->next = p2;
			p = p2;
			p2 = p2->next;
		}
		else if(p1->data== p2->data) {
			p->next = p1;
			p = p1;
			p1 = p1->next;
			PN r = p2;
			p2 = p2->next;
			delete r;//删除重复数据
		}
	}
	p->next = p1 ? p1 : p2;
	delete Pb;
}

//将链表的次序颠倒(前插法)
void ReverseP(PN& P)
{
	PN p = P->next;
	P->next = NULL;
	while (p) {
		PN r = p;
        p = p->next;
		r->next = P->next;
		P->next = r;
	}
}
//法一:将两个递减的有序链表合并为一个递减的有序链表(表中允许重复的数据)
void MergeP2(PN& Pa, PN& Pb) {
	PN p1 = Pa->next;
	PN p2 = Pb->next;
	PN p = Pa;
	while (p1 && p2) {
		if (p1->data >= p2->data) {
			p->next = p1;
			p = p1;
			p1 = p1->next;
		}
		else if (p1->data < p2->data) {
			p->next = p2;
			p = p2;
			p2 = p2->next;
		}
	}
	p->next = p1 ? p1 : p2;
	delete Pb;
}
//法二:前插法(不用颠倒次序):将两个递增的有序链表合并为一个递增的有序链表(表中不允许重复的数据)
void MergeP3(PN& Pa, PN& Pb) {
	PN p1 = Pa->next;
	PN p2 = Pb->next;
	PN P, p;P=p = Pa;
	P->next = NULL;//不要遗忘
	while (p1||p2) {
		if (!p1) {
			p = p2;
			p2 = p2->next;
		}
		else if (!p2) {
			p = p1;
			p1 = p1->next;
		}
		else if (p1->data <= p2->data) {
			p = p1;
			p1 = p1->next;
		}
		else if (p1->data > p2->data) {
			p = p2;
			p2 = p2->next;
		}
		p->next = P->next;
		P->next = p;
	}
	
	delete Pb;
}
//求交集,并存放在A链表中
void Conjunction(PN& Pa, PN& Pb) {
	PN p1 = Pa->next;
	PN p2 = Pb->next;
	PN P, p; P = p = Pa;
	P->next = NULL;
	while (p1 && p2) {
		if (p1->data == p2->data) {
			p->next = p1;
			p = p1;
			p1 = p1->next;
			PN r = p2;
			p2 = p2->next;
			delete r;
		}
		else if (p1->data < p2->data)//删除较小元素
		{
			PN r = p1;
			p1 = p1->next;
			delete r;
		}
		else if (p1->data > p2->data) {
			PN r = p2;
			p2 = p2->next;
			delete r;
		}
	}
	while (p1) {
		PN r = p1;
		p1 = p1->next;
		delete r;
	}
	while (p2) {
		PN r = p2;
		p2 = p2->next;
		delete r;
	}
	delete Pb;
	
}
//求集合A和B的差集,并以同样的形式存储,同时返回该集合的元素个数。
void Subtract(PN& Pa, PN& Pb,int &n) {
	PN p1 = Pa->next;
	PN p2 = Pb->next;
	PN p = Pa;
	while (p1 && p2) {
		if (p1->data < p2->data) {
			n++;
			p = p1;
			p1 = p1->next;
		}
		else if (p1->data >p2->data) {
			p2 = p2->next;
		}
		else {
			PN r = p1;
			p->next = p1->next;
			p1 = p1->next;
			delete r;
		}
	}
	while (p1) {
		n++;
		p1 = p1->next;
	}
}
//将一个带头结点的单链表A分解为两个具有相同结构的链表B和C(后插法)
void Decompose(PN& Pa,PN&Pb) {
	PN p = Pa;
	PN p1 = Pa->next;
	PN p2 = Pb;
	while (p1) {
		if (p1->data > 0) {
			p = p->next;
			p1 = p1->next;
		}
		else if (p1->data < 0) {
			PN r = p1;
			p->next = p1->next;
			p1 = p1->next;
			r->next = NULL;
			p2->next = r;
			p2 = p2->next;
		}
	}
}
//将一个带头结点的单链表A分解为两个具有相同结构的链表B和C(前插法)
void Decompose2(PN& A, PN& B,PN&C) {
	PN p = A->next;//提前保存
	B = A;
	B->next = NULL;
	C = new PNode;
	C->next = NULL;
	while (p) {
		PN r = p->next;
		if (p->data < 0) {
			p->next = B->next;
			B->next = p;
		}
		else if(p->data > 0) {
			p->next = C->next;
			C->next = p;
		}
		p = r;
	}
}
//展示链表各结点值
void Display(PN& P) {
	PN p = P->next;
	while (p)
	{
		cout << p->data << " ";
		p = p->next;
	}
	cout << endl;
}
//一趟遍历确定长度为n的单链表中值最大的结点
ElemType LocateMaxElem(PN& P) {
	PN pMax = P->next;
	PN p = pMax->next;
	while (p) {
		if (pMax->data < p->data)
			pMax = p;
			p = p->next;
		
	}
	return pMax->data;
}
//删除递增有序链表中值大于mink,小于maxk的所有元素(mink,maxk是给定的两个参数)
void DeleteP(PN& P,int mink,int maxk) {
	PN pre = P;
	PN p = P->next;
	while (p) {
		if (p->data > mink && p->data < maxk) {
			PN r = p;
			pre->next = p->next;
			p = p->next;
			delete r;
		}
		else
		{
			pre = pre->next;
			p = p->next;
		}
	}
}
//双向链表
typedef struct DNode {
	ElemType data;
	struct DNode* prior;
	struct DNode* next;
}DNode, * DN;
//建立递增的双向循环链表
void CreateD(DN& D, int n) {
	D = new DNode;
	D->next = D;
	D->prior = D;
	for (int i = 0; i < n; ++i) {
		DN S = new DNode;
		cin >> S->data;
		DN q = D->next;
		while (q != D && q->data < S->data) {
			q = q->next;
		}
		S->prior = q->prior;
		q->prior->next = S;
		S->next = q;
		q->prior = S;
		
	}
}
//按输入值建立双向循环链表
void CreateDN(DN& D) {
	D = new DNode;
	D->next = D;
	D->prior = D;
	DN d = D;
	int n;
	while (cin >> n) {
		DN nd = new DNode;
		nd->data = n;
		d->next = nd;
		nd->prior = d;
		D->prior = nd;
		nd->next = D;
		d = d->next;
		if (cin.get() == '\n') break;
	}
}
//交换p所指向的结点及其前驱结点的顺序(p指向双向循环链表中的一个结点)
void change(DN& p) {
	DN r = p->prior;
	p->prior = r->prior;
	r->prior->next = p;
	r->prior = p;
	r->next = p->next;
	p->next->prior = r;
	p->next = r;
}
//展示双向循环链表的结点
void DisplayD(DN& D) {
	DN p = D->next;
	while (p != D) {
		cout << p->data << " ";
		p = p->next;
	}
	cout << endl;
}
typedef int Status;
#define MAXSIZE 5
#define OVERFLOW -2
#define OK 1
#define ERROR 0
//顺序表
//顺序表的存储结构
typedef struct {
	ElemType* elem;
	int length;
}L;
//顺序表的初始化
Status InitList(L& l) {
	l.elem = new ElemType[MAXSIZE];
	if (!l.elem)exit(OVERFLOW);
	l.length = 0;
	return OK;
}
//按输入值顺序存储
void CreateL(L&l) {
	int m;
	while (cin >> m) {
		l.elem[l.length++] = m;
		if (cin.get()=='\n')break;
	}
}
//展示
void DisplayL(L& l) {
	for (int i = 0; i < l.length; i++) {
		cout << l.elem[i] << " ";
	}
	cout << endl;
}
//删除顺序表中所有值为item的数据元素
void DeleteItem(L& l,int item) {
	int count =0;
	for (int i = 0; i < l.length; i++) {
		if (l.elem[i] != item) {
			l.elem[count++] = l.elem[i];
		}
	}
	l.length = count;
}
int main() {
	/*L l;
	InitList(l);
	CreateL(l);
	DisplayL(l);
	DeleteItem(l, 2);
	DisplayL(l);*/
	/*DN D;
	CreateDN(D);
	cout << "D表结点:";
	DisplayD(D);
	DNode* p = D->next->next;
	change(p);
	cout << "交换后D表结点:";
	DisplayD(D);*/
	//PNode* Pa,Pb;
	//CreateP(Pa,5);
	//Create(Pa);
	/*cout << "A表结点:";
	Display(Pa);
	DeleteP(Pa, 2, 5);
	cout << "删除后A表结点:";
	Display(Pa);*/
	/*ReverseP(Pa);
	cout << "颠倒后A表结点:";
	Display(Pa);*/
	/*Pb = new PNode;
	Pb->next = NULL;*/
	//ReverseP(Pa);
	//CreateP(Pb, 3);
	//ReverseP(Pb);
	//MergeP(Pa, Pb);
	//MergeP2(Pa, Pb);
	//Conjunction(Pa, Pb);
	/*cout << "A表结点:";
	Display(Pa);
	Decompose(Pa,Pb);
	cout << "C表结点:";
	Display(Pa);
	cout << "B表结点:";
	Display(Pb);*/
	PN Pa;
	Create(Pa);
	Display(Pa);
	ReverseP(Pa);
	Display(Pa);
	/*cout << "最大结点:" << LocateMaxElem(Pa);*/
	/*int n = 0;
	Subtract(Pa, Pb, n);
	cout << "A-B元素个数:" << n << endl;
	Display(Pa);*/

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值