有头结点和无头结点创建单链表

一,(1)有头结点用头插法创建单链表,输出后是倒序

//头插法建立单链表:读入数据的顺序和生成的链表中元素的顺序是相反的;郝斌老师的里面加入了一个新的结点pTail,pTail和L是一样的也是指向头结点,
     /*pNew->data = val;
	 pTail->pNext = pNew;
	 pNew->pNext = NULL;
	 pTail = pNew;*/ //通过将pTail与pNew互换,这样就可以是pTail继续指向下一个新增结点,顺序是正序
LinkList List_HeadInsert(LinkList &L)
{
  LNode *s;//强调这是一个指向结点的指针
  int x;
  L = (LinkList)malloc(sizeof(LNode));//创建一个头结点,动态分配内存,使得指针L指向这块区域也就是头结点
  L->next = NULL;//初始为空链表
  scanf("%d\n",&x);//输入结点的值
  while(x != 9999)
  {
    s = (LNode*)malloc(sizeof(LNode));
	s->data = x;//将输入的结点的值赋值给新创建的结点指s所值结点的数据域中
	s->next = L->next;//s->next里存放的地址是L->next里的地址,就使得s所指结点指向了头指针所指的那个结点
	L->next = s;//将L->next的地址改为s,这样就会使头结点指向s所指的那个结点
	scanf("%d",&x);
  }
  return L;
}

(2)无头结点用头插法创建单链表

//头插法建立单链表
LinkList List_HeadInsert(LinkList &L)
{
  printf("请输入链表的值\n");
  int x;
  scanf("%d",&x);
  while(x != 9999)
  {
    LNode * s = (LNode *)malloc(sizeof(LNode));//动态分配空间,使s指向这片空间
	s->data = x;//将定义的值赋值到这个结构体的数据域
	s->next = L;//这样s指向的这个结点指向L指向的这个结点,因为头结点,所以最开始L指向的是NULL,s指向的这个结点指向NULL
	L = s;//将s赋给L,这样L就指向了s指向的那个结点
	scanf("%d",&x);
  }
  return L;
}

(2)有头结点尾插法创建单链表

//尾插法建立单链表:正序
//郝斌老师里的加入了len,这样就可以规定链表的长度,这样就不需要规定“x != 9999”,省得取值还有限制
 LinkList List_TailInsert(LinkList &L)
{
  int x;  //设元素类型为整数型
  L = (LinkList)malloc(sizeof(LNode));
  LNode *r = L;//表尾指针,最开始使其也指向头指针
  LNode *s;
  scanf("%d",&x);
  while(x != 9999)
  {
    s = (LNode *)malloc(sizeof(LNode));//动态分配空间,使s指向刚分配空间的结点
	s->data = x;//将x的值赋值给s所指结点的数据域中
	r->next = s;//将s所指结点的地址给头结点,这样头结点就指向了s所指向的那个结点
	r = s;//在将s的地址赋给r,这样r也就指向了s所指的那个结点
	scanf("%d",&x);
  }
  r->next = NULL;
  return L;
}

无头结点用尾插法创建单链表

//用尾插法建立单链表
LinkList List_TailInsert(LinkList &L)
{
  LNode *r;
  r = L;
  LNode *s;
  int x;
  scanf("%d",&x);
  while(x != 9999)
  {
    s = (LNode*)malloc(sizeof(LNode));
	s->data = x;
	s->next = NULL;//该处和 if else 我想了很久都想不出来,是从博主“夕演_hd99”里看的
	if(L == NULL)
	{
	  L = s;
	  r = s;
	}//用这个if条件之后,就可以是L,r都是指向了最开始输入的结构体,这样就可以用r->next,就可以使结构体连接在一起形成链表,若是没有这一步,最开始直接使用r->next会错误,因为最开始r = NULL
	else
	{
		r->next = s;
		r = s;
	}
	scanf("%d",&x);
  }
  return L;
}

二,(1)有头结点按序号查找某一结点

//按序号查找结点
//时间复杂度为O(n)
LNode *GetElem(LinkList L, int i)//i为位序,是从1开始的
{
  if(i<1)
	  return NULL;
  int j = 1;
  LNode *p = L->next;//第一个结点指针赋给p,表示p指向第一个结点
  while(p != NULL && j<i)
  {
	  p = p->next;
	  ++j;
  }
  return p;
}

无头结点按序号查找表结点

//按位查找
LNode *GetElem(LinkList L, int i)
{
  if(i<1)
	  return false;
  else
  {
    LNode *p = L;
	int j = 0;
	while(p != NULL && j < i-2)//因为没有了头结点,所以L指向的就是首节点,因为i是位序是从1开始的,而链表是从0开始的,所以是i-2
	{
		p = p->next;
		++j;
	}
	return p;
  }
}

(2)有头结点按值查找表结点

//按值查找表结点
//时间复杂度为O(n)
LNode * LocateElem(LinkList L, int e)//e表示的是链表中的某一值
{
	LNode *p = L->next;
	while(p != NULL && p->data != e)
	{
		p = p->next;
	}
	return p;

}

无头结点查找表结点

//按值查找
LNode *LocateElem(LinkList L, int e)
{
  LNode *p = L;
  while(p != NULL && p->data != e)
  {
	  p = p->next;

  }
  return p;
}

三,(1)时间复杂度位O(n) 有头结点插入某一结点

//插入结点操作
//时间复杂度为O(n)
bool ListInsert(LinkList L, int i,int e)
{
  LNode *p = GetElem(L, i-1);
  if(NULL == p)
	  return false;
  LNode *s = (LNode*)malloc(sizeof(LNode));
  s->data = e;
  s->next = p->next;
  p->next = s;
  return true;
}

无头结点插入某一结点

//给定位置和值,插入某一结点
bool InsertList(LinkList L, int i, int e)
{
  LNode *p =  GetElem(L, i-1);
  if(NULL == p)
	  return false;
  LNode *q = (LNode*)malloc(sizeof(LNode));
  q->data = e;
  q->next = p->next;
  p->next = q;
  return true;
}

(2)扩展,时间复杂度为O(1),给定某一指针,然后进行插入

有头结点,后插操作

//后插操作:在p1结点之后插入元素e,因为没有循环,所以时间复杂度为O(1)
bool InsertNextNode(LNode *p,int e)
{
  if(NULL == p)
	  return false;
  LNode *s = (LNode*)malloc(sizeof(LNode));
  s->next = p->next;
  p->next = s;
  return true;
}

无头结点,后插操作

//给定某一结构体指针,进行后插操作
bool InsertNextNode(LNode *p, int e)
{
  if(NULL == p)
	  return false;
  LNode *s = (LNode*)malloc(sizeof(LNode));
  s->data = e;
  s->next = p->next;
  p->next = s;
  return true;
}

有头结点,前插操作

//前插操作:在p结点之前插入元素e
bool InsertPriorNode(LNode *p, int e)
{
  if(NULL == p)
	  return false;
  LNode *s = (LNode *)malloc(sizeof(LNode));
  if(NULL == s)
	  return false;
  s->next = p->next;
  p->next = s;//新结点s连接到p之后
  s->data = p->data;//将p中的元素复制到s中
  p->data = e;//p中元素被e覆盖
  return true;
}

无头结点,前插操作

//给定一个结构体指针,进行前插操作
bool InserPriorNode(LNode* p, int e)
{
  if(NULL == p)
	  return false;
  LNode *s = (LNode *)malloc(sizeof(LNode));
  s->next = p->next;
  p->next = s;
  s->data = p->data;
  p->data = e;
  return true;
}

四,删除操作

(1)时间复杂度O(n)

有头结点删除操作

bool ListDelete(LinkList &L, int i, int &e)
{
   LNode *p = GetElem(L, i-1);
   if(NULL == p)
	   return false;
   if(NULL == p->next)//因为p是i的前一个结点,如果p->next == NULL,则说明位置i的结构体为NULL,这样就不要删除
	   return false;
   LNode *q = p->next;
   e = q->data;
   p->next = q->next;
   free(q);
   return true;
}

无头结点删除操作

bool ListDelete(LinkList &L, int i, int &e)
{
  LNode *p =  GetElem(L, i-1);
  if(NULL == p)
	  return false;
  if(NULL == p->next)
	  return false;
  LNode *q = p->next;
  e = q->data;
  p->next = p->next->next;
  free(q);
  return true;
}

(2)指定某一结点删除,时间复杂度O(1)

有头结点,删除指定的某一结点

//删除指定结点p,时间1复杂度O(1)
//如果p是指向链表最后一个结点,则此时就会出现错误,若是想删除指定p结点,则只能从表头往后寻找p的直接前驱
bool DeleteNode(LNode *p)
{
  if(NULL == p)
	  return false;
  LNode *q = p->next;
  p->data = p->next->data;
  p->next = q->next;
  free(q);
 return true;
}

无头结点删除指定的某一结点

//删除指定结点
bool DeleteNode(LNode *p)
{
  if(NULL == p)
	  return false;
  LNode *q = p->next;
  p->data = q->data;
  p->next = q->next;
  return true;
}

五,计算链表的长度

(1)有头结点

//求表的长度
//时间复杂度为O(n)
int length(LinkList L)
{
  int len = 0;//统计链表的长度
  LNode *p = L;
  while(p->next != NULL)
  {
	  p = p->next;
	  len++;
  }
  return len;
}

(2)无头结点计算链表的长度

//链表的长度
int Length(LinkList L)
{
  int len = 0;
  LNode *p = L;
  while(NULL != p)
  {
    len++;
	p = p->next;
  }
  return len;
}

六,(1)有头结点遍历输出

//遍历输出
void PrintLinkList(LinkList L)
{
	LinkList p = L->next;
	while(NULL != p)
	{
		printf("%d\n",p->data);
		p = p->next;
	}
	printf("\n");
	return;
}

(2)无头结点遍历输出

void PrintList(LinkList L)
{
  LinkList p = L;
  while(NULL != p)
  {
	  printf("%d\n",p->data);
	  p = p->next;
  }
  printf("\n");
  return;
}

有头结点的全部代码

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

typedef struct LNode//定义单链表结点类型
{
  int data;//数据域:每个结点存放一个数据元素
  struct LNode *next;//指针域:指针指向下一个节点;因为指针域要指向下一个结点,所以指针的类型肯定要和结点类型一致
}LNode, *LinkList;
//使用LinkList--强调这是一个单链表;  使用LNode* --  强调这是一个结点

//函数说明
LinkList List_HeadInsert(LinkList &L);
LinkList List_TailInsert(LinkList &L);//必须得用&L,因为该函数是要对L进行更改的,所以得是L的地址,不然是无法更改的
void PrintLinkList(LinkList L);
LNode *GetElem(LinkList L, int i);
LNode * LocateElem(LinkList L, int e);
bool ListInsert(LinkList L, int i, int e);
int length(LinkList L);
bool ListDelete(LinkList &L, int i, int &e);
int main(void)
{
  LinkList L = NULL;//强调这是一个头指针指向一个链表,先使其初始化,避免垃圾值
  //L = List_HeadInsert(L);
  printf("创造一个链表:\n");
  L = List_TailInsert(L);
  printf("链表的值为:\n");
  PrintLinkList(L);
  ListInsert(L, 3, 10);
  printf("插入元素之后链表的值为:\n");
  PrintLinkList(L);
  int len = length(L);
  printf("链表的长度为:%d\n",len);
  int e;
  ListDelete( L,3,e);
  printf("删除元素是:%d\n",e);
  return 0;
}


//头插法建立单链表:读入数据的顺序和生成的链表中元素的顺序是相反的;郝斌老师的里面加入了一个新的结点pTail,pTail和L是一样的也是指向头结点,
     /*pNew->data = val;
	 pTail->pNext = pNew;
	 pNew->pNext = NULL;
	 pTail = pNew;*/ //通过将pTail与pNew互换,这样就可以是pTail继续指向下一个新增结点,顺序是正序
 LinkList List_HeadInsert(LinkList &L)
{
  LNode *s;//强调这是一个指向结点的指针
  int x;
  L = (LinkList)malloc(sizeof(LNode));//创建一个头结点,动态分配内存,使得指针L指向这块区域也就是头结点
  L->next = NULL;//初始为空链表
  scanf("%d\n",&x);//输入结点的值
  while(x != 9999)
  {
    s = (LNode*)malloc(sizeof(LNode));
	s->data = x;//将输入的结点的值赋值给新创建的结点指s所值结点的数据域中
	s->next = L->next;//s->next里存放的地址是L->next里的地址,就使得s所指结点指向了头指针所指的那个结点
	L->next = s;//将L->next的地址改为s,这样就会使头结点指向s所指的那个结点
	scanf("%d",&x);
  }
  return L;
}


//尾插法建立单链表:正序
//郝斌老师里的加入了len,这样就可以规定链表的长度,这样就不需要规定“x != 9999”,省得取值还有限制
 LinkList List_TailInsert(LinkList &L)
{
  int x;  //设元素类型为整数型
  L = (LinkList)malloc(sizeof(LNode));
  LNode *r = L;//表尾指针,最开始使其也指向头指针
  LNode *s;
  scanf("%d",&x);
  while(x != 9999)
  {
    s = (LNode *)malloc(sizeof(LNode));//动态分配空间,使s指向刚分配空间的结点
	s->data = x;//将x的值赋值给s所指结点的数据域中
	r->next = s;//将s所指结点的地址给头结点,这样头结点就指向了s所指向的那个结点
	r = s;//在将s的地址赋给r,这样r也就指向了s所指的那个结点
	scanf("%d",&x);
  }
  r->next = NULL;
  return L;
}

//遍历输出
void PrintLinkList(LinkList L)
{
	LinkList p = L->next;
	while(NULL != p)
	{
		printf("%d\n",p->data);
		p = p->next;
	}
	printf("\n");
	return;
}


//按序号查找结点
//时间复杂度为O(n)
LNode *GetElem(LinkList L, int i)//i为位序,是从1开始的
{
  if(i<1)
	  return NULL;
  int j = 1;
  LNode *p = L->next;//第一个结点指针赋给p,表示p指向第一个结点
  while(p != NULL && j<i)
  {
	  p = p->next;
	  ++j;
  }
  return p;
}


//按值查找表结点
//时间复杂度为O(n)
/*LNode * LocateElem(LinkList L, int e)//e表示的是链表中的某一值
{
	LNode *p = L->next;
	while(p != NULL && p->data != e)
	{
		p = p->next;
	}
	return p;

}*/


//插入结点操作
//时间复杂度为O(n)
bool ListInsert(LinkList L, int i,int e)
{
  LNode *p = GetElem(L, i-1);
  if(NULL == p)
	  return false;
  LNode *s = (LNode*)malloc(sizeof(LNode));
  s->data = e;
  s->next = p->next;
  p->next = s;
  return true;
}

//下面两个插入就是指定将某个结点插入在某个指针的位置
//后插操作:在p1结点之后插入元素e,因为没有循环,所以时间复杂度为O(1)
bool InsertNextNode(LNode *p,int e)
{
  if(NULL == p)
	  return false;
  LNode *s = (LNode*)malloc(sizeof(LNode));
  s->next = p->next;
  p->next = s;
  return true;
}

//拓展:对某一结点进行前插操作
//时间复杂度为:O(1)
//前插操作:在p结点之前插入元素e
bool InsertPriorNode(LNode *p, int e)
{
  if(NULL == p)
	  return false;
  LNode *s = (LNode *)malloc(sizeof(LNode));
  if(NULL == s)
	  return false;
  s->next = p->next;
  p->next = s;//新结点s连接到p之后
  s->data = p->data;//将p中的元素复制到s中
  p->data = e;//p中元素被e覆盖
  return true;
}


//按位序删除结点
//时间复杂度O(n)
bool ListDelete(LinkList &L, int i, int &e)
{
   LNode *p = GetElem(L, i-1);
   if(NULL == p)
	   return false;
   if(NULL == p->next)//因为p是i的前一个结点,如果p->next == NULL,则说明位置i的结构体为NULL,这样就不要删除
	   return false;
   LNode *q = p->next;
   e = q->data;
   p->next = q->next;
   free(q);
   return true;
}

//指定结点的删除
//删除指定结点p,时间1复杂度O(1)
//如果p是指向链表最后一个结点,则此时就会出现错误,若是想删除指定p结点,则只能从表头往后寻找p的直接前驱
bool DeleteNode(LNode *p)
{
  if(NULL == p)
	  return false;
  LNode *q = p->next;
  p->data = p->next->data;
  p->next = q->next;
  free(q);
 return true;
}

//求表的长度
//时间复杂度为O(n)
int length(LinkList L)
{
  int len = 0;//统计链表的长度
  LNode *p = L;
  while(p->next != NULL)
  {
	  p = p->next;
	  len++;
  }
  return len;
}

后插法创建链表 

无头结点全部代码

#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
typedef struct LNode
{
  int data;
  struct LNode *next;
}LNode, *LinkList;
//函数说明
LinkList List_HeadInsert(LinkList &L);
LinkList List_TailInsert(LinkList &L);
void PrintList(LinkList L);
LNode *GetElem(LinkList L, int i);//按位查找
LNode *LocateElem(LinkList L, int e);//按值查找
bool InsertList(LinkList L, int i, int e);//插入某一结点
bool ListDelete(LinkList &L, int i, int &e);//删除某一结点
int Length(LinkList L);//求链表的长度
int main(void)
{
  LinkList L = NULL;
  printf("创建一个链表\n");
  L = List_HeadInsert(L);
  //List_TailInsert(L);
  printf("链表的数据域为\n");
  PrintList(L);
  InsertList(L,2,10);
  printf("插入之后链表的值为:\n");
  PrintList(L);
  int e;
  if(ListDelete(L,4,e))
  {
    printf("删除成功,删除的元素是:%d\n",e);
  }
  else
  {
    printf("删除失败!\n");
  }
  printf("删除元素之后链表的值为:\n");
  PrintList(L);
  int len = Length(L);
  printf("链表的长度:%d\n",len);
  return 0;
}

//头插法建立单链表
LinkList List_HeadInsert(LinkList &L)
{
  printf("请输入链表的值\n");
  int x;
  scanf("%d",&x);
  while(x != 9999)
  {
    LNode * s = (LNode *)malloc(sizeof(LNode));//动态分配空间,使s指向这片空间
	s->data = x;//将定义的值赋值到这个结构体的数据域
	s->next = L;//这样s指向的这个结点指向L指向的这个结点,因为头结点,所以最开始L指向的是NULL,s指向的这个结点指向NULL
	L = s;//将s赋给L,这样L就指向了s指向的那个结点
	scanf("%d",&x);
  }
  return L;
}

//用尾插法建立单链表
LinkList List_TailInsert(LinkList &L)
{
  LNode *r;
  r = L;
  LNode *s;
  int x;
  scanf("%d",&x);
  while(x != 9999)
  {
    s = (LNode*)malloc(sizeof(LNode));
	s->data = x;
	s->next = NULL;//该处和 if else 我想了很久都想不出来,是从博主“夕演_hd99”里看的
	if(L == NULL)
	{
	  L = s;
	  r = s;
	}//用这个if条件之后,就可以是L,r都是指向了最开始输入的结构体,这样就可以用r->next,就可以使结构体连接在一起形成链表,若是没有这一步,最开始直接使用r->next会错误,因为最开始r = NULL
	else
	{
		r->next = s;
		r = s;
	}
	scanf("%d",&x);
  }
  return L;
}

void PrintList(LinkList L)
{
  LinkList p = L;
  while(NULL != p)//已经多次失误用成if
  {
	  printf("%d\n",p->data);
	  p = p->next;
  }
  printf("\n");
  return;
}

//按位查找
LNode *GetElem(LinkList L, int i)
{
  if(i<1)
	  return false;
  else
  {
    LNode *p = L;
	int j = 0;
	while(p != NULL && j < i-2)//因为没有了头结点,所以L指向的就是首节点,因为i是位序是从1开始的,而链表是从0开始的,所以是i-2
	{
		p = p->next;
		++j;
	}
	return p;
  }
}

//按值查找
LNode *LocateElem(LinkList L, int e)
{
  LNode *p = L;
  while(p != NULL && p->data != e)
  {
	  p = p->next;

  }
  return p;
}


//给定位置和值,插入某一结点
bool InsertList(LinkList L, int i, int e)
{
  LNode *p =  GetElem(L, i-1);
  if(NULL == p)
	  return false;
  LNode *q = (LNode*)malloc(sizeof(LNode));
  q->data = e;
  q->next = p->next;
  p->next = q;
  return true;
}

//给定某一结构体指针,进行后插操作
bool InsertNextNode(LNode *p, int e)
{
  if(NULL == p)
	  return false;
  LNode *s = (LNode*)malloc(sizeof(LNode));
  s->data = e;
  s->next = p->next;
  p->next = s;
  return true;
}


//给定一个结构体指针,进行前插操作
bool InserPriorNode(LNode* p, int e)
{
  if(NULL == p)
	  return false;
  LNode *s = (LNode *)malloc(sizeof(LNode));
  s->next = p->next;
  p->next = s;
  s->data = p->data;
  p->data = e;
  return true;
}


//删除某一结点
bool ListDelete(LinkList &L, int i, int &e)
{
  LNode *p =  GetElem(L, i-1);
  if(NULL == p)
	  return false;
  if(NULL == p->next)
	  return false;
  LNode *q = p->next;
  e = q->data;
  p->next = p->next->next;
  free(q);
  return true;
}


//删除指定结点
bool DeleteNode(LNode *p)
{
  if(NULL == p)
	  return false;
  LNode *q = p->next;
  p->data = q->data;
  p->next = q->next;
  return true;
}

//链表的长度
int Length(LinkList L)
{
  int len = 0;
  LNode *p = L;
  while(NULL != p)
  {
    len++;
	p = p->next;
  }
  return len;
}

 前插法创建单链表

 

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值