C语言基础教程(10)链表

链表


C语言和数据结构的连接(过渡)

链表是数据结构第一部分 而是C语言最后一章内容,由此可以比较两者难度

   算法:

   通俗定义:

       解题的方法和步骤

 

   狭义定义:

       对存储数据的操作

       对不同的存储结构,要完成某一个功能所执行的操作是不一样

           比如:

              要输出数组中所有的元素的操作 和

              要输出链表中所有的元素的操作 是不一样的

           这说明:

              算法是依附于存储结构的

             不同的存储结构,所执行的算法是不一样的

 

   广义定义:

       广义的算法也叫泛型 C++

       无论数据是如何存储的,对该数据的操作都是一样的

       分层思想,站在更高的层次看,把内部的实现给屏蔽

      数组和链表都是线性的,都是先输出一个元素后,再输出下一个元素

         

我们至少可以通过两种结构来存储数据

       数组

          优点:存取速度快

          缺点:需要一整块连续的空间

(对于庞大数据,往往没有一个适合的较大的连续的空间如a[30000000000000])

           插入和删除元素效率很低

(插入和删除中间某个元素,其后的所有都要前后移动)

          链表  

             优点:插入删除元素效率高

             缺点:查找某个位置的元素效率低

(由于不是连续的,不同由下标直接找,必须由头至尾逐一比对查找)

两者各有所长,至今没有出现一个更优的存储方式,可集数组、链表优点于一身。

   链表专业术语

       首结点

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

 

       尾结点:

           存放最后一个有效数据的结点,指针域的指针为NULL,尾结点的标志

 

       头结点:

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

           头结点是首结点前面的那个节点

           头结点并不存在有效数据

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

       头指针:

           存放头结点地址的指针变量

 

       确定一个链表需要一个参数,头指针

对于每个链表元素,分为左右两部分,左边为数据单元,右边为下一元素地址。

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


struct Node{

   int data; //数据域

   struct Node * pNext; //指针域

};


//函数声明

struct Node * create_list(void);

void traverse_list(struct Node *);


int main(void){

   struct Node * pHead = NULL;


   pHead = create_list(); 

//create_list():创建一个非循环单链表,并将该链表的头结点的地址付给pHead

   traverse_list(pHead);

   return 0;

}


struct Node * create_list(void){

   int len;  //用来存放有效节点的个数

   int i;

   int val; //用来临时存放用户输入的结点的值


   //分配了一个不存放有效数据的头结点

   struct Node * pHead = (struct Node *)malloc(sizeof(struct Node));

   if (NULL == pHead)

   {

       printf("分配失败, 程序终止!\n");

       exit(-1);

   }

   struct Node * pTail = pHead;

   pTail->pNext = NULL;


   printf("请输入您需要生成的链表节点的个数: len = ");

   scanf("%d", &len);


   for (i=0; i<len; ++i)
   {

       printf("请输入第%d个节点的值: ", i+1);

       scanf("%d", &val);

      

       struct Node * pNew = (struct Node *)malloc(sizeof(struct Node));

       if (NULL == pNew)

       {

          printf("分配失败, 程序终止!\n");

          exit(-1);  //终止程序

       }

       pNew->data = val;

       pTail->pNext = pNew;

       pNew->pNext = NULL;

       pTail = pNew;

   }

   return pHead;

}


void traverse_list(struct Node * pHead)
{

   struct Node * p = pHead->pNext;


   while (NULL != p)
   {

       printf("%d  ", p->data);

       p = p->pNext;

   }

   printf("\n");

   return;

}

 

对于以上例题不要求逐行敲出但要能看懂。

      

字符串的处理

两种: 字符数组   字符指针

 

位运算

      & 按位与  -- 每一位都按位与  (区别&j取地址) 

       1&1 = 1   

       1&0 = 0

       0&0 = 0

       0&1 = 0

      

       | 按位或  -- 每一位都按位与 

 

      ~ 取反     -- 每一位取反

 

      ^ 按位异或 -- 相同为零 不同为1

       1^0=1

       0^1=1

       1^1=0

       0^0=0

 

       << 按位左移   -- 左移n位相当于乘以2的n次方

       i<<3 表示把i的所有二进制位左移动3位,右边补零    

       面试题:

           A) i = i*8;

           B) i = i<<3;

           请问上述两个语句,哪个语句执行的速度快

           答案:B快

           乘法在运算器里,运行原理比较复杂

           按位左移,简单!

 

       >> 按位右移   -- 右移n位相当于除以2的n次方,首位为0补0,首位是1补1

       i>>3 表示把i的所有二进制位右移动3位,左边补零

       防止过度右移,容易丧失精度和意义

      

       位运算的现实意义

       通过位运算符,我们可以对数据的操作精确到每一位。

 

NULL   二进制全部为零的含义

       ---0000000000 的含义

           1.数值零

           2.字符串结束标记 '\0'

           3.空指针NULL

       NULL表示零,而这个零不代表数字零,而表示的内存单元的编号零

          

       我们计算机规定了,以零为编号的存储单元的内容不可读,不可写

           free(p);

           p = NULL;

       *p = 0; 错!把0号单元改写!0单元是非常重要的数据。程序员不可能读写出0号单元信息


纯C的知识

文件

   不是用'流'的思想,用函数实现,于java C++没联系

typedef

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值