您的位置:首页 > 其它

单链表的基本操作_legend

2014-05-22 12:04 344 查看
#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;

}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  单链表