线性表(2)-----单链表

本文深入探讨了单链表的存储方式与操作原理,包括插入、删除、查找等核心功能,并提供了完整的C语言实现代码,附带详细的注释与运行结果。

                                             单链表(含代码)

❀叨叨两句:

前面已经介绍过线性表有两种存储方式:顺序与链式。

                             顺序存储方式相关内容在这儿:--->https://mp.youkuaiyun.com/postedit/93474277

需要注意的是两种存储方式的优缺点:

  1. 顺序表:读取查找时很方便,直接根据索引查询即可,时间复杂度为O(1);但在插入删除等存取操作时需要移动大量元素,时间复杂度为O(n)
  2. 单链表:与顺序表相反,在存取数据时不需要移动大量元素,只需修改部分节点的指针即可,时间复杂度为O(1);但在查找定位等操作时需要逐个遍历,时间复杂度为O(n)。

言归正传:

           1. ✍单链表长这样:

带头节点的单链表的相貌

           2. ✍因此这样定义:

typedef struct node{
    int data;//数据域:存放数据 
    struct node* Next;//指针域: 下个节点的存放地址 
}Node, *Linklist;

          3.✍插入节点时的原理图:

                                    

在第i个位置插入新节点

        4.✍删除操作原理图:

                        

删除第i个结点

        5.✍具体操作+具体解释+具体测试

          具体操作有:创建,遍历,判空,定位,插入,删除,获取长度,合并两表

         以下代码超长,可能引起不适:

                 //单链表的基本操作
#include<stdio.h>
#include<stdlib.h> 
//结点定义 

typedef struct node{
    int data;//数据域:存放数据 
    struct node* Next;//指针域: 下个节点的存放地址 
}Node, *Linklist;
 
 //操作声明 
Linklist createList();   
void traverse(Linklist Head);
bool isEmpty(Linklist Head);
int length(Linklist Head);
bool insert(Linklist Head,int lenth, int pos, int val);
bool del(Linklist Head, int lenth,int pos);
Linklist get(Linklist Head, int value);
Linklist locate(Linklist Head, int k); 
void MergeLinklist(Linklist &La,Linklist &Lb,Linklist &Lc);
int main(void)
{
   //test
   Linklist La=createList();
   Linklist Lb=createList();
   Linklist Lc=(Linklist)malloc(sizeof(Node));;
   Lc->Next=NULL;
    int lena=length(La);
    int lenb=length(Lb);
    int lenc=length(Lc);
    printf("\n La的长度是%d,Lb的长度是%d,Lc的长度是%d\n",lena,lenb,lenc);
	//遍历测试 
    printf("\n 当前表La中的数据有 \n"); 
    traverse(La);
    printf("\n 当前表Lb中的数据有 \n"); 
    traverse(Lb);
    //查找测试
    Linklist p=get(La,1);//获取La中data=1的节点 
    printf("\nLa中data=1的节点数据为%d\n",p->data); 
    Linklist q=locate(Lb,1); //获取Lb的第1个节点 
    printf("\nLb的第1个节点存放的数据为%d\n",q->data);  
    //插入数据测试 
    insert(La,lena,3,3);
    insert(Lb,lenb, 1,4);
    lena=length(La);
    lenb=length(Lb);
    lenc=length(Lc);
    printf("\n在第三个位置插入数据3后La的长度是%d,Lb插入新数据后的长度是%d,Lc的长度是%d",lena,lenb,lenc);
    printf("\n第一个位置插入数据3后表La中的数据有\n"); 
    traverse(La);
    printf("\n在表Lb中第一个位置插入数据4后的数据有\n"); 
    traverse(Lb);
    //删除数据测试
    del(La,lena, 3);
    del(Lb, lenb,1);
    printf("\n表La中的数据有\n"); 
    traverse(La);
    printf("\n表Lb中的数据有\n"); 
    traverse(Lb);
    MergeLinklist(La,Lb,Lc);
    printf("\n表Lc中的数据有\n"); 
    traverse(Lc);
   return 0; 
} 
       // 1.创建链表
Linklist createList(){
	int len,value;
	Linklist head=(Linklist)malloc(sizeof(Node));
	Linklist rear=head;//尾指针初始化 
	rear->Next=NULL;//到此已经创建了一个空链表
	printf("请输入您所要插入的节点数:");
	scanf("%d",&len);
    printf("请逐个输入您所要插入的数据:");
	for(int i=0;i<len;i++)
	{
		scanf("%d",&value);
		//需提前新建结点接收保存数据,再插入尾部
	 Linklist nnode=(Linklist)malloc(sizeof(Node));
	 nnode->data=value;
	 /*尾结点是rear ,插入一个数据需将tail的next设置为保存数据的新节点nnode,
    保证nnode加入链表成为新的尾结点,再将rear更新成尾结点 */
	 rear->Next=nnode;
	 rear=nnode;
	 rear->Next=NULL;
	}
	return head;//返回头指针 
}
              //2.遍历链表
void traverse(Linklist head){
	Linklist travel=head;//从头开始,但头结点不存储数据  
    while(travel->Next)//只要后面还有节点,也即travel->next !=NULL
    {
         travel=travel->Next;//因为头结点不存数据所以输出时先将travel后移;
    	 printf("%d ",travel->data); 
	}
	printf("\n");
}
              //3.判断链表是否为空
bool isEmpty(Linklist Head){
 if(Head->Next==NULL)
      return true;
    else{
      return false;
      } 
} 
              //4.链表长度(不计头结点) 
int length(Linklist Head){
    int len = 0;
    while(Head->Next!=NULL){
        Head =Head->Next;
        len++;//从头结点后的第一个节点开始计数,头节点不算 哈 
    }
    return len;
}
              // 5.插入结点
bool insert(Linklist Head,int lenth, int pos, int value){
	//先判断插入位置是否合法 
	if(pos<1||pos>lenth) return false;
	Linklist nnode=(Linklist)malloc(sizeof(Node));
	nnode->data=value;
	//遍历寻找插入位置de前一个节点 ,注意循环终止条件 
	Linklist pre=Head;
	for(int i=1;i<pos;i++)
	{
		pre=pre->Next;
	} 
    nnode->Next=pre->Next;//注意插入规则,先后连,再前连,防止断链 
	pre->Next=nnode;
} 
           //6.删除结点
bool del(Linklist Head, int lenth,int pos){
	  if(pos<1 || pos>lenth){
        return false;
    }else{
        Linklist Del = Head;
        for(int i=1;i<pos;i++){
            Del = Del->Next;//同样也是找到删除位置的前一个节点 
        }
        
        if(pos==lenth){
		//若插入位置在尾部 
          free(Del->Next);//直接释放最后一个节点即可 
          Del->Next = NULL;    
        }else{
            Linklist double_Next = Del->Next->Next;
            free(Del->Next);
            Del->Next = double_Next;
        }
        //其实两种情况可以合并,不用刻意去分开,直接用else里的代码就行,当插入尾部时double_Next为NULL而已 
        return true;
        
    }
} 
            //7.查找节点   
			       //(1)按元素值查找
Linklist get(Linklist Head, int value){
	 Linklist p = Head->Next;
    while(p&&p->data!=value){      //NULL 是 0 
        p = p->Next;
    }
    if(!p){
    	printf("无此节点~\n"); 
    	return NULL;
	} 
    return p;
}
                   //(2)按序号查找
Linklist locate(Linklist Head, int k){
               Linklist p = Head;
    for(int i=1;i<=k;i++){
        p = p->Next;
    }
    return p;   
}
            //归并两表1(无去重,结果无序)
                         
void MergeLinklist(Linklist &La,Linklist &Lb,Linklist &Lc)
{
         	Linklist pa=La->Next;
		    Linklist pb=Lb->Next;
		    Linklist pc=Lc;
		    while(pa&&pb){
            if(pa->data >=pb->data){
            	pc->Next=pb;
            	pc=pb;
            	pb=pb->Next;
			}else{
				pc->Next=pa;
            	pc=pa;
            	pa=pa->Next;
			}
		    }
		    while(pa){
			    pc->Next=pa;
            	pc=pa;
            	pa=pa->Next;	
			}
		    while(pb){
			   	pc->Next=pb;
            	pc=pb;
            	pb=pb->Next;
			}
} 

       6.✍运行结果:

运行结果

       7.✍正经致谢:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值