单链表的基本操作_legend

本文深入探讨了链表的基本操作,包括初始化、插入、删除、遍历和销毁链表的方法。同时,介绍了选择排序算法的应用,并通过具体实例展示了链表的创建、排序和反转过程。


#include <iostream>
using namespace std;
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>

/*
详细见ppt:线性表基本操作

1.可以学习的地方,函数中按值传递,以及引用传递。
如:此中initLinkList 以及destroy函数中,传递的都是LINKLIST *,
但是在insertNodeAt,deleteNodeAt,searchNode,getNodeAt
等函数中使用的是LINKLIST.
这是因为前者中LINKLIST 传递前后需要变化,后者不需要变化。
另外,在getNodeAt,以及searchNode 中 NODEPTR * pre,也是这个道理。


2.另外就是遍历过程中while循环中输出与获得元素的相对位置。

3.可移植性。tydedef
*/

#define FORMATSTR2 "  %d "

typedef int elementType;

typedef struct NODE_TAG
{
    elementType  data;
    struct NODE_TAG * next;
} NODE,*NODEPTR,*LINKLIST;

/*
此中设置的nodeptr,linklist都是node*,但是不同在于
可以区分是一个普通节点的指针,还是链表中的头结点指针。
*/


// 初始化linkList的头结点。
int initLinkList(LINKLIST* linklist){

*linklist=(NODEPTR)malloc(sizeof(NODE));
if(!*linklist)
return 0;
(*linklist)->next=NULL;
return 1;
}


// 头插法插入一个节点。
int addNode(LINKLIST linklist, elementType element){

NODEPTR pnode=(NODEPTR)malloc(sizeof(NODE));
if(!pnode)
return 0;

pnode->data=element;

NODEPTR firstNode=linklist->next;

pnode->next=firstNode;

linklist->next=pnode;

return 1;
}


// 获取第i个节点,以及其前驱节点pre,如果没有则返回null,pre也为null

NODEPTR getNodeAt(LINKLIST linklist ,int i,NODEPTR* pre){

int k=0;
NODEPTR temp=linklist;

while(temp && (k<i)){
*pre=temp;

temp=temp->next;
k++;
}

if(k<i) {
*pre=NULL;
return NULL;
}

return temp;
}


// 在特定位置i插入一个节点。
int insertNodeAt(LINKLIST linklist, int i, elementType element){

      NODEPTR pNewNode=(NODEPTR)malloc(sizeof(NODE));
      if(!pNewNode) return 0;

      pNewNode->data=element;

      NODEPTR pre ,p;
      p=getNodeAt(linklist,i,&pre);

      if(!p) return 0;

      pNewNode->next=p;
      pre->next=pNewNode;
      return 1;
}


//  删除一个特定位置i的节点。
int deleteNodeAt(LINKLIST linklist, int i ){
      NODEPTR pre ,p;
      p=getNodeAt(linklist,i,&pre);

      if(!p) return 0;
      pre->next=p->next;
      free(p);
      p=NULL;
      return 1;
}


// 通过某个值来查找某个节点。

NODEPTR searchNode(LINKLIST linklist, elementType element, NODEPTR * pre){

      NODEPTR cur=linklist->next;

      while(cur &&(cur->data!=element)){
      *pre=cur;
      cur=cur->next;
      }
      if(!cur) *pre=NULL;
      return cur;
}

// 通过值删除某个节点。
 int deleteNode(LINKLIST linklist, elementType element){
 NODEPTR pcur,pre;
 pcur=searchNode(linklist,element ,&pre);
 if(!pcur) return 0;
 pre->next=pcur->next;
 free(pcur);
 pcur=NULL;
 return 1;

 }

// 遍历linkLIST

void traverseLinkList(LINKLIST linklist){
      printf("\n traverse  the linklist\n");
      if(!linklist) {
            printf("the linklist is empty");
            return ;}
 NODEPTR  pcur;
 pcur=linklist->next;
 while(pcur){
 printf(FORMATSTR2,pcur->data);
 pcur=pcur->next;
 }

 printf("\n");
/*
此中while 循环中,printf函数在pcur=pcur->next之前,类似于
文件遍历中的while,
如果程序改为
pcur=linklist;
while(pcur){
pcur=pcur->next;
printf(FORMATSTR2,pcur->data);
}
则出错,因为到之后pcur=NULL,然后pcur->data,然后循环才可以结束。
*/
}


//销毁linklist
void destroyLinkList(LINKLIST* linklist){

NODEPTR pcur=*linklist;
NODEPTR pre;
while(pcur){
pre=pcur;
pcur=pcur->next;
free(pre);
}
*linklist=NULL;

}

/*不断从控制台输入来创建node,来建linklist,输入0表示输入结束*/

void createLinkList(LINKLIST linklist){

elementType input;
NODEPTR pNewNode;
NODEPTR firstNode;
while(1){

cin>>input;
if(input==0) return ;
pNewNode=(NODEPTR)malloc(sizeof(NODE));
pNewNode->data=input;
firstNode=linklist->next;
pNewNode->next=firstNode;
linklist->next=pNewNode;

}

return ;
}

//选择键值最小的 节点,以及其前驱节点。

NODEPTR minmumNode(LINKLIST linklist, NODEPTR * preNode){

      NODEPTR pnode;

      if(linklist->next){

      NODEPTR p_minNode=linklist->next;
      *preNode=linklist;

            for(pnode=linklist;pnode->next!=NULL;pnode=pnode->next){
                  if(pnode->next->data<p_minNode->data){
                  *preNode=pnode;
                  p_minNode=pnode->next;

                  }
            }

            return p_minNode;
      }

      return NULL;

}

//选择排序
NODEPTR selectAscentSort(LINKLIST linklist){

      NODEPTR pnode=linklist->next;


      LINKLIST newLinklist;
      initLinkList(&newLinklist);
 /*initLinkList函数是为 了建立一个有头结点的空链表*/

      NODEPTR newPNode=newLinklist->next;

      NODEPTR pMinmumNode,pPreMinmum;

      while(pnode){
      pMinmumNode=minmumNode(linklist,&pPreMinmum);

            if(pMinmumNode){
            pPreMinmum->next=pMinmumNode->next;
 //从原有的链表中取掉最小的节点pMinmunNode。

 //头插法建立新的链表,不断更新头。
            pMinmumNode->next=newPNode;
            newLinklist->next=pMinmumNode;
            newPNode=pMinmumNode;

            pnode=pnode->next;
            }
      }
return newLinklist;

}

void insertSort(LINKLIST linklist){


      if(linklist->next)
      {
      NODEPTR pnode_oldList=linklist->next->next;
      /*旧链表从第二个节点开始。*/
      NODEPTR pNode_newList=linklist->next;
      NODEPTR pre_pPnode_newList=linklist;
      pNode_newList->next=NULL;
      NODEPTR pTempNode;
      /*初始时newlist中除了头节点,只有一个节点,就是第一个节点*/

      while(pnode_oldList){

            NODEPTR pNode_newList=linklist->next;
            NODEPTR pre_pPnode_newList=linklist;
            // 从小到大排序
            while(pNode_newList && pnode_oldList->data>pNode_newList->data){
            pre_pPnode_newList=pNode_newList;
            pNode_newList=pNode_newList->next;
            }
            /*
            此中注意:空节点的 处理,如果原链表中有空节点,则插入一个节点之后还是有空节点的,即使是插在最后一个节点之后。
            因为之后一个节点的next为NULL,即NULL 的前驱为最后一个节点,即使是一个节点插在最后一个节点之后,
            那么NULL 还是会有的。

            所以,链表初始化的时候必须给尾节点的next置为NULL。
            */
            /*插入节点*/
            /*注意此中如果pnode_oldList=pnode_oldList->next的位置放在下面注释中,
            则出错,因为在那之前pnode_oldList已经改变了*/
            pTempNode=pnode_oldList;

            pnode_oldList=pnode_oldList->next;

            pTempNode->next=pNode_newList;
            pre_pPnode_newList->next=pTempNode;

            /*pnode_oldList=pnode_oldList->next;*/
      }

      }


}

/*带有头节点的单链表的反转
思想: 想让整个链表反转,先将两个节点反转,然后节点的 追赶。

本来是pnode1->pnode2->pnode3..
然后  逆序为pnode1<-pnode2...
然后         更新pnode1为pnode2;
            更新pnode2为pnode3;(即链表中节点的追赶)
*/
void reverse(LINKLIST linklist){

      if(NULL==linklist->next->next || NULL==linklist->next)
      {
            printf("单链表头节点后只有一个节点,或者只有一个头节点,不需要反转\n");
            return ;
      }

      NODEPTR pnode1=linklist->next;/*第一个节点*/
      NODEPTR pnode2=pnode1->next;/*第二个节点*/

      pnode1->next=NULL;/*第一个节点变成了尾节点*/

      NODEPTR pnode3;
      while(pnode2){
      pnode3=pnode2->next;

      pnode2->next=pnode1;

      pnode1=pnode2;
      pnode2=pnode3;
      }
      /*循环结束时,pnode2=NULL,pnode1为新的首节点*/

      linklist->next=pnode1;

}
// main
int main()
{
      LINKLIST linklist=NULL;
      initLinkList(&linklist);
      elementType element=90;
      createLinkList(linklist);

      traverseLinkList(linklist);

      printf(" insertNodeAt 4 ,vaule=90 \n");
      insertNodeAt(linklist,4,element);

      traverseLinkList(linklist);

      printf("deleteNodeAt 4 \n");
      deleteNodeAt(linklist,4);
      traverseLinkList(linklist);

      printf(" insertNodeAt 4 ,vaule=100 \n");
      insertNodeAt(linklist,4,100);

      traverseLinkList(linklist);
      printf("deleteNode  values 100 \n");
      deleteNode(linklist,100);
      traverseLinkList(linklist);

      printf("reversr the linklist  \n");
      reverse(linklist);
      traverseLinkList(linklist);

/*
      cout<<endl<<"select sort of linklist "<<endl;

      NODEPTR newLinklist=selectAscentSort(linklist);
      traverseLinkList(newLinklist);

      cout<<endl<<"linklist is "<<endl;
      traverseLinkList(linklist);
      */


      cout<<"insertSort of linklist "<<endl;
      insertSort(linklist);
      cout<<endl<<"linklist is "<<endl;
      traverseLinkList(linklist);

    cout << "\nHello world!\n" << endl;

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值