数据结构知识总结(一)——线性表之单链表

数据结构知识总结(一)——线性表之单链表与顺序表(C语言实现)

线性表:
线性表是最基本、最简单、也是最常用的一种数据结构。线性表(linear list)是数据结构的一种,一个线性表是n个具有相同特性的数据元素的有限序列。
线性表中数据元素之间的关系是一对一的关系,即除了第一个和最后一个数据元素之外,其它数据元素都是首尾相接的(注意,这句话只适用大部分线性表,而不是全部。比如,循环链表逻辑层次上也是一种线性表(存储层次上属于链式存储),但是把最后一个数据元素的尾指针指向了首位结点)。
以上是百度对线性表的介绍与定义,线性表,顾名思义,就是线式存储的一种数据结构。
需要注意的是我们说“线性”和“非线性”,只在逻辑层次上讨论,而不考虑存储层次,因此,链式存储的链表,栈,队列依然属于线性表。
线性表主要由顺序表示或链式表示。在实际应用中,常以栈、队列、字符串等特殊形式使用。我们首先看看顺序表,因为顺序表结构简单,具体代码就简单的做了创建、插入和删除,如果有感兴趣的,可以自己去实践一下别的,这里不再过多描述。
I. 顺序表:
如下图是顺序表的存储结构,显而易见的,这就是一个简单的顺序存储即数组结构。代码贴在最后,这里不再做展示。
在这里插入图片描述
II. 链表
链表可分单向链表,双向链表,循环单链表和循环双链表,但因为所有的链表的存储结构都相同只是结构体定义有些许不同,因此这里不再一一叙述,下面我们以单链表为例,看看单链表的一些常见算法。
这里以C语言为例,先看看链表的结构定义

typedef struct node
{
	int data;
	struct node *next;
 } NODE,*PNODE;

创建任意长度的链表,这里采用的是尾插法(就是永远想最后位置添加结点元素)

void insert_Arbitrarily(PNODE S,int val)
{
	PNODE P=(NODE*)malloc(sizeof(NODE));
	P->data=val;
	P->next=S->next;		
	S->next =P;
}

PNODE create_list_Arbitrarily()
{
	PNODE S;
	S=(PNODE)malloc(sizeof(NODE));
	S->next =NULL;
	int data;
	printf("请输入链表数据,输入-1结束\n");
	while(scanf("%d",&data),data!= -1)
	{
		insert_Arbitrarily(S,data);
	 } 
	return S;
}

接下来是合并2个链表,这也非常简单,直接看代码吧

 PNODE megre(PNODE L1,PNODE L2)
{
	NODE* S=L1->next;
	while(S->next!=NULL)
	{
		S=S->next;
	}
	S->next =L2->next ;
	return L1;
}

再看插入与删除链表结点的算法,这里借用图片给大家说明
在这里插入图片描述
在这里插入图片描述
这是示意图,下面我们看代码实现

//删除某一个节点
int delete_list(PNODE pHead)
{
	int i;
	PNODE s,p; 
	printf("请输入需要删除链表中的第几个节点:"); 
	scanf("%d",&i);
	s=GPSnode(i,pHead);
	p=GPSnode(i-1,pHead);
	p->next=s->next;
	free(s);
	return 1; 
}

//插入节点操作
int add_list(PNODE pHead)
{
	int number;
	PNODE s,p;
	s=(PNODE)malloc(sizeof(NODE));
	printf("请输入需要插入的数据");
	scanf("%d",&s->data);
	printf("请输入要该节点作为链表的第几个节点:");
	scanf("%d",&number);
	p=GPSnode(number-1,pHead);
	s->next=p->next;
	p->next=s;
	return 1;
 } 

然后我们再看看单链表的遍历操作,这个很简单,不多说,直接上代码

//遍历输出链表 
void traverse_list(PNODE pHead)
  {
  	PNODE P=pHead->next;
	while(P!=NULL)
	{
		printf("%d\t",P->data);
		P=P->next;
	}
	return;
  }

下面是单链表的逆置操作,由于个人表述能力有限,大家如果没看懂,请移步
单链表的逆置(头插法和就地逆置) by敲代码的小小哥

我们在这里重点介绍单链表原地逆置的迭代逆置
直接看图吧
单链表逆置示意
按这步骤进行下去,最终结果为逆置结果
下面我们来看代码

//就地逆置链表 
PNODE reverse(PNODE head)
{
	if(head==NULL||head->next==NULL)
		return head;
	NODE *p=NULL;
	NODE *k=head->next;
	while(k!=NULL)
	{
		NODE* temp=k;
		k=k->next;
		temp->next =p;
		p=temp;
	}
	head->next=p;
	return head;
}

看完了上面这些基础操作,链表的基础内容也就到此结束,而双链表和循环链表就是在单链表的基础上加了一个指针,这里不再赘述,谢谢大家!
下面贴上单链表实现的完整C语言代码

#include <stdio.h>
#include<stdlib.h>
typedef struct node
{
	int data;
	struct node *next;
 } NODE,*PNODE;
 
PNODE create_list(); 				//创建并初始化链表 (规定有多少元素时)
PNODE create_list_Arbitrarily();	//创建并初始化链表(任意长度)
void insert_Arbitrarily(PNODE S,int data);	//头插入法 
void traverse_list(PNODE pHead);	//遍历链表 
int delete_list(PNODE pHead); 		//删除链表结点 
PNODE GPSnode(int i,PNODE pHead);	 //查找该节点,并返回该节点指针(这里是按位查找)
PNODE GPSnode_vale(int i,PNODE pHead);	//查找该节点,并返回该节点指针(按值查找 ) 
PNODE reverse(PNODE head); 		 //就地逆置链表 
PNODE megre(PNODE L1,PNODE L2);	 //合并2个链表 
int add_list(PNODE pHead);		//插入结点 
int length(PNODE pHead);		//求长度 
int show(); 					//选项界面

int main(void)
 {
 	int i;
 	PNODE pHead=NULL;
 	pHead=create_list();
 	i=show();
	switch(i) 
	{
		case 1:add_list(pHead);break;
		case 2:delete_list(pHead);break;
	}
	traverse_list(pHead);
	printf("\n %d",length(pHead));
 	return 0;
 }

 //选项界面  
int show()
{	int i; 
	printf("请选择菜单选项,完成操作");
	printf("1.插入节点               2.删除节点");
	scanf("%d",&i);
	return i;
 }
 
 //创建并初始化链表 (规定有多少元素时) 
 PNODE create_list()
 {
 	int len,i;
	int val;
	PNODE pHead=(PNODE)malloc(sizeof(NODE));
	if(pHead==NULL)
	{
		printf("动态内存分配失败,即将退出程序\n");
		exit(-1); 
	}
	PNODE pTail=pHead;
	pTail->next=NULL;
	 
	printf("请输入需要创建的链表节点数:");
	scanf("%d",&len);
	for(i=0;i<len;++i)
	{
		printf("请输入第%d个节点的数据: ",i+1);
		scanf("%d",&val);
		PNODE pNew=(PNODE)malloc(sizeof(NODE));
		pNew->data=val;
		pTail->next=pNew;
		pNew->next=NULL;
		pTail=pNew;
		if(pNew==NULL)
	{
		printf("动态内存分配失败,即将退出程序!\n");
		exit(-1); 
	}
	}
	return pHead;
  } 
  
创建并初始化链表(任意长度)
void insert_Arbitrarily(PNODE S,int val)
{
	PNODE P=(NODE*)malloc(sizeof(NODE));
	P->data=val;
	P->next=S->next;		
	S->next =P;
}

PNODE create_list_Arbitrarily()
{
	PNODE S;
	S=(PNODE)malloc(sizeof(NODE));
	S->next =NULL;
	int data;
	printf("请输入链表数据,输入-1结束\n");
	while(scanf("%d",&data),data!= -1)
	{
		insert_Arbitrarily(S,data);
	 } 
	return S;
}

//遍历输出链表 
void traverse_list(PNODE pHead)
  {
  	PNODE P=pHead->next;
	while(P!=NULL)
	{
		printf("%d\t",P->data);
		P=P->next;
	}
	return;
  }
  
//查找该节点,并返回该节点指针(这里是按位查找) 
PNODE GPSnode(int i,PNODE pHead)
{	PNODE s;
	s=pHead;
	int x=0; 
 	while(x!=i&&s!=NULL)
 	{
 		s=s->next;
 		x++;
	 }
	 if (s==NULL)
	 {
	 	printf("未找到该节点");
		return NULL; 
	 }
	 else return s;
 } 

 //查找该节点,并返回该节点指针(按值查找 ) 
 PNODE GPSnode_vale(int i,PNODE pHead)
 {
 	PNODE s;
	s=pHead;
	while(s!=NULL) 
	{
		if(s->data==i)
			return s;
		else s=s->next; 
	}
	if (s==NULL)
	 {
	 	printf("未找到该节点");
		return NULL; 
	 }
 }
 
//删除某一个节点
int delete_list(PNODE pHead)
{
	int i;
	PNODE s,p; 
	printf("请输入需要删除链表中的第几个节点:"); 
	scanf("%d",&i);
	s=GPSnode(i,pHead);
	p=GPSnode(i-1,pHead);
	p->next=s->next;
	free(s);
	return 1; 
}

//插入节点操作
int add_list(PNODE pHead)
{
	int number;
	PNODE s,p;
	s=(PNODE)malloc(sizeof(NODE));
	printf("请输入需要插入的数据");
	scanf("%d",&s->data);
	printf("请输入要该节点作为链表的第几个节点:");
	scanf("%d",&number);
	p=GPSnode(number-1,pHead);
	s->next=p->next;
	p->next=s;
	return 1;
 } 
 
 //求链表长度 (不包括头结点) 
 int length(PNODE pHead)
{
	PNODE P=pHead->next;
	int length=0;
	while(P!=NULL)
	{
		length++;
		P=P->next;
	}
	return length;
 } 
 
 //合并2个链表 
 PNODE megre(PNODE L1,PNODE L2)
{
	NODE* S=L1->next;
	while(S->next!=NULL)
	{
		S=S->next;
	}
	S->next =L2->next ;
	return L1;
}

 
 //就地逆置链表 
PNODE reverse(PNODE head)
{
	if(head==NULL||head->next==NULL)
		return head;
	NODE *p=NULL;
	NODE *k=head->next;
	while(k!=NULL)
	{
		NODE* temp=k;
		k=k->next;
		temp->next =p;
		p=temp;
	}
	head->next=p;
	return head;
}

然后这是最开始说的关于顺序表的代码,这个实现功能不多,只是起一个对比作用,望大家见谅。

#include<iostream> 
#define datatype int
#define MaxSize 100
using namespace std;

struct SeqList
{
	datatype val[MaxSize];		//这里就是存储元素的数组 
	int last;					//表示顺序表的长度 
};

SeqList* creat()
{
	SeqList* S=new SeqList;
	datatype num;
	int i=0;
	S->last=-1;
	cout<<"请输入顺序表的初始数据"<<endl; 
	cout<<"输入-1表示输入结束"<<endl;
	while(cin>>num&&num != -1)
	{
		S->val[i]=num;
		i++;
		S->last++;
	}
	return S;
}

//插入元素 
void insert(SeqList *S,datatype data,int loc)
{
	if(S->last<loc)
	{
		cout<<"越界"<<endl;
		exit (-1);
	}
	loc-=1;
	int i=loc;
	datatype temp1,temp2;
	temp1=S->val[i];
	for(;i<=S->last;i++) 	//这里需要吧插入元素后面的所有元素都后移一位 
	{
		temp2=S->val[i+1];
		S->val[i+1]=temp1;
		temp1=temp2;
	}
	S->val[loc]=data;
	S->last++;
 } 
 
 //删除元素 
 void _delete(SeqList *S,int loc)
 {
 	if(S->last<loc)
	{
		cout<<"越界"<<endl;
		exit (-1);
	}
	int i=S->last;
	datatype temp1,temp2;
	temp1=S->val[i];
	for(;i>=loc;i--)		//与插入一样,删除需要把之后的所有元素前移一位 
	{
		temp2=S->val[i-1];
		S->val[i-1]=temp1;
		temp1=temp2;
	}
	S->last--;
 }
 
 //遍历输出顺序表 
 void print(SeqList *S)
 {
 	int i=0;
 	while(i<=S->last)
 	{
 		cout<<S->val[i]<<"    ";
 		i++;
	 }
	 cout<<endl;
 }
 
 //菜单操作 
 int choose(SeqList *S)
 {
 	int number;
 	cout<<"1.插入一个数据"<<endl;
 	cout<<"2.删除一个数据"<<endl;
 	cout<<"按其他键退出"<<endl;
 	cout<<"请选择:"; 
	cin>>number; 
	switch(number)
	{
		case 1:{
			datatype data;
			int loc;
			cout<<"请输入要插入的元素以及插入的位置"<<endl;
			cin>>data>>loc;
			insert(S,data,loc); 
			break;
		}
		case 2: {
			int loc;
			cout<<"请输入要删除的元素的位置:";
			cin>>loc;
			_delete(S,loc);
			break;
		}
		default: break;
	}
 }
 
 int main()
 {
 	SeqList *S=creat();
 	print(S);
 	choose(S);
 	print(S);
 	return 0;
 }
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值