数据结构(2)--线性表单链表的主要操作的实现

参考书籍:数据结构(C语言版) 严蔚敏 吴伟民编著 清华大学出版社

本文中的代码可从这里下载:https://github.com/qingyujean/data-structure

1.基本定义

#include<stdio.h>
#include<stdlib.h>

//线性表的两种存储结构:
//1.顺序表(动态数组实现、静态数组实现)
//2.链表(单链表、静态链表)
//本实例实现线性表的链式存储

#define NULL 0
typedef int ElemType;
//单链表存储结构节点定义
typedef struct LNode{
	ElemType data;
	struct LNode *next;
}LNode, *LinkList;
//默认单链表都带有头节点

 

2.创建线性表和打印输出线性表

//创建一个长度为n的线性单链表,使用尾插法(顺序建立),
//(若为头插法则为逆向建立,那么输入元素的顺序应该与线性表里的逻辑顺序相反)
void createList(LinkList &L, int n){
	//先建立一个带头节点的单链表L,即初始化
	L = (LinkList)malloc(sizeof(LNode));
	L->next = NULL;

	LinkList r = L;//r指针总是指向当前线性表的最后一个元素,即尾元素
	printf("请输入%d个数据:\n", n);
	for(int i = 0; i < n; i++){
		LinkList s = (LinkList)malloc(sizeof(LNode));
		scanf("%d", &s->data);
		//getchar();
		s->next = NULL;
		r->next = s;
		r = s;
	}
}
//打印输出线性单链表
void printList(LinkList L){
	printf("打印线性链表:");
	LinkList p = L->next;
	while(p){//p为当前查访的元素
		printf("%d ", p->data);
		p=p->next;
	}
	printf("\n");
}

演示:

int main(){
	
	LinkList L;
	createList(L, 5);//初始化并创建一个线性单链表
	printList(L);

    return 0;
}

 

3.插入操作

//在带头节点的单链表的第i(1<=i<=n+1)个位置之前插入元素e,有n+1个位置可供插入
//得找到前驱结点第i-1个节点
//时间复杂度:O(n)
void insertList(LinkList &L, int i, ElemType e){
	int j = 1;
	LinkList p = L;//p现在指向头节点
	while(j<i&&p){
		p = p->next;
		j++;
	}//顺利的话,j应该为插入的位置i,p为其前驱结点即i-1位置的节点
	//如果i大于表长+1,则会因为p=NULL而跳出循环,如果i<1,则会因为j<i不满足跳出循环
	if(j>i||!p){
		printf("插入位置参数不合法\n");
	}else{
		LinkList s = (LinkList)malloc(sizeof(LNode));
		s->data = e;
		s->next = p->next;
		p->next = s;
	}	
}

演示:

int main(){
	
	LinkList L;
	createList(L, 5);//初始化并创建一个线性单链表
	printList(L);	
	
	//完成插入功能  
    printf("您要插入的数据和位置(1~6)(如:在第2个位置插入10则输入:2,10):");  
    int elem, pos;  
    scanf("%d,%d",&pos,&elem);  
    insertList(L,pos,elem);  
    printList(L);  

    return 0;
}

 

4.删除操作

//在带头节点的单链表里删除第i(1<=i<=n)个元素,并由e返回
//需要找到第i个元素的前驱结点
//时间复杂度:O(n)
void delList(LinkList &L, int i, ElemType &e){
	int j = 1;
	LinkList p = L;
	while(j<i&&p->next){
		p = p->next;
		j++;
	}//顺利的话,j应该为插入的位置i,p为其前驱结点即i-1位置的节点
//如果i大于表长,则会因为p->next=NULL而跳出循环,如果i<1,则会因为j<i不满足跳出循环
	if(j>i||!p->next){
		printf("删除位置参数不合法\n");
	}else{
		LinkList s = p->next;
		e = s->data;
		p->next = s->next;
		free(s);
		printf("被删除的第%d个位置的数据是%d\n", i, e);
	}
}

演示:

int main(){
	
	LinkList L;
	createList(L, 5);//初始化并创建一个线性单链表
	printList(L);	
	
	//完成删除功能  
    printf("您要删除的数据的位置(1~5)(如:在第2个位置删除则输入:2):");  
    int pos; 
	ElemType elem;
    scanf("%d",&pos);  
    delList(L,pos,elem); 
    printList(L); 

    return 0;
}

 

5.两个线性表的merge操作

//已知线性表La和Lb中的数据元素按值非递减排列,现要求将La和Lb归并为一个新的线性表Lc,且Lc中的数据元素仍然按值非递减有序排列  
//实现:为保持Lc的非递减有序,则当a<=b时,c=a;当a>b时,c=b  
//时间复杂度:O(La.len+Lb.len)  
//实例:La=(3,5,8,11),Lb=(2,6,8,9,11,15,20),Lc=(2,3,5,6,8,8,9,11,11,15,20),注意并没有去重,只是做了合并 
//注意:与线性顺序表的实现的区别之处:Lc可利用la和Lb的节点,即把La,Lb逐步链接到Lc中去
void mergeList(LinkList &La, LinkList &Lb, LinkList &Lc){
	Lc = La;//将La的头节点作为Lc的头节点
	LinkList pa = La->next;
	LinkList pb = Lb->next;
	LinkList pc = Lc;//pc总是指向Lc的最后一个节点

	while(pa&&pb){
		if(pa->data <= pb->data){
			pc->next = pa;
			pc = pa;
			pa = pa->next;
		}else{
			pc->next = pb;
			pc = pb;
			pb = pb->next;
		}
	}
	pc->next = pa?pa:pb;//插入剩余段
	free(Lb);//释放Lb的头节点
}

演示:

int main(){
	//完成merge操作  
    LinkList La, Lb, Lc;   
    printf("创建线性表La:\n");  
    createList(La, 4);//初始化并创建线性表La  
    printList(La);  
    printf("创建线性表Lb:\n");  
    createList(Lb, 7);//初始化并创建线性表Lc  
    printList(Lb);  
    mergeList(La, Lb, Lc);  
    printf("merge以后得到的Lc:\n");  
    printList(Lc);  

    return 0;
}

 

6.两个线性表的union操作

//利用两个线性表La,Lb分别表示两个集合A和B(线性表中的数据元素即为集合元素),现要求一个新的集合A=AUB  
//实现:扩展线性表La,实现类似于merge操作,只是要去重,可以用2个指针同时从两个线性表出发并比较,这样求得的并集保持了合并前的顺序
//实例:La=(3,5,8,11),Lb=(2,6,8,9,11,15,20),union以后的La=(2,3,5,6,8,9,11,15,20),La.len=9,注意有去重, 
//时间复杂度:O(La.len + Lb.len) 
void unionList(LinkList &La, LinkList &Lb){
	LinkList pa = La->next;
	LinkList pb = Lb->next;
	LinkList pc = La;//pc总是指向并集列表的最后一个节点

	while(pa&&pb){
		if(pa->data < pb->data){
			pc->next = pa;
			pc = pa;
			pa = pa->next;
		}else if(pa->data > pb->data){
			pc->next = pb;
			pc = pb;
			pb = pb->next;
		}else{//a==b,只插入其中之一
			LinkList s = pb;

			pc->next = pa;
			pc = pa;
			pa = pa->next;
			pb = pb->next;

			free(s);
		}
	}
	pc->next = pa?pa:pb;//插入剩余段
	free(Lb);//释放Lb的头节点
}

演示:

int main(){
	//完成union操作  
    LinkList La, Lb;   
    printf("创建线性表La:\n");  
    createList(La, 4);//初始化并创建线性表La  
    printList(La);  
    printf("创建线性表Lb:\n");  
    createList(Lb, 7);//初始化并创建线性表Lc  
    printList(Lb); 
    unionList(La, Lb);  
    printList(La);   

    return 0;
}

 

本文中的代码可从这里下载:https://github.com/qingyujean/data-structure

  • 6
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值