c语言之链表学习小结

1 链表

Typedef struct linkworker{

//此处Typedef 就是给结构体变量名struct linkworker取别名LINK

    char id[10];

    char name[10];

    struct linkworker *next;  //这个指针是结构体指针,只能指向这样的结构体

}LINK;

   LINK w1={“0001””战士”},w2={“0002”,”法师”},w3={“0003”,”射手”},*head;

   head=&w1;

   w1.next=&w2;

   w2.next=&w3;

  w3.next=NULL;

 

 

 

2 链表的三要素

1、头指针 head 是用来说明链表开始了,头指针就代表链表本身,所以以后要访问链表,就要访问头指针。

2、节点(node)链表中每一个结构体变量。

3、尾指针:用来说明链表结束(它是一个空指针NULL)。

 

如何来创建一个链表

1:用函数来创建一个链表

      返回值(创建的那个链表,实际就是要返回头指针)

      返回指针的函数

 

typedef struct student{

   Char id[10];

   Char name[10];

   Int age;

   Struct student *Next;//这个指针是结构体指针,只能指向这样的结构体

}STU;

STU *createLink(STU a[],int n)//要返回链表实际上就是要返回头指针

//通过结构体数组来提供节点

{

    STU *head;

    Head=&a[0]; //表示把数组a中的第一个元素赋给头指针,让头指针指向第一个节点

    //用循环n=4

    a[0].Next=&a[1];   

    a[1].Next=&a[2];

    a[2].Next=&a[3];   

    a[3].Next=NULL;

//用循环把前一个节点与后一个节点通过next指针联系起来

    for(inti=0;i<n-1;i++)

    { //与上面的几行代码功能一样

        a[i].Next=&a[i+1];

    }

    a[n-1].Next=NULL; //退出循环后,把尾指针作为NULL

    return head; //返回头指针,实际就是链表本身
}

Void findById(STU *head,char id[]);

如何输出链表的所有节点值

void outPutLink(STU *head)//参数需要一个链表,实际就是需要头指针

{       

    STU *p=head;//把链表的头指针赋给指针p

    printf(“学号\t姓名”);

    while(p!=NULL){当访问的节点不到末尾的时候

    printf(“%s\t%s”,p->id,p->name);

    p=p->Next;//把指针移动到下一个节点

}



void main

{

STU a[8]={

    {“s1”,”张1”},{“s2”,”张2”},{“s3”,”你好”},{“s4”,”张三”},

    {“s5”,”战士”},{“s6”,”张三”},{“s7,”哈哈”},{“s8”,”法师”}},*head

    ,NewNode={“s9”,”八戒”,12},*pNewNode=&NewNode;

    Head=createLink(a,8);

    outPutLink(head);

    Head=Insert(head,pNewNode);

    outPutLink(head);

}

 

 

 

链表的查找

链表的查找(如何在链表中查找一个指定的值)如果找到就输出,找不到输出没找到。

Void findById(STU *head,char id[])

{ //在一个链表中查找指定工号

  //要访问链表中的所有节点

    STU *p=head;//把链表的头指针赋给p

While(p!=NULL)

{

    //p就代表链表中的每一个节点,

    //如果p所指向那个节点的id与我们要找的id相同则退出循环

    If(strcmp(p->id,id)==0)

    {

        break;//说明找到了,就要退出循环

    }

    p=p->Next;

}

    If(p=NULL)

    {
       printf(“找不到此人”)
    }
    else{
     //找到了就输出指针所指向的那个节点的值       
      printf(“%s\t%s”,p->id,p->name); 
   }
}

 

链表的删除:

 

1:必须找到要删除的节点(还要保留要删除节点前的节点

2:然后才是删除

3:该函数要返回删除后的新链表,实际上是返回头指针;

根据工号去删除对应链表中的节点

STU *delById(STU *head char id[])//第一个参数告诉是哪一个链表,第二个参数是哪一个节点

{        //必须要找的该节点

    STU*p=head,*fornt;

    While(p!=NULL){

     If(strcmp(p->id,id)==0)     break;//如果这个节点是要找的节点

    //p在向后移动的过程中,首先把当前值赋给front,之后p再去移动

     fornt=p;//状态保存法

     p=p->Next;//移动到下一个节点

}

    If(p!=NULL){    //说明找到了要删除的节点

        //p前面一个节点的Next指向p后面一个节点

        fornt->Next=p->next;//这里的节点其实需要释放空间malloc和free;new和delete

   }

   return head;

}

 

 

 

链表的插入

可能会插入在开头,中间,结尾

1:找的要插入的位置

2:front->Next=&NewNode;           NewNode->next=p;中间

//插入一个节点并返回插入后的链表

 
STU *InsertNode(STU *head, STU *pNewNode)//第一个参数告诉是哪一个链表,第二个参数是哪一个节点

{        //必须要找的该节点

    STU*p=head,*fornt;

    While(p!=NULL&& p->age < pNewNode->age)
   {//如果发现p指向的年龄比新节点的年龄小就不断循环

    //p在向后移动的过程中,首先把当前值赋给front,之后p再去移动

    fornt=p;//状态保存法

     p=p->Next;//移动到下一个节点

   }

If(p==head)
{ //说明新节点插入在开头

    pNewNode->Next=head;//新节点的Next要指向以前的head

    head=pnewNode;//新的head要指向插入的节点

}
else If(p=NULL)
{ //说明新的节点插入在链表的末尾

   Front->next=pnewNode;//把front的Next指向新节点

   pnewNode->next=NULL;//再把新节点的Next赋值为NULL

}
else
{     //说明新的节点插入在中间

      //在p的前面插入

      fornt->Next=pNewNode;//把front的next指向新节点

    新节点的next指向p

   pNewNode->next=p;

}
else
{

    return head;

}

 

 

 

函数模板写链表

#if 1 
#include <iostream>  
using namespace std;

template<class Type>
class Link
{
public:
 Link();
 void Insert(Type&);//插入
 void Delete(Type );//删除
 void Reverse();//倒置
 void Print();//输出
 ~Link();//结点的释放
 struct Node
 {
  Node *next;
  Type* p;
 };
 Node *head;
};

template<class Type>
Link<Type>::Link()
{
  head = NULL;
}

template<class Type>
void Link<Type>::Reverse()
{
 Node * current = head ;
 Node * next = NULL ;
 Node * result = NULL ;
 while( current != NULL )
 {
  next = current->next ;
  current->next = result ;
  result = current ;
  current = next ;
 }
 head = result ;
}

template<class Type>
void Link<Type>::Insert(Type& t)
{
 Node* temp = new Node;
 temp->p = &t;
 temp->next = head;
 head = temp;
}

template<class Type>
void Link<Type>::Delete(Type t )
{
 Node * current = head ;
 while( current != NULL )
 {
  if( current->next != NULL &&* (current->next->p) == t )
  {
   Node * tmp = current->next;
   current->next = current->next->next ;
   delete tmp;
   return ;
  }
  current = current->next ;
 }
}

template<class Type>
void Link<Type>::Print()
{
 for (Node *pp = head; pp; pp = pp->next)
 {
  cout << *(pp->p) << " ";
 }
 cout << endl;
}
template<class Type>
Link<Type>::~Link()
{
 Node* pp;
 while (pp = head)
 {
  head = head->next;
  delete pp->p;
  delete pp;
 }
}
int main()
{
 Link<double> DoubleLink;
 for (int i = 1; i < 7; i++)
 {
  DoubleLink.Insert( * new double(i + 0.1) );
 }
 DoubleLink.Delete( double(2.1) );
 DoubleLink.Reverse();
 DoubleLink.Print();
 return 0;
}
#endif 
 

 

 

 

 

共用体和位运算

什么是共用体?所有成员都使用同一片地址单元

如何来定义共用体

union 共用体类型名

{

成员列表

};

说明:

1、共用体的定义与使用方法与结构体类似

2、结构体中各个成员都有属于自己的存储单元,而共用体中各个成员都共享一个存储单元

3、数据类型与存储单元大小的对应关系;

Int-----2个存储单元(2个字节、16位2进制)

Float---4个存储单元(64位)

Long---4个存储单元(64位)

Char---1个存储单元(8位)

Double--8个存储单元

4、结构体的大小等于结构体中所有成员所占存储单元之和

5、共用体的大小等于共用体中最大成员所占存储单元的大小

6、右边的是低字节,左边的是高字节

位运算

~ :按位求反                   把0变成1,把1变成0

<<:左移                            把数字向左移动,右边补0                    ex:   10001<<2  --> 00100

>>:右移                            把数字向右移动,左边补0                    ex:     10001>>2   --> 00100

&:位与        全为1则为1,有0 为0

10010

  &01110

00010

^:异或            相同为0,不同为1

10010

  ^01110

11100

 

|:位或            有1则1,全0为0

 

优先级别:~、<<、>>、&、^、|

 

Inta=3,b=6;

C=a^b<<2;

先要把10进制化成2进制(化成8):

0000 0 0 1 1              00000 0 1 1

0000 0 1 1 0  -> ^ 0001 1 0 0 0

                                                   000110 1 1

根据优先级先执行左移

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

aFakeProgramer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值