带头节点的不循环单链表相关操作

创建list.h头文件

#pragma once
//头结点:开头标识,类似旗帜,不存放数据,不参与运算
//数据结点:存放数据
typedef struct Node
{
 int data;
 struct Node *next;
}Node,*pList;

//初始化
void InitSeqList(pList plist);

//头插
bool Insert_head(pList plist,int val);

//尾插
bool Insert_tail(pList plist,int val);

//在plist中查找关键字Key,找到后返回地址,失败返回-1
Node *Search(pList plist,int key);

//判空
bool IsEmpty(pList plist);

//删除第一个key值
bool DeleteVal(pList plist,int key);

//获取数据长度
int GetLength(pList plist);

//显示
void Show(pList plist);

//清空数据
void Clear(pList plist);

//销毁动态内存
void Destroy(pList plist);

创建list.cpp文件

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include"list.h"
/*
注意事项:
 1.找后一个节点是p=p->next;不能写成p++
*/

//判空
static void DeterPointNull(pList plist)
{
 assert(plist!=NULL);
 if(plist==NULL)
 {
  exit(0);
 }
}

//初始化
void InitSeqList(pList plist)
{
 DeterPointNull(plist);
 plist->next=NULL;
}

//头插
bool Insert_head(pList plist,int val)
{
 DeterPointNull(plist);
 
 //程序出错,由于Node定义的是局部变量,使用后便销毁,无法传递回去
 /*Node node;
 node.data=val;
 node.next=plist->next;
 plist->next=&node;*/
 
 Node *p=(Node *)malloc(sizeof(Node));
 p->data=val;
 p->next=plist->next;
 plist->next=p;
 
 return true;
}

//尾插
bool Insert_tail(pList plist,int val)
{
 DeterPointNull(plist);
 
 //创建新节点
 Node *p=(Node *)malloc(sizeof(Node));
 
 //将值存放到新节点
 p->data=val;
 
 //找尾结点
 Node *q;
 for(q=plist;q->next!=NULL;q=q->next);
 //将新节点插入到q后面
 p->next=q->next;// 相当于p->next=NULL;
 q->next=p;
 
 return true;
}

//在plist中查找关键字Key,找到后返回地址,失败返回空指针
Node *Search(pList plist,int key)
{
 DeterPointNull(plist);
 for(Node *p=plist->next;p!=NULL;p=p->next)
 {
  if(p->data==key)
  {
   return p;
  }
 }
 return NULL;
}

//判空
bool IsEmpty(pList plist)
{
 DeterPointNull(plist);
 return plist->next==NULL;
}

//删除plist中的第一个key
bool DeleteVal(pList plist,int key)
{
 DeterPointNull(plist);
 Node *q;
 for(Node *p=plist->next;p!=NULL;)
 {
  q=p->next;
  if(p->data==key)
  {
   plist->next=p->next;
   free(p);
   return true;
  }
  if(q->data==key)
  {
   p->next=q->next;
   free(q);
   return true;
  }
 }
 return false;
}

//获取数据长度
int GetLength(pList plist)
{
 DeterPointNull(plist);
 int count=0;
 for(Node *p=plist->next;p!=NULL;p=p->next)
 {
  count++;
 }
 return count;
}

//显示
void Show(pList plist)
{
 DeterPointNull(plist);
 for(Node *p=plist;p->next!=NULL;p=p->next)
 {
  printf("%-5d",p->next->data);
 }
 printf("\n");
}

//清空数据
void Clear(pList plist)
{
 DeterPointNull(plist);
 plist->next=NULL;
}

//销毁动态内存
//总是删除第一个数据结点
void Destroy(pList plist)
{
 DeterPointNull(plist);
 Node *p;
 while (plist->next!=NULL)//还有第一个数据结点
 {
  p=plist->next;//p指向第一个数据结点
  plist->next=p->next;//将p从链表中剔除
  free(p);
 }
}
/*
//销毁动态内存
void Destroy(pList plist)
{
 DeterPointNull(plist);
 Node *p=plist->next;//指向需要删除的结点
 Node *q;//p的下一个节点,不能直接赋值=p->next
 
 while (p=plist->next!=NULL)
 {
  q=p->next;
  free(p);
  p=q;
 }
 plist->next=NULL;
}
*/

其他功能:
1.已知递增有序的单链表A,B,C分别存储了一个集合,设计算法实现A:AU(BnC),并使求解结构A仍保持递增。
要求算法的时间复杂度为O(|A|+|B|+|C|)。其中,|A|为集合A的元素个数

void Calculate(pList plistA,pList plistB,pList plistC)
{
 Node *p1=plistA;
 Node *p2=plistB->next;
 Node *p3=plistC->next;
 while (p1->next!=NULL && p2!=NULL && p3!=NULL)
 {
  if(p2->data==p3->data)
  {
   if(p1->next->data<p2->data)
   {
    if(p1->next->next==NULL)
    {
     Insert_tail(plistA,p2->data);
    }
    p1=p1->next;
   }
   else if(p1->next->data==p2->data)
   {
    p2=p2->next;
    p3=p3->next;
   }
   else
   {
    Node *q=(Node *)malloc(sizeof(Node));
    q->data=p2->data;
    q->next=p1->next;
    p1->next=q;
   }
  }
  else if(p2->data<p3->data)
  {
   p2=p2->next;
  }
  else if(p2->data>p3->data)
  {
   p3=p3->next;
  }
 }
}
int main()
{
 Node headA;
 InitSeqList(&headA);
 Node headB;
 InitSeqList(&headB);
 Node headC;
 InitSeqList(&headC);
 
 Insert_tail(&headA,2);
 Insert_tail(&headA,3);
 Insert_tail(&headA,7);
 Insert_tail(&headA,8);
 Insert_tail(&headA,9);
 
 Insert_tail(&headB,1);
 Insert_tail(&headB,5);
 Insert_tail(&headB,6);
 Insert_tail(&headB,8);
 Insert_tail(&headB,10);
 
 Insert_tail(&headC,1);
 Insert_tail(&headC,3);
 Insert_tail(&headC,6);
 Insert_tail(&headC,9);
 Insert_tail(&headC,10);
 
 Show(&headA);
 Show(&headB);
 Show(&headC);
 
 Calculate(&headA,&headB,&headC);
 Show(&headA);
 
 return 0;
}

2.将链表逆置

//算法1:利用栈实现(利用数组模拟栈)//时间复杂度:O(n)  空间复杂度:O(n)
void Reverse1(pList plist)
{
 int len=GetLength(plist);
 int *arr=(int *)malloc (len*sizeof(int));
 assert(arr!=NULL);
 int i=0;//arr的下标
 
 //从头到尾遍历plist,将数据全部存放到arr中
 for(Node *p=plist->next;p!=NULL;p=p->next)
 {
  arr[i++]=p->data;
 }
 
 //金属组中的数据从后往前,再赋值到链表中
 i=len-1;//最后一个元素的下标
 for(Node *p=plist->next;p!=NULL;p=p->next)
 {
  p->data=arr[i--];
 }
 free(arr);
}

//算法2:利用头插和尾插相反的算法 //O(n)  O(1)
void Reverse(pList plist)
{
 Node *p=plist->next;
 Node *q;
 plist->next=NULL;
 while(p!=NULL)
 {
  q=p->next;

  //将p头插到plist中
  p->next=plist->next;
  plist->next=p;
  p=q;
 }
}

3.给定单链表,检测是否有环,并返回相遇结点

//查找相遇结点
static pList IsCircle(pList plist)
{
 Node *p=plist;//快指针
 Node *q=plist;//慢指针
while(q!=NULL)//q为快指针,所以即使为NULL,也是q先为NULL,所以不对p进行判断
{
  p=p->next;
  q=q->next;
if(q==NULL)
{
return NULL;
}
  q=q->next;
if(p==q)
{
return p;//有环,返回快慢指针的相遇结点
}
}
return NULL;
}
//判断是否有环
pList IsCircleList(pList plist)
{
DeterPointNull(plist);
//pNode是快慢指针相遇的结点,不一定是入环的第一个节点
 pList pNode =IsCircle(plist);//找到相遇结点
if(pNode==NULL)//无环
{
return NULL;
}
//求入环的第一个节点
 Node *p=pNode;//相遇结点
 Node *q=plist;//头结点
while(p!=q)//有环,不为NULL
{
  p=p->next;
  q=q->next;
}
return p;//肯定为入环的第一个节点
}

4.给定两个单链表(head1,head2),检测两个链表是否有交点,如果有,返回第一个交点
思路1:通过两个指针,直接跑到最后一个结点,判断两个结点的地址是否相等,但是不返回第一个交点
2思路:求得两个链表的长度,求差值,指向长的链表的指针先跑差值的节点数,两个指针再同时往后跑,每跑一个节点,判断其地址是否相等,则直接返回其中一个指针,这就是相交的第一个节点

pList TwoListIntersec1(pList plistA,pList plistB)
{
DeterPointNull(plistA);
DeterPointNull(plistB);
int len1=GetLength(plistA);
int len2=GetLength(plistB);
 pList p=plistA;
 pList q=plistB;
//跑完差值
if(len1>len2)
{
for(int i=0;i<len1-len2;i++)
{
   p=p->next;
}
}
else
{
for(int i=0;i<len2-len1;i++)
{
   q=q->next;
}
}
//查找并返回相交的第一个节点
while (p!=NULL && q!=NULL)
{
if(p==q)
{
return p;
}
  p=p->next;
  q=q->next;
}
return NULL;
}

5.只给定单链表中某个结点p(并非最后一个结点,即p->next!=NULL)指针,删除该结点 O(1)
思路:如果查找前驱结点,那么时间复杂度必然为O(n),所以此处采取将p->next的结点赋值给p,然后删除p->next结点,从而实现对p结点的删除

bool DeleteNode(pList plist,Node *p)
{
DeterPointNull(plist);
if(p==plist || p==NULL && p->next==NULL)
{
return false;
}
 Node *q=p->next;
 p->data=q->data;
 p->next=q->next;
free(q);
return true;
}

6.只给定单链表中某个节点p(非空节点),在p前面插入一个节点,时间复杂度为O(1)

bool InsertNode(pList plist,Node *p,int val)
{
 if(plist==NULL || p==NULL || p==plist)
 {
  return false;
 }
 Node *q=(Node *)malloc(sizeof(Node));
 q->data=p->data;
 q->next=p->next;
 p->data=val;
 p->next=q;
 return true;
}

7.给定单链表头结点,删除链表中倒数第k个结点

bool DeleteBottomK(pList plist,int k)
{
 DeterPointNull(plist);
 Node *p=plist;
 if(plist->next==NULL || k>GetLength(plist) || k<=0)
 {
  return false;
 }
 int len =GetLength(plist)-k;//删除节点的位置
 for(int i=0;i<k-1;i++)
 {
  p=p->next;
 }
 Node *q=p->next;
 p->next=p->next->next;
 free(q);
 return true;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值