数据结构1.2 - 线性表 应用

声明:大部分内容来自 - 《2019天勤数据结构高分笔记》

1. 顺序表:

1.1 初始化顺序表

void init(sqlist &L) //初始化有个递增的顺序表,L要改变,所以用引用型 
{
	L.length = 0;
}

1.2 查找

(1) 查找位置

int findElem(sqlist L,int x)
{
	int length = L.length;
	int i;
	for(i = 0; i < length; i++)
	{
		if(L.data[i] > x)
			return i;
	}
	return i;
}

(2)查找元素值为e的位置

int findElem(sqlist L, int e)
{
	int i;
	for(i = 0; i < L.length; i++ )
	{
		if(L.data[i] == e)
			return i;
	}
	return -1;
}

(3)查找位置p的元素

重点是判断位置p是否合理

int getElem(sqlist L, int p, int &e)
{
	if(p<0 || p>=L.length)
	{
		printf("位置错误!\n");
		return 0;
	}
	e = L.data[p];
}

1.3 一顺序表L,其中元素递增,设计算法使 插入一元素x(int型)后仍有序。

思路:1找到要插入位置p + 2进行插入操作

初始化 + 遍历 + 判满 + 插入 + 输出数组详请

完整版:

#include<bits/stdc++.h>
#define maxsize 100
using namespace std;

typedef struct sqlist
{
	int data[maxsize];
	int length;
}sqlist;

void init(sqlist &L) //初始化有个递增的顺序表,L要改变,所以用引用型 
{
	L.data[0] = 1;
	L.data[1] = 3;
	L.data[2] = 5;
	L.length = 3;
}

int findElem(sqlist L,int x)
{
	int length = L.length;
	int i;
	for(i = 0; i < length; i++)
	{
		if(L.data[i] > x)
			return i;
	}
	return i;
}

int isfull(sqlist L) 
{
	if(L.length >= maxsize)	
		return 0;
	return 1;
}

void trace(sqlist L)
{
	int i;
	printf("顺序表:");
	for(i = 0; i < L.length ;i++)
		printf("%d  ",L.data[i]);
	cout<<endl<<endl;
}

void insert(sqlist &L,int x) //L要改变,所以用引用型 
{
	
	int p = findElem(L,x);
	int i;
	
	for(i = L.length-1; i>=p ;i--)
		L.data[i+1] = L.data[i];
	L.data[p] = x;
	L.length++;
	printf("插入成功!\n");
	trace(L);
}

int main()
{
	int x;
	sqlist L;//定义一个循序表L 
	init(L); //初始化 
	trace(L);//遍历 
	while(L.length < maxsize)
	{
		int f = isfull(L); //判断是否已满 
		if( f = 1)
		{
			printf("输入要插入的元素整数x:"); 
			scanf("%d",&x);
			insert(L,x);
		}
		else
			printf("顺序表已满!\n");
	}
	return 0;
}

int findElem(sqlist L, int e)
{
	int i;
	for(i = 0; i < L.length; i++ )
	{
		if(L.data[i] == e)
			return i;
	}
	return -1;
}

1.4 删除顺序表中下标为p的元素,成功返回1,失败返回0,被删除元素值复制给e

#include<bits/stdc++.h>
#define maxsize 100
using namespace std;

typedef struct sqlist
{
	int data[maxsize];
	int length;
}sqlist;

void init(sqlist &L) //初始化有个递增的顺序表,L要改变,所以用引用型 
{
	L.data[0] = 1;
	L.data[1] = 3;
	L.data[2] = 5;
	L.length = 3;
}

int findElem(sqlist L,int x)
{
	int length = L.length;
	int i;
	for(i = 0; i < length; i++)
	{
		if(L.data[i] > x)
			return i;
	}
	return i;
}

void trace(sqlist L)
{
	int i;
	printf("顺序表:");
	for(i = 0; i < L.length ;i++)
		printf("%d  ",L.data[i]);
	cout<<endl<<endl;
}

int del(sqlist &L, int p, int &e)
{
	int i;
	e = L.data[p];
	for(i = p; i < L.length; i++)
	{
		L.data[i] = L.data[i+1];
	}
	L.length--;
	return 1;
}

int main()
{
	int x,e,p;
	sqlist L;//定义一个循序表L 
	init(L); //初始化 
	trace(L);//遍历 
	
	while(L.length > 0)
	{
		printf("输入位置p:"); 
		scanf("%d",&p);
		del(L,p,e);
		trace(L);
	}
	return 0;
}

2. 链表:

头结点:它一定是第一个结点,且值域是空
链表可分两类:1 带有头结点,2 不带头结点

头结点的好处:
1 头插法容易实现
2 一些条件判断不用去考虑 空链表 和 非空链表

5类链表:
1 单链表
2 双链表
3 循环单链表
4 循环双链表
5 静态链表(数组表示)

以下链表均带有头结点:

2.1 判空

无头结点均:

head == NULL;

2.1.1 单链表 and 双链表

有头结点head:

head -> next == NULL;

2.1.2 循环链表

有头结点:

head == head -> next;

2.1.3 循环双链表

有头结点:
下面4行代码,任一1个均可判断

head == head -> prior ;
head == head -> next ;
head == head -> next || head == head -> prior ;
head == head -> next && head == head -> prior ;

2.2 两个单链表A、B(均带头结点),元素均有序递增,设计算法,将A、B合并为链表C,C由A和B结点组成。

扩展:随机数生成

#include<bits/stdc++.h> 
using namespace std;

void myrand()
{
	int i;
	for(i = 0; i < 10; i++)
		printf("%d ", rand()%10);
	cout<<endl<<endl;
}

int main(void)
{
	srand(time(NULL));
	myrand();
	myrand();
	return 0;
}


该题思路:
1 定义链表结构
2 随机数预处理
3 初始化单链表
4 创建单链表,且结点的值非减,将详情输出,用尾插法(还有头插法,本文后面会有!)
5 合并两个单链表,也用尾插法(还有头插法,本文后面会有!)
6 讲合并的单链表详情输出

完整代码:

#include<bits/stdc++.h> 

#define num 100
using namespace std;

typedef struct LNode
{
	int data;
	struct LNode *next;
}*Link,LNode;

void init(LNode *&L)
{
	L = (LNode *)malloc(sizeof(LNode));
	L->next = NULL;
}

void creat(LNode *&L) // Link L 等价于  LNode *L
{
	LNode *q,*p=L;
	int length = rand()%num;
	int i,j;
	
	q = (LNode *)malloc(sizeof(LNode));
	j = rand()%num;
	while(j > num/6) //一开始就是很大的数,不太好,我希望数字可以分布均匀一点,这里j是最后的尾结点! 
	{
		j = rand()%num;
	}
	q->data = j;
	p->next = q;
	p = q;
	
	for(i = 0; i < length; i++)
	{
		q = (LNode *)malloc(sizeof(LNode));
		j = rand()%num;

		while(j < p->data)
		{
			j = rand()%num;
		}
		q->data = j;
		p->next = q;
		p = q;
	}
	p->next = NULL;
	printf("创建成功!\n"); 
}

void trace(LNode *L)
{
	LNode *p = L->next;
	if(p) 
	{
		while(p)
		{
			printf("%d ",p->data);
			p = p->next;
		}	
		printf("\n");
	}
	else
		printf("链表为空!\n");
}

void merge(Link A, Link B,Link &C) 
{
	Link p = A->next;
	Link q = B->next;
	Link r;
	free(B);
	C = A;
	C->next = NULL;
	r = C;
	
	while(p&&q)
	{
		if(p->data > q->data)
		{
			r->next = q;
			q = q->next;
			r = r->next;
		}
		else
		{
			r->next = p;
			p = p->next;
			r = r->next;
		}
	}
	if(p)
	{
		r->next = p;
	}
	else
		r->next = q;
	printf("成功!\n");
}

int main()
{
	srand(time(NULL));
	Link A,B,C;
	init(A);
	init(B);
	init(C);//初始化 
	
	printf("链表A");
	creat(A);
	printf("\n链表B");
	creat(B);
	
	printf("\n链表A:\n");
	trace(A); 
	
	printf("\n链表B:\n");
	trace(B);
	
	printf("\n链表A和链表B合并为链表C ");
	merge(A, B, C);
	printf("\n链表C:\n");
	trace(C);
	
	return 0;
}

2.2.1 创建单链表 之尾插法

一直在尾巴末尾添加结点,当添加一个结点时,注意谁是新的尾节点
关键代码:

		q->data = j;
		p->next = q;
		p = q;

完整代码见上题

2.2.2 创建单链表 之头插法

一直在头结点后面插入结点
关键代码:

		q->data = j;
		q->next = p->next;
		p->next = q;

完整代码:

#include<bits/stdc++.h> 

#define num 100
using namespace std;

typedef struct LNode
{
	int data;
	struct LNode *next;
}*Link,LNode;

void init(LNode *&L)
{
	L = (LNode *)malloc(sizeof(LNode));
	L->next = NULL;
}

void creat(LNode *&L) // Link L 等价于  LNode *L
{
	LNode *q, *p=L;
	int length = rand()%num;
	int i,j;
	
	q = (LNode *)malloc(sizeof(LNode));
	j = rand()%num;
	while(j < 5*num/6) //一开始就是很小的数,不太好,我希望数字可以分布均匀一点 
	{
		j = rand()%num;
	}
	q->data = j;
	q->next = NULL;
	p->next = q;
	
	for(i = 1; i < length; i++)
	{
		q = (LNode *)malloc(sizeof(LNode));
		j = rand()%num;

		while(j > p->next->data)
		{
			j = rand()%num;
		}
		q->data = j;
		q->next = p->next;
		p->next = q;
	}
	printf("创建成功!\n"); 
}

void trace(LNode *L)
{
	LNode *p = L->next;
	if(p) 
	{
		while(p)
		{
			printf("%d ",p->data);
			p = p->next;
		}	
		printf("\n");
	}
	else
		printf("链表为空!\n");
}

int main()
{
	srand(time(NULL));
	Link A;
	init(A);

	printf("链表A");
	creat(A);
	
	printf("\n链表A:\n");
	trace(A); 
	
	return 0;
}

2.2.3 删除结点

2.2.3.1 单链表删除第n个结点

删除结点p后一个结点q,而非结点p
关键

 	p->next = q->next;

更好的版本:

	p->next = q->next;	
	free(q);

完整代码:

#include<bits/stdc++.h>
#define num 100
using namespace std;

typedef struct LNode
{
	int data;
	struct LNode *next;
}*Link,LNode;

void init(LNode *&L)
{
	L = (LNode *)malloc(sizeof(LNode));
	L->next = NULL;
}

void creat(LNode *&L) // Link L 等价于  LNode *L
{
	LNode *q,*p=L;
	int length = rand()%num;
	int i,j;
	
	q = (LNode *)malloc(sizeof(LNode));
	j = rand()%num;
	while(j > num/6) //一开始就是很大的数,不太好,我希望数字可以分布均匀一点 
	{
		j = rand()%num;
	}
	q->data = j;
	p->next = q;
	p = q;
	
	for(i = 0; i < length; i++)
	{
		q = (LNode *)malloc(sizeof(LNode));
		j = rand()%num;

		while(j < p->data)
		{
			j = rand()%num;
		}
		q->data = j;
		p->next = q;
		p = q;
	}
	p->next = NULL;
	printf("创建成功!\n"); 
}

void del(Link &L, int e)
{
	LNode *p = L->next, *q, *r = L;
	int flag = 0,i = 1;
	
	while(p)
	{
		if(i == e)
		{
			q = p;
			r->next = p->next;
			free(q);
			flag = 1;
			printf("\n第%d个结点已被删除!\n", e);
			break;
		}
		i++;
		p = p->next;
		r = r->next;
	}
	if( flag == 0)
		printf("位置越界!\n");
}

void trace(LNode *L)
{
	LNode *p = L->next;
	if(p) 
	{
		while(p)
		{
			printf("%d ",p->data);
			p = p->next;
		}	
		printf("\n");
	}
	else
		printf("链表为空!\n");
}

int main()
{
	int e;
	srand(time(NULL));
	Link L;
	init(L);
	
	printf("链表L");
	creat(L); 
	
	printf("\n链表L:");
	trace(L);
	
	e = rand()%10 + 1;
	del(L, e);
	
	printf("\n链表L:");
	trace(L);
	
	return 0;
}


注意:这里删除操作分情况,有不同思路的代码:
1 删除第n个结点,那么每次查找结点要计数累加即可,再判断是否越界
2 删除结点值为n的结点,是删除第一个这样的结点(1个) 还是 所有的值为n的结点(2个及以上),判断一下是否存在这样的结点(0个),见下面的例子:

2.2.3.2 单链表删除值为n的结点

完整代码:

#include<bits/stdc++.h>
#define num 100
using namespace std;

typedef struct LNode
{
	int data;
	struct LNode *next;
}*Link,LNode;

void init(LNode *&L)
{
	L = (LNode *)malloc(sizeof(LNode));
	L->next = NULL;
}

void creat(LNode *&L) // Link L 等价于  LNode *L
{
	LNode *q,*p=L;
	int length = rand()%num;
	int i,j;
	
	q = (LNode *)malloc(sizeof(LNode));
	j = rand()%num;
	while(j > num/6) //一开始就是很大的数,不太好,我希望数字可以分布均匀一点 
	{
		j = rand()%num;
	}
	q->data = j;
	p->next = q;
	p = q;
	
	for(i = 0; i < length; i++)
	{
		q = (LNode *)malloc(sizeof(LNode));
		j = rand()%num;

		while(j < p->data)
		{
			j = rand()%num;
		}
		q->data = j;
		p->next = q;
		p = q;
	}
	p->next = NULL;
	printf("创建成功!\n"); 
}

void del(Link &L, int e)
{
	LNode *p = L->next, *q, *r = L;
	int flag = 0,i = 1;
	
	while(p)
	{
		if(p->data == e)
		{
			q = p;
			r->next = p->next;
			free(q);
			flag = 1;
			printf("\n值为%d的结点已被删除!\n", e);
			break;
		}
		i++;
		p = p->next;
		r = r->next;
	}
	if( flag == 0)
		printf("无值为%d的结点!\n",e);
}

void trace(LNode *L)
{
	LNode *p = L->next;
	if(p) 
	{
		while(p)
		{
			printf("%d ",p->data);
			p = p->next;
		}	
		printf("\n");
	}
	else
		printf("链表为空!\n");
}

int main()
{
	int e;
	srand(time(NULL));
	Link L;
	init(L);
	
	printf("链表L");
	creat(L); 
	
	printf("\n链表L:");
	trace(L);
	
	e = rand()%10 + 1;
	del(L, e);
	
	printf("\n链表L:");
	trace(L);
	
	return 0;
}



两个代码的不同之处 仅仅在于 条件判断:
while( p)后面的:
删除第n个结点:

if(i == e)

删除值为n的结点:

if(p->data == e)

2.3 双链表

2.3.1.1 尾插法创建双链表

void creat(DLink &L) //尾插法 
{
	DLink p = L, q;
	
	int length = rand()%num ; // 双链表长度
	int i ;
	
	for( i = 0; i < length; i++ )
	{
		q = (DLink)malloc(sizeof(DLNode));
		q->data = rand()%num;
		q->next = NULL;
		q->prior = p;
		p->next = q;
		p = q;
	}
	cout << "创建成功!" << endl << endl;
}

2.3.1.2 头插法创建双链表

void creat2(DLink &L) //头插法 
{
	DLink p = L, q;
	
	int length  = rand()%num;
	int i;
	
	cout << "随机生成:" ;
	
	for( i = 0; i < length; i++ )
	{
		q = (DLink)malloc(sizeof(DLNode));
		q->data = rand()%num;
		cout <<	q->data << " ";
		q->next = p->next;
		if(p->next)
			p->next->prior = q;
		q->prior = p;
		p->next = q;
	}
	cout << endl << "头插法创建成功!" << endl;
}

2.3.2 查找双链表第一个值为n的结点

void findElem(DLink L, int e)
{
	DLink p = L->next;
	int flag = 0, i = 1;
	
	while(p)
	{
		if(p->data == e)
		{
			flag = 1;
			break;
		}
		p = p->next;
		i++;
	}
	if( flag == 1)
		cout << "第" << i << "个结点是结点值为" << e << "的结点" << endl; 
	else
		cout << "无结点值为" << e << "的结点" << endl;
}

2.3.3 双链表第n个结点后插入一个结点

void insert(DLink L, int n, int e) //在第n个结点后 插入 结点值为e 的结点 
{
	DLink  p = L->next, q; 
	int i = 1;
	int length = getlength(L);
	
	if(length < n || n < 1)
	{
		cout << "位置越界!" << endl;
	}
	else
	{
		while(i < n) 
		{
			p = p->next;
			i++;
		}	
		q = (DLink)malloc(sizeof(DLNode));
		q->data = e;
		
		q->next = p->next;
		p->next->prior = q;
		p->next = q;
		q->prior = p;
		cout << "插入成功!" << endl;
	}
}

2.3.2 删除双链表第一个值为n的结点

void delElem(DLink L, int e)
{
	DLink p = L->next, q = L;
	int flag = 0 , i =1;
	
	while(p)
	{
		if(p->data == e)
		{
			flag = 1;
			q->next = p->next;
			p->next->prior = q;
			cout << "第" << i << "个结点,其值为" << e <<",已被删除!" << endl;
			break;
		}
		q = q->next;
		p = p->next;
		i++;
	}
	if( flag == 0)
		cout << "无结点值为" << e << "的结点!" << endl;
}

上面4部分可运行的完整代码:
https://paste.ubuntu.com/p/gGyCPWmrH3/

https://blog.csdn.net/qq_40893824/article/details/105890799(防网站中上面代码丢失)

运行结果:

2.4 循环链表

仅单循环链表:

尾结点的判断条件:

	p - > next == head;

完整的代码:

#include<bits/stdc++.h> 
#define num 100
using namespace std;

typedef struct Node
{
	int data;
	struct Node *next;
}*Link,Node;

void init(Link &L)
{
	L = (Link)malloc(sizeof(Node));
	L->next = L;
	cout << "初始化成功!" << endl;
}

void mycout(int n) 
{
	int i = 0;
	for(i = 0; i < n; i++)
		cout << endl;
}

void creat(Link &L)
{
	Link p = L,q;
	int length = rand()%num;
	int i;
	
	cout << "随机数:" << endl;
	for(i = 0; i < length; i++)
	{
		q = (Link)malloc(sizeof(Node));
		q->data = rand()%num;
		cout << q->data << " ";
		q->next = L->next;
		L->next = q;
		L = q;
	}
	cout << endl << "创建成功!" << endl;
}

void trace(Link L)
{
	Link p = L->next->next;
	
	while(p != L)
	{
		cout << p->data << " " ;
		p = p->next;
	}
	cout << p->data ;
	cout << endl;
}

int main()
{
	srand(time(NULL));
	Link L;
	int n;
	
	cout << "循环链表L" ;
	init(L);
	mycout(1);
	
	cout << "循环链表L" ;
	creat(L);
	mycout(1);
	
	cout << "循环链表L元素:" ;
	trace(L);
	
	return 0;
}


这里仅写循环链表的创建,插入和删除完全可以参考之前单链表的操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq_1403034144

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值