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

来源:互联网 发布:股票涨跌原理 知乎 编辑:程序博客网 时间:2024/06/05 10:23

离散存储【链表】

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;}//创建一个链表,创建一个非循环单链表,并将该链表的头结点的地址赋给 pHeadPNODE  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;}

原创粉丝点击