数据结构基础三-----之模块一《离散存储【链表】》

离散存储【链表】

1.定义:

       n个结点离散分配
       彼此通过指针相连
       每个结点只有一个前驱结点,每个结点只有一个后续结点
       首结点没有前驱结点,尾结点没有后续结点               


2.专业术语:

      首结点:第一个存放有效数据的结点

      尾结点:最有一个存放有效数据的结点

      头结点:头结点的数据类型和首结点的类型是一样的

                      首结点之前的结点//   第一个有效结点之前的那个指针

                      头结点并不存放有效数据,也没有存放整个链表中 结点的个数。

                      加头结点的目的是为了方便对链表的操作

      头指针:指向头结点的指针变量  链表的首位置

      尾指针:指向尾结点的指针变量

示例1:如何定义一个结点(每一个结点的类型如何表示)

typedef struct Node
{
  int data; //数据域
  struct Node * pNext; //指针域

//指针存储的地址只能是 struct Node 类型。
//指针域指向的 是与 本身结点数据类型相同的下一个结点 所以数据类型是 struct Node *;
}NODE,*PNODE;

//NODE 等价于 struct Node,
//PNODE 等价于 struct Node *;


      

3.如果希望一个函数来对链表进行处理,我们至少需要接受链表的哪些信息:

          只需要一个参数:头指针
          以为我们通过头指针可以推算出链表的其他所有参数
                    

4.分类:

         单链表:每个结点的指针域只指向后面的结点
         双链表:每一个结点有两个指针(指前指后) 
         循环链表:能通过任何一个结点找到其他所有的结点
         非循环链表

5.算法:

       遍历
       查找
       清空
       销毁
       求长度
       排序
       删除结点

       插入结点


插入结点:(伪算法)

 

//第1种写法
  r = p->pNext; 
   p->pNext = q; 
   q->pNext = r;

//第2种写法
   q->pNext = p->pNext; 
   p->pNext = q;//(这两行代码不能倒过来)

/*

  q 本身就是结点的地址  q 指向的就是 结点

  q-> pNext 表示的就是结点的指针域  

  至于指针域中存放的下一个结点的地址是谁 稍加判断就好了。

  最重要的!p->pNext //p所指向的结构体变量中 pNext 成员本身。
*/


删除结点:(伪算法)

  r = p->pNext;
 p->pNext = p->pNext->pNext; 
  free(r);//这里很重要 一定要记得释放内存,防止内存 溢出

示例2:创建并遍历一个链表,实现判断是否为空,求链表的长度查找删除

仿JAVA中LinkedList对象部分功能的实现

#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
typedef struct Node
{
//数据域
	int data;
//指针域
	struct Node * pNext;
//指针域指向的 是与 本身结点数据类型相同的下一个结点 所以数据类型是 struct Node *;
}NODE,*PNODE;
//NODE 等价于 struct Node,
//PNODE 等价于 struct Node *;
//函数声明
PNODE  create_list(void);
void traverse_list(PNODE pHead);
bool is_empty(PNODE pHead);
int length_list(PNODE);
bool insert_list(PNODE,int,int);
bool delete_list(PNODE,int,int *);
void sort_list(PNODE);

int main(void)
{
   PNODE pHead = NULL;//等价于 struct Node * pHead = NULL;
   //create_list()的功能:创建一个非循环单链表,并将该链表的头结点的地址赋给 pHead
   pHead = create_list();
   traverse_list(pHead);//遍历
   if(is_empty(pHead))
      printf("链表为空\n");
   else
      printf("链表不空\n");
   int len = length_list(pHead);
   printf("链表的长度是%d \n",len);
   sort_list(pHead);
   traverse_list(pHead);//遍历
   insert_list(pHead,2,33);
   traverse_list(pHead);//遍历
   int val;
   if(delete_list(pHead,4,&val))
   {
      printf("您删除的元素是%d\n",val);
   }
   else
   {
      printf("删除失败%d\n",val);
   }
   return 0;
}

//创建一个链表,创建一个非循环单链表,并将该链表的头结点的地址赋给 pHead
PNODE  create_list(void)
{
   //C语言里的写法是把所有的变量都定义在前面
   int len;//用来存放有效结点的个数
   int i;
   int val;//用来存放用户输入的有效结点的值
   //升成一个头结点  头结点的数据类型与 其他结点是相同的。
   //分配了一个不存放有效数据的头结点
   PNODE pHead = (PNODE)malloc(sizeof(NODE));
   if(NULL == pHead)
   {
      printf("分配失败,程序终止。\n");
      exit(-1);
   }
   //pTail  永远指向 尾结点
   PNODE pTail = pHead;
   pTail -> pNext = NULL;
   printf("请输入您需要生成的链表的结点的个数:len =");
   scanf("%d",&len);
   for(i =0;i<len;++i)
   {
      printf("请输入第%d个结点的值:",i+1);
      scanf("%d",&val);
      PNODE pNew  = (PNODE)malloc(sizeof(NODE));
      if(NULL == pNew)
      {
         printf("分配失败,程序终止。\n");
         exit(-1);
      }
      pNew ->data = val;
      //新生成的结点要挂到整个链表的最后的一个位置。
      pTail -> pNext = pNew;
      pNew ->pNext = NULL;
      pTail = pNew;
      }
   return pHead;
}

//遍历这个链表
void traverse_list(PNODE pHead)
{
//p 指向的是链表的第一个有效结点
   PNODE p  = pHead->pNext;
   while(p!= NULL)
   {
      printf("  %d",p->data);
      p = p->pNext;
   }
   printf("\n");
   return;
}

//判断链表是否为空
bool is_empty(PNODE pHead)
{
   if(pHead->pNext == NULL)
      return true;
   else
      return false;
}

//返回链表长度
int length_list(PNODE pHead)
{
   PNODE p = pHead ->  pNext;
   int len = 0;
   while(p != NULL)
   {
      len++;
      p = p->pNext;
   }
   return len;
}

//链表排序
void sort_list(PNODE pHead)
{	
  //实际上算法都是类似
  //数组和链表同样都是 线性结构
   int i,j,t;
   PNODE p, q;
   int len = length_list(pHead);
   //i 是数组中第一个有效元素的下标  p 是链表中第一个有效元素的 地址。
   for(i = 0,p = pHead ->pNext;i<len - 1;++i,p = p->pNext)
   {
   //  q 就应该是p 的下一个元素
      for(j = i+1,q = p ->pNext;j<len;++j,q = q->pNext)
      {
	/*
	请参照数组中的方式来理解 链表
	if(a[i] > a[j])
	{
	   t = a[i];
	   a[i] = a[j];
	   a[j] = t;
	}
	*/
	if((p->data )> (q->data))
	{
	   t = p->data;
	   p->data = q->data;
   	   q->data= t;
	}
      }
   }
	return;
}

//在pHead 所指向链表的第pos 个结点的前面插入一个新的结点,该结点的值是 val并且 pos 的值是从1 开始。
bool insert_list(PNODE pHead,int pos,int val)
{
   int i = 0;
   PNODE  p = pHead;
   while(p != NULL && i<pos -1)
   {
      p = p->pNext;
      i++;
   }
   if(i>pos-1||p== NULL)
      return false;
   PNODE pNew = (PNODE)malloc(sizeof(PNODE));
   if(pNew == NULL)
   {
      printf("动态分配内存失败");
      exit(-1);
   }
   pNew ->data = val;
   //定义了一个临时结点
   PNODE q = p->pNext;
   p->pNext = pNew;
   pNew ->pNext = q;
   return true;
}

//删除指定位置的元素,并用*pVal记录被删除的元素
bool delete_list(PNODE pHead,int pos,int * pVal)
{
   int i = 0;
   PNODE  p = pHead;
   while(p ->pNext!= NULL && i<pos -1)
   {
      p = p->pNext;
      i++;
   }
   if(i>pos-1||p ->pNext== NULL)
      return false;
   PNODE q = p ->pNext;
   *pVal = q ->pNext;
  //删除p结点后面的结点
   p->pNext = p->pNext->pNext;
   free(q);
   q = NULL;
   return true;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值