数据结构实验3:线性表、堆栈和队列的操作与实现(C语言)

一、实验目的

1、线性表的链表实现:遍历、查找、插入、删除、翻转

2、栈的链式存储结构实现:入栈、出栈

3、队列的链式存储结构的实现:入队、出队

4、线性表、栈和队列的应用实现

二、实验类型: 验证性

三、实验学时:4学时(二周)

四、实验教学重点和难点

重点线性表、堆栈和队列链式存储结构的C或C++语言的实现方法

难点:指针操作

五、实验内容

1、单链表实验、实现单链表的基本功能

(1)实现链表结点的创建功能

(2)实现单链表的创建功能

(3)实现单链表的插入功能

(4)实现单链表的删除功能

(5)实验单链表某个数据的查找(成功或不成功,成功时位置)

#include 
#include 
#include 
#include 

struct Node
{
	int data; //数据域
	struct Node* next; //指针域
	int length; //链表长度
};

//创建链表
struct Node* createList()
{
	struct Node* headNode = (struct Node*)malloc(sizeof(struct Node));
	headNode->next = NULL;
	return headNode;
}

//创建结点,有数据域
struct Node* createNode(int data)
{
	struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
	newNode->data = data;
	newNode->next = NULL;
	return newNode;
}

//打印链表
void printList(struct Node* headNode)
{
	struct Node* pMove = headNode->next;
	for (int i = 0; i < headNode->length; i++)
	{
		printf("%d ", pMove->data);
		pMove = pMove->next;
	}
	printf("\n");
}

//插入(头插法)
void insertNodeHead(struct Node* headNode, int data)
{
	struct Node* newNode = createNode(data);
	newNode->next = headNode->next;
	headNode->next = newNode;
	headNode->length++;
}

//指定位置插入
void insertNodePos(struct Node* headNode, int data, int pos)
{
	struct Node* newNode = createNode(data);
	struct Node* pNode = (struct Node*)malloc(sizeof(struct Node));
	pNode = headNode;
	if (pos > (headNode->length + 1))
		printf("插入位置不合理!\n");
	else
	{
		for (int i = 0; i < pos - 1; i++)
			pNode = pNode->next;
		newNode->next = pNode->next;
		pNode->next = newNode;
		headNode->length++;
		printf("插入成功!\n");
	}
}

//删除结点
void deleteNode(struct Node* headNode, int posdata)
{
	struct Node* posNode = headNode->next;
	struct Node* posNodefront = headNode;
	if (posNode == NULL)
		printf("链表为空,无法删除!\n");
	else
	{
		while (posNode->data != posdata)
		{
			posNodefront = posNode;
			posNode = posNodefront->next;
			if (posNode == NULL)
			{
				printf("没有找到相关信息,无法删除!\n");
				return;
			}
		}
		posNode = posNodefront->next; //临时保存被删结点的地址以备释放
		posNodefront->next = posNode->next;
		free(posNode);
		headNode->length--;
		printf("删除成功!\n");
	}
}

//查找
void findNode(struct Node* headNode, int data)
{
	struct Node* pNode = (struct Node*)malloc(sizeof(struct Node));
	pNode = headNode->next;
	int i = 0;
	while (pNode->next)
	{
		i++;
		if (pNode->data == data)
		{
			printf("查找成功!该数据位于链表的第 %d 位\n", i);
			break;
		}
		pNode = pNode->next;
	}
	if (pNode->next == NULL)
		printf("查找失败,该数据不在链表中!\n");
}

2、线性表的链表实现:

(1)用随机函数生成10个3位整数(100~999),把这些整数存于链表中;

(2)输出链表的内容;

(3)读入一个整数,查看该整数是否在表中,若在,输出其位置(首位置为1);

(4)读入一个整数,以及要插入的位置,把该整数插入到链表中,输出链表的内容(要求判断输入的位置是否合理);

(5)读入一个整数,若该整数在链表里,删除该整数,输出链表的内容;

(6)把链表的内容翻转,输出链表的内容。

#include 
#include 
#include 
#include 

struct Node
{
	int data; //数据域
	struct Node* next; //指针域
	int length; //链表长度
};

//创建链表
struct Node* createList()
{
	struct Node* headNode = (struct Node*)malloc(sizeof(struct Node));
	headNode->next = NULL;
	return headNode;
}

//创建结点,有数据域
struct Node* createNode(int data)
{
	struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
	newNode->data = data;
	newNode->next = NULL;
	return newNode;
}

//打印链表
void printList(struct Node* headNode)
{
	struct Node* pMove = headNode->next;
	for (int i = 0; i < headNode->length; i++)
	{
		printf("%d ", pMove->data);
		pMove = pMove->next;
	}
	printf("\n");
}

//插入(头插法)
void insertNodeHead(struct Node* headNode, int data)
{
	struct Node* newNode = createNode(data);
	newNode->next = headNode->next;
	headNode->next = newNode;
	headNode->length++;
}

//指定位置插入
void insertNodePos(struct Node* headNode, int data, int pos)
{
	struct Node* newNode = createNode(data);
	struct Node* pNode = (struct Node*)malloc(sizeof(struct Node));
	pNode = headNode;
	if (pos > (headNode->length + 1))
		printf("插入位置不合理!\n");
	else
	{
		for (int i = 0; i < pos - 1; i++)
			pNode = pNode->next;
		newNode->next = pNode->next;
		pNode->next = newNode;
		headNode->length++;
		printf("插入成功!\n");
	}
}

//删除结点
void deleteNode(struct Node* headNode, int posdata)
{
	struct Node* posNode = headNode->next;
	struct Node* posNodefront = headNode;
	if (posNode == NULL)
		printf("链表为空,无法删除!\n");
	else
	{
		while (posNode->data != posdata)
		{
			posNodefront = posNode;
			posNode = posNodefront->next;
			if (posNode == NULL)
			{
				printf("没有找到相关信息,无法删除!\n");
				return;
			}
		}
		posNode = posNodefront->next; //临时保存被删结点的地址以备释放
		posNodefront->next = posNode->next;
		free(posNode);
		headNode->length--;
		printf("删除成功!\n");
	}
}

//查找
void findNode(struct Node* headNode, int data)
{
	struct Node* pNode = (struct Node*)malloc(sizeof(struct Node));
	pNode = headNode->next;
	int i = 0;
	while (pNode->next)
	{
		i++;
		if (pNode->data == data)
		{
			printf("查找成功!该数据位于链表的第 %d 位\n", i);
			break;
		}
		pNode = pNode->next;
	}
	if (pNode->next == NULL)
		printf("查找失败,该数据不在链表中!\n");
}

//翻转(一直往后迭代)
void reverseNode(struct Node* headNode)
{
	struct Node* p1 = NULL; //前一个
	struct Node* p2 = headNode->next; //后一个
	while (p2)
	{
		struct Node* nextNode = p2->next;
		p2->next = p1;
		p1 = p2;
		p2 = nextNode;
	}
	headNode->next = p1->next;
}

int main()
{
	time_t t;
	srand((unsigned)time(&t));

	struct Node* headNode, * pNode;
	headNode = (struct Node*)malloc(sizeof(struct Node)); //初始化头结点
	pNode = (struct Node*)malloc(sizeof(struct Node)); //申请第一个结点
	headNode->next = pNode; //连接俩结点

	//随机函数生成10个3位整数(100~999)存于链表中并输出
	printf("该链表为:\n");
	for (int i = 0; i < 10; i++)
	{
		pNode->data = rand() % 900 + 100;
		printf("%d ", pNode->data);
		pNode->next = (struct Node*)malloc(sizeof(struct Node)); //申请下一个结点
		pNode = pNode->next; //将两结点连起来
	}
	headNode->length = 10;
	pNode->next = NULL; //尾结点next指向空
	printf("\n");

	int choice = 0;
	do
	{
		printf("\n  1 - 查找, 2 - 插入, 3 - 删除, 4 - 翻转, 0 - 退出\n  请选择:");
		scanf_s("%d", &choice);
		printf("\n");

		switch (choice)
		{
		case 1:
		{
			int num = 0;
			printf("请输入要查找的数据:");
			scanf_s("%d", &num);
			findNode(headNode, num);
			break;
		}
		case 2:
		{
			int num = 0, pos = 0;
			printf("请输入要插入的数据:");
			scanf_s("%d", &num);
			printf("请输入要插入的位置:");
			scanf_s("%d", &pos);
			insertNodePos(headNode, num, pos);
			printf("链表为:\n");
			printList(headNode);
			break;
		}
		case 3:
		{
			int num = 0;
			printf("请输入要删除的数据:");
			scanf_s("%d", &num);
			deleteNode(headNode, num);
			printf("链表为:\n");
			printList(headNode);
			break;
		}
		case 4:
		{
			reverseNode(headNode);
			printf("链表翻转后为:\n");
			printList(headNode);
			break;
		}
		case 0:
			printf("感谢使用!\n"); break;
		}
	} while (choice);

	free(headNode);
	free(pNode);

	return 0;
}

3、栈的顺序存储结构实现

(1)用随机函数生成10个3位整数(100~999),把这些整数应用入栈操作存于堆栈中,在入栈接口处设置断点①,按“F5”启动调试,按“F10”逐句执行,直到数据全部入栈。程序暂停时观察栈顶数据和栈顶位置;

入栈完成top指针在栈顶元素的上方

(2)应用出栈操作输出堆栈的内容,在出栈接口处设置断点②,按“F5”启动调试,按“F10”逐句执行,直到所有数据完全出栈,程序暂停时观察栈顶数据和栈顶位置的变化;

出栈完成base指针等于top指针

#include 
#include 
#include 
#include 
#define maxsize 100 

struct SqStack
{
	int* base;
	int* top;
	int stacksize;
};

//初始化
void InitStack(struct SqStack* S)
{
	S->base = (int*)malloc(sizeof(int) * maxsize);
	if (!S->base)
		exit(-2); //存储内存分配失败
	S->top = S->base;  //top初始为base,空栈
	S->stacksize = maxsize;  //stacksize置为栈的最大容量maxsize
}

//入栈
int Push(struct SqStack* S, int data) //插入元素data为新的栈顶元素
{
	if (S->top - S->base == S->stacksize) //栈满
		return 0;
	*S->top = data;
	++S->top;  //将新元素压入栈顶,栈顶指针加1
	return 1;
}

//出栈
int Pop(struct SqStack* S) //删除S的栈顶元素,用data返回其值
{
	int data;
	if (S->top == S->base)
		return 0; //栈空
	--S->top;
	data = *S->top;  //栈顶指针减1,将栈顶元素赋给data
	printf("%d ", data);
	return 1;
}

//取栈顶元素
int GetTop(struct SqStack* S) //返回S的栈顶元素,不修改栈顶指针
{
	if (S->top != S->base)
		return *(S->top - 1);  //栈非空,返回栈顶元素的值,栈顶指针不变
}

void PrintStack(struct SqStack* S)
{
	while(S->top != S->base)
		printf("%d ", *S->base++);
	printf("\n");
}

int main()
{
	time_t t;
	srand((unsigned)time(&t));

	struct SqStack* S;
	S = (struct SqStack*)malloc(sizeof(struct SqStack));
	InitStack(S);
	int data = 0;
	printf("入栈顺序:\n");
	for (int i = 0; i < 10; i++)
	{
		data = rand() % 900 + 100;
		printf("%d ", data);
		Push(S, data);
	}
	printf("\n");
	printf("出栈顺序:\n");
	while(S->top != S->base)
		Pop(S);
	printf("\n\n");

	free(S);

	system("pause");
	return 0;
}

4、队列的链式存储结构的实现

(1)用随机函数生成10个3位整数(100~999),把这些整数应用入队操作存于队列中;

(2)应用遍历操作输出队列的内容;

(3)把队列的内容翻转,应用出队操作输出队列的内容。

#include 
#include 
#include 
#include 

//结点
struct QNode
{
	int data;
	struct QNode* next;
};

//队列
struct Queue
{
	struct QNode* front;  //队头指针
	struct QNode* rear;   //队尾指针
};

//初始化
void InitQueue(struct Queue* Q)
{
	Q->front = Q->rear = (struct QNode*)malloc(sizeof(struct QNode)); //生成新结点作为头结点,队头和队尾指针指向此结点
	Q->front->next = NULL;  //头结点的指针域置空
}

//入队,插入元素为Q的新的队尾元素
void EnterQueue(struct Queue* Q, int data)
{
	struct QNode* pNode = (struct QNode*)malloc(sizeof(struct QNode)); //为入队元素分配结点空间,用指针pNode指向
	pNode->data = data; //将新结点数据域置为data
	pNode->next = NULL; //将新结点插入到队尾
	Q->rear->next = pNode; //修改队尾指针
	Q->rear = pNode;
}

//出队,删除Q的队头元素,用data返回
void DeQueue(struct Queue* Q, int data)
{
	struct QNode* p;
	if (Q->front == Q->rear) //若队列为空,则结束
		return;
	p = Q->front->next; //p指向队头元素
	data = p->data;  //data保存队头元素的值
	printf("%d ", data);
	Q->front->next = p->next; //修改头结点的指针域
	if (Q->rear == p)  //最后一个元素被删, 队尾指针指向头结点
		Q->rear = Q->front;
	free(p); //释放原队头元素的空间
}

//取链队的队头元素
int GetHead(struct Queue* Q)
{
	if (Q->front != Q->rear)  //队列非空
		return Q->front->next->data; //返回Q的队头元素,不修改队头指针
}

//遍历操作输出队列内容
void printQueue(struct Queue* Q)
{
	struct QNode* pnode = Q->front; //Q相当于头结点
	while (pnode->next)
	{
		pnode = pnode->next;
		printf("%d ", pnode->data);
	}
	printf("\n");
}

//将队列内容翻转
void reverseQueue(struct Queue* Q)
{
	struct QNode* p1 = Q->front->next; //front
	struct QNode* p2 = p1->next; //front下一个
	struct QNode* nextNode = p2->next;
	Q->rear = p1;

	while (nextNode)
	{
		p2->next = p1;
		p1 = p2;
		p2 = nextNode;
		nextNode = p2->next;
	} //循环结束后p2在原来rear的位置
	p2->next = p1; //p1在原来rear的上一个
	Q->front->next = p2; //Q相当于头结点,它的next就是链队的front,变为原来rear的位置
	Q->rear->next = NULL;
}

int main()
{
	time_t t;
	srand((unsigned)time(&t));

	struct Queue* Q;
	Q = (struct Queue*)malloc(sizeof(struct Queue));
	InitQueue(Q);
	int data = 0;
	printf("元素入队顺序为:\n");
	for (int i = 0; i < 10; i++)
	{
		data = rand() % 900 + 100;
		printf("%d ", data);
		EnterQueue(Q, data);
	}
	printf("\n遍历操作输出队列内容:\n");
	printQueue(Q);

	int num = 0;

	reverseQueue(Q);
	printf("把队列的内容翻转,应用出队操作输出队列的内容:\n");
	while (Q->front->next)
		DeQueue(Q, data);
	printf("\n");

	free(Q);

	return 0;
}

5、线性表、栈和队列的应用

(1)用随机函数生成10个3位整数(100~999),把这些整数存于单链表中,然后读入一个整数,以该值为基准把单链表分割为两部分,所有小于该值的结点排在大于或等于该值的结点之前。

#include 
#include 
#include 
#include 

struct Node
{
	int data;
	struct Node* next;
};

struct Node* createList()
{
	struct Node* headNode = (struct Node*)malloc(sizeof(struct Node));
	headNode->next = NULL;
	return headNode;
}

void insertHead(struct Node* headNode, int data)
{
	struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
	newNode->next = headNode->next;
	newNode->data = data;
	headNode->next = newNode;
}

void printList(struct Node* headNode)
{
	struct Node* pNode = headNode->next;
	while (pNode->next)
	{
		printf("%d ", pNode->data);
		pNode = pNode->next;
	}
	printf("\n");
}


//排序
void sortList(struct Node* headNode)
{
	struct Node* p1 = headNode->next;
	struct Node* p2 = p1->next;
	while (p1->next)
	{
		while (p2->next)
		{
			if (p1->data > p2->data)
			{
				int temp = p1->data;
				p1->data = p2->data;
				p2->data = temp;
			}
			p2 = p2->next;
		}
		p1 = p1->next;
		p2 = p1->next;
	}
}

int main()
{
	time_t t;
	srand((unsigned)time(&t));

	struct Node* headNode, * pNode;
	headNode = (struct Node*)malloc(sizeof(struct Node));
	pNode = (struct Node*)malloc(sizeof(struct Node));
	headNode->next = pNode;

	printf("链表元素为:\n");
	for (int i = 0; i < 10; i++)
	{
		pNode->data = rand() % 900 + 100;
		printf("%d ", pNode->data);
		pNode->next = (struct Node*)malloc(sizeof(struct Node));
		pNode = pNode->next;
	}
	pNode->next = NULL;

	int num = 0;
	printf("\n请输入一个数:");
	scanf_s("%d", &num);
	insertHead(headNode, num);

	printf("以该值为基准把单链表分割为两部分:\n");
	sortList(headNode);
	printList(headNode);


	free(headNode);
	free(pNode);

	return 0;
}

(2)假设一个字符串中可以包含三种括号:( )[ ]{},且这三种括号可以按任意次序嵌套使用(如:“...[...{...}...[...]...]...(...)” 为合法嵌套,“...[...{... )...[...]...]...(...)”为不合法嵌套)。编写判别给定表达式中所含括号是否正确配对出现的算法,如果是合法嵌套则返回为true,如果是不符合法嵌套则返回为false。

#include 
#include 
#define maxsize 10

struct SqStack
{
	int* base;
	int* top;
	int stacksize;
};

//初始化
void InitStack(struct SqStack* S)
{
	S->base = (int*)malloc(sizeof(int) * maxsize);
	if (!S->base)
		exit(-2); //存储内存分配失败
	S->top = S->base;  //top初始为base,空栈
	S->stacksize = maxsize;  //stacksize置为栈的最大容量maxsize
}

//入栈
int Push(struct SqStack* S, char ch) //插入元素data为新的栈顶元素
{
	if (S->top - S->base == S->stacksize) //栈满
		return 0;
	*S->top = ch;
	++S->top;  //将新元素压入栈顶,栈顶指针加1
	return 1;
}

//出栈
int Pop(struct SqStack* S) //删除S的栈顶元素,用data返回其值
{
	char ch;
	if (S->top == S->base)
		return 0; //栈空
	--S->top;
	ch = *S->top;  //栈顶指针减1,将栈顶元素赋给data
	return 1;
}

int StackEmpty(struct SqStack* S)
{
	if (S->top != S->base)
		return 0;
	else
		return 1;
}


char GetTop(struct SqStack* S) //返回S的栈顶元素,不修改栈顶指针
{
	if (S->top != S->base)
		return *(S->top - 1);  //栈非空,返回栈顶元素的值
}

int main()
{
	struct SqStack* S;
	S = (struct SqStack*)malloc(sizeof(struct SqStack));
	InitStack(S);
	int flag = 1;  //标记匹配结果以控制循环及返回结果
	char ch;
	printf("请输入()[]{},且这三种括号可以按任意次序嵌套使用,并以#结束:\n");

	scanf_s("%c", &ch);
	while (ch != '#' && flag)  //表达式以 # 结尾
	{
		switch (ch)
		{
		case '[':    //若是左括号,则将其压入栈
		case '(':
			Push(S, ch);
			break;
		case '{':
			Push(S, ch);
			break;
		case ')':    //若是右括号,则根据当前栈顶元素的值分情况考虑
			if (!StackEmpty(S) && (GetTop(S) == '('))
				Pop(S, GetTop(S));   //若栈非空且栈顶元素是左括号则正确匹配
			else flag = 0;           //若栈空或栈顶元素不是左括号则错误匹配
			break;
		case ']':
			if (!StackEmpty(S) && (GetTop(S) == '['))
				Pop(S, GetTop(S));
			else flag = 0;
			break;
		case '}':
			if (!StackEmpty(S) && (GetTop(S) == '{'))
				Pop(S, GetTop(S));
			else flag = 0;
			break;
		}
		scanf_s("%c", &ch);  //继续读下一个字符
	}
	if (StackEmpty(S) && flag)
		printf("%s\n", "True");
	else
		printf("%s\n", "False");


	return 0;
}

附:随机函数的使用(仅供参考)

#include “time.h”     //用到时间函数

#include “math.h”    // 用到随机函数

主程序:

time_t t;   // 定义时间变量

srand((unsigned)time(&t));  //由时间确定随机序列,执行一次

生成10个随机数的循环体里:

rand()//随机生成一个0~32767的整数,可以嵌在转换公式或函数里

要求:

  1. 链式线性表、堆栈和队列可以带表头或不带表头,也可以设计为循环结构;
  2. 链表内容(结点数值)无序,可以重复,也可以不重复;
  3. 运行测试时,应尽量穷尽各种可能及组合,并在实验报告中展示输入及输出结果,选取具有代表性的使用截屏显示。

遇到的问题:

顺序栈在c中显示为初始化,但在c++中能正常运行。

解决:c中没有引用,初始化时应传指针。

你可能感兴趣的:(数据结构,链表,c语言)