#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;
}