//单链表的操作 (不带表头节点)
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MALLOC(p,s) \
if( !( (p) = malloc(s) ) ) { \
fprintf(stderr,"Insufficient memory.\n"); \
exit(EXIT_FAILURE); \
}
typedef struct listNode *listPtr;
struct listNode
{
int data;
listPtr link;
};
/* 1.初始化线性表,即置单链表的表头指针为空 */
void initList(listPtr *pNode)
{
*pNode = NULL;
printf("initList函数执行,初始化成功\n");
}
//创建两个节点链表, first 指向第一个节点,second指向第二个节点
//返回变量first指向表头
listPtr create()
{ /* create a linked list with two node */
listPtr first, second;
MALLOC(first, sizeof(*first) );
MALLOC(second, sizeof(*second) );
second->link = NULL;
second->data = 20;
first ->data = 10;
first->link = second;
return first;
}
listPtr getNode(int item)
{
listPtr newNode;
MALLOC(newNode, sizeof(*newNode));
memset(newNode, 0, sizeof(*newNode));
newNode->data = item;
newNode->link = NULL;
return newNode;
}
//计算单链表的长度
int length( listPtr lead )
{
int len = 0;
while( lead )
{
++len;
lead = lead->link;
}
return len;
}
//链表的插入,要在链表中的任意位置x之后插入一个节点,节点的数据域是50
//函数的参数有两个,first指向表头,如果first为空指针,则返回后它的值
//变成指向数据域为50的指针,由于这个指针的内容可能改变,必须传这个指针的地址
//形参声明为listPtr *first,第二个参量值x不会改变,因此不用传它的地址。函数调用
//语句应为insert(&first, x),first是表头,x指向插入的位置
void insert(listPtr *first, listPtr x )
{ /* insert a new node with data = 50 into the chain first after node x */
listPtr tempNode;
MALLOC(tempNode, sizeof(*tempNode));
tempNode->data = 50;
if ( *first )
{ // not NULL
tempNode->link = x->link; //在x与其后继节点之间插入tempNode指向的节点
x->link = tempNode;
}
else
{ // empty list
tempNode->link = NULL;
*first = tempNode;
}
}
//在链表的表头插入一个元素,若成功返回1,失败返回0;
int insertFront(listPtr *front, int x )
{
listPtr p;
MALLOC(p, sizeof(*p) );
memset(p, 0, sizeof(*p) );
p->data = x;
p->link = (*front);
*front = p;
printf("向表头插入元素 %d 成功\n", x);
return 1;
}
//单链表的正向排序
//将item插入到一个从小到大排序的有序链表中
void insertSort(listPtr *front, const int item )
{
listPtr newNode;
newNode = getNode(item);
if( *front == NULL )
{// empty list
*front = newNode;
}
else if ( (*front)->data >= newNode->data )
{ // 在第一个节点之前插入
newNode->link = *front;
*front = newNode;
}
else
{
listPtr curr = *front;
listPtr prev = NULL;
//找到需要插入的位置
while(newNode->data > curr->data && curr->link != NULL )
{
prev = curr;
curr = curr->link;
}
//如果是在中间位置,把newNode插入到prev和curr之间
if ( curr->data >= newNode->data )
{
newNode->link = curr;
prev->link = newNode;
}
else
{ //位置在末尾,把newNode插入到curr之后
curr->link = newNode;
}
}
}
//将一个节点按节点中值的升序插入到一个链表中
listPtr insertNode( listPtr front, listPtr node )
{
listPtr prev = NULL;
listPtr curr = front;
while( curr != NULL && curr->data < node->data )
{
prev = curr;
curr = curr->link;
}
if ( curr == front )
{
node->link = front;
front = node;
}
else
{ //插入到 prev和curr之间
prev->link = node;
node->link = curr;
}
return front;
}
//将两个有序链表head1和head2合并成一个链表,依然有序,使用递归方法以及非递归方法
//非递归合并
listPtr mergeList( listPtr head1, listPtr head2 )
{
//若果有一个是空表则返回另一个
if ( head1 == NULL )
return head2;
if ( head2 == NULL )
return head1;
// neither list is NULL,find the shorter one
listPtr head ; //指向两个表中较长的那个表的表头
listPtr p; //指向较短的那个表表头
listPtr nextP; //指向p之后
if(length(head1) > length(head2))
{
head = head1;
p = head2;
}
else
{
head = head2;
p = head1;
}
//将较短表中的元素逐个插入到较长的表中
while ( p != NULL )
{
nextP = p->link; //保存p的下一结点
head = insertNode(head, p); //将p插入到目标链表中
p = nextP; // p指向将要插入的下一个节点
}
return head;
}
//递归合并两个有序链表
listPtr mergeRecursive(listPtr head1, listPtr head2 )
{
listPtr head = NULL;
if ( head1 == NULL )
return head2;
if (head2 == NULL )
return head1;
if (head1->data < head2->data )
{
head = head1;
head->link = mergeRecursive( head1->link, head2 );
}
else
{
head = head2;
head->link = mergeRecursive( head1, head2->link );
}
return head;
}
//打印链表,最先打印first的数据域,然后first的值用它自己的link域值替换
//这样访问链表的所有节点知道结束。
void printList(listPtr first )
{
printf("The list contains: ");
for( ; first; first = first->link )
printf("%4d", first->data );
printf("\n");
}
//将链表反向
listPtr invert(listPtr lead )
{ /* invert the list pointed to by lead */
listPtr trail, middle;
middle = NULL;
while ( lead )
{
trail = middle;
middle = lead;
lead = lead->link;
middle->link = trail;
}
return middle;
}
//把两个单向链表ptr1, ptr2连接起来,函数复杂度是O(prt1长度)
//函数不申请新节点,连接就放在ptr1中
listPtr concatenate( listPtr ptr1, listPtr ptr2 )
{ /* produce a new list that pointed to by ptr1
* is changed permanently */
listPtr temp;
/* check for empty lists */
if ( !ptr1 ) return ptr2;
if ( !ptr2 ) return ptr1;
/* neither list is empty, find end of first list */
for ( temp = ptr1; temp->link; temp = temp->link );
/* link end of first to start of second */
temp->link = ptr2;
return ptr1;
}
//清空链表,当程序不再需要链表时,应当即使释放链表所占用的内存
//通过重复删除表头节点直至链表为空(front = NULL)来清空一个链表
void freeList(listPtr *front)
{
listPtr p;
//不能删除空链表的front节点
while( *front != NULL)
{
// p指向原来的front节点
p = *front;
//把front移到下一个节点
*front = (*front)->link;
free( p );
}
printf("已清空链表\n");
}
//在链表总查找具有特定值target的第一个节点,若查找成功返回指向该节点的指针,失败返回NULL
listPtr find( listPtr front, const int target )
{
listPtr p = front;
while ( p != NULL && p->data != target )
{
p = p->link;
}
return p;
}
//删除链表中的节点,删除节点需要考虑节点所在的位置。 假设first指向表头,x指向待删除节点,
//指向x的直接前驱节点。如果待删除节点是表头,因此必须改变first的值,如果不是表头节点只需要
//将trail的链域改变,让它指向x所指向的节点即可
void deleteNode(listPtr *first, listPtr x )
{ /* delete x from the list, trail is the preceding node
* and *first is the front of the list
*/
listPtr trail; // 指向x的前驱节点
if ( x == (*first) )
trail = NULL;
else
{ // x is not the first, find the position of trail
for(trail = *first; trail->link != x; trail= trail->link);
}
if(trail != NULL)
{ //trail is not NULL, means it is not the first
trail->link = x->link;
}
else
{
*first = (*first)->link;
}
free(x);
}
//判断一位链表是否有环, 有环返回1,无环返回0
int hasLoop(listPtr front)
{
listPtr fast = front;
listPtr slow = front;
while(fast != NULL && fast->link != NULL)
{
slow = slow->link; // 1 step
fast = fast->link->link; // 2 step
if( fast == slow)
return 1;
}
return 0;
}
//删除一个具有特定值的节点,如果链表中存在值target则删除找到的第一个匹配的节点
//否则不改变链表。函数可能会改变头结点,所以要传递该指针的地址或引用
void eraseValue(listPtr *front, const int target)
{
int found = 0; //如果找到节点,将设置为1
listPtr curr; //用于遍历链表
listPtr trail; // 跟在curr的后面
curr = *front;
trail = NULL;
//扫面链表直到找到目标节点或者到达链表尾
while ( curr != NULL && !found )
{
if( curr->data == target )
{ // have a match
//要删除的是不是表头节点
if(trail == NULL)
{
*front = (*front)->link; // remove the first node
}
else
{
trail->link = curr->link; // erase the intermediate node
}
free(curr);
found = 1;
}
else
{
trail = curr;
curr = curr->link;
}
}
}
int main()
{
listPtr list1 = create();
insertFront(&list1,30);
insertFront(&list1, 40);
printList(list1);
listPtr list2 = create();
list2 = invert(list2);
printList(list2);
listPtr list3 = concatenate(list1, list2);
printList(list3);
listPtr p = find(list3, 10);
deleteNode(&list3, p);
printList(list3);
int size = length(list3);
printf("The size of list3 is: %d\n", size);
freeList(&list3);
listPtr head = getNode(3);
int i;
for (i = 10; i > 0; i--)
insertSort(&head, i);
printList(head);
insertNode(head,getNode(100));
printList(head);
listPtr k;
initList(&k);
for (i = 10; i > 0; i--)
k = insertNode(k, getNode(i+10));
printList(k);
listPtr j = NULL;
for (i = 17; i < 25; i++)
j = insertNode(j, getNode(i));
printList(j);
//listPtr m = mergeList(j,k);
listPtr m = mergeRecursive(j, k);
printList(m);
return 0;
}
单链表的实现(不带头节点)
最新推荐文章于 2023-03-19 17:48:15 发布