//SCList.h
/*****************************************
头插 尾插 显示 头删 尾删
按值插入 按位置插入 查找 长度
逆序 清除 摧毁 初始化 排序
按位置删除 按值删除
****************************************/
//代码可以进一步优化
#ifndef SCLIST_H_
#define SCLIST_H_
#include <stdio.h>
typedef int ElementType;
typedef enum
{
false_,
true_
}bool_;
//链表的各节点类型
typedef struct Node
{
ElementType data;
struct Node *next;
}Node, *pNode;
//链表的管理结构
typedef struct List
{
Node *first; //指向头结点
Node *last; //指向最后一个节点,用于在某些时候避免不必要的遍历
int size; //链表除头结点的个数
}List, *pList;
bool_ init(List *mylist);
bool_ push_front(List *mylist, ElementType e);
bool_ push_back(List *mylist, ElementType e);
void show(List mylist);
bool_ pop_front(List* mylist, ElementType *e);
bool_ pop_back(List* mylist, ElementType *e);
bool_ insert_val(List *mylist, ElementType e);
bool_ insert_pos(List *mylist, int i, ElementType e);
Node *find(List mylist, ElementType e, bool_ precursor);
int length(List mylist);
void reverse(List *mylist);
void clear(List *mylist);
void destroy(List *mylist);
void sort(List *mylist);
bool_ delete_pos(List *mylist, int i, ElementType *e);
bool_ delete_val(List *mylist, ElementType e);
#endif //SCLIST_H_
//SCList.c
#include "SCList.h"
#include "stdlib.h"
/*******************
与单链表无太大差异
只是判断条件由 != NULL 变为了 != 头结点
值得注意的是,循环链表的头结点千万不能搞丢了,即使是指向头结点的指针不能随意乱指
********************/
bool_ init(List *mylist)
{
mylist->first = mylist->last = (Node *)malloc(sizeof(Node));
if( NULL == mylist->first )
return false_;
mylist->size = 0;
mylist->first->data = -1;
mylist->last->next = mylist->first; //头结点自循环
return true_;
}
bool_ push_front(List *mylist, ElementType e)
{
Node *p = (Node *)malloc(sizeof(Node));
if( NULL == p )
return false_;
p->data = e;
if( 0 == mylist->size )
{
mylist->last = p;
mylist->last->next = mylist->first; //循环
}
p->next = mylist->first->next;
mylist->first->next = p;
mylist->size++;
return true_;
}
bool_ push_back(List *mylist, ElementType e)
{
Node *p = (Node *)malloc(sizeof(Node));
if( NULL == p )
return false_;
mylist->last->next = p;
p->data = e;
p->next = mylist->first; //循环
mylist->last = p;
mylist->size++;
return true_;
}
void show(List mylist)
{
Node *p = mylist.first->next;
while(mylist.first != p) //标志为头结点
{
printf("%d->", p->data);
p = p->next;
}
printf("HEAD\n");
printf("尾节点的值为%d\n", mylist.last->data);
printf("尾节点的后继结点 %s 头结点\n", mylist.last->next == mylist.first ? "是" : "不是");
printf("头结点的值为%d\n", mylist.last->next->data);
}
bool_ pop_front(List* mylist, ElementType *e)
{
if( 0 == mylist->size )
{
printf("链表为空\n");
return false_;
}
Node *p = mylist->first->next;
if( p == mylist->last )
mylist->last = mylist->first; //头结点自循环
mylist->first->next = p->next;
*e = p->data;
free(p);
mylist->size--;
return true_;
}
int length(List mylist)
{
return mylist.size;
}
bool_ pop_back(List* mylist, ElementType *e)
{
if( 0 == mylist->size )
{
printf("链表为空\n");
return false_;
}
Node *p = mylist->first;
while(p->next != mylist->last)
p = p->next;
mylist->last = p; //尾指针
*e = p->next->data;
free(p->next);
p->next = mylist->first;
mylist->size--;
return true_;
}
bool_ insert_val(List *mylist, ElementType e) //此函数的先决条件:链表中已存在节点的数据域值必须有序
{
Node *p = mylist->first;
while(p->next != mylist->last && p->next->data < e)
p = p->next;
if( p->next == mylist->last && p->next->data < e ) //循环链表中所有节点数据域值均小于e
{
return push_back(mylist, e);
}
else
{
Node *s = (Node *)malloc(sizeof(Node));
if (NULL == s)
return false_;
s->data = e;
s->next = p->next;
p->next = s;
mylist++;
}
return true_;
}
//头结点为位置0
bool_ insert_pos(List *mylist, int i, ElementType e)
{
if( i < 1 )
{
printf("位置过小已作为头节点插入\n");
return push_front(mylist, e);
}
if( i > mylist->size + 1 )
{
printf("位置过大已作为尾节点插入\n");
return push_back(mylist, e);
}
Node *s = (Node *)malloc(sizeof(Node));
if( NULL == s )
return false_;
s->data = e;
Node *p = mylist->first;
for(int j = 1; j < i; j++)
p = p->next;
s->next = p->next;
p->next = s;
mylist->size++;
return true_;
}
Node *find(List mylist, ElementType e, bool_ precursor)
{
if( 0 == mylist.size )
return NULL;
Node *p = mylist.first;
while( p->next != mylist.first && p->next->data != e)
p = p->next;
if( p->next->data != e )
return NULL;
else
return precursor ? p : p->next;
}
//还是跟之前一样的做法,将链表分为两个小链表,链表1包含头结点的节点1,链表2为剩下的节点,然后将链表2的每个节点头插入链表1
void reverse(List *mylist)
{
if( 0 == mylist->size || 1 == mylist->size )
return ;
Node *p = mylist->first->next;
Node *q = p->next;
mylist->last = mylist->first->next; //处理尾指针
mylist->last->next = mylist->first; //链表1自循环循环
while(q != mylist->first) //将链表2中的节点逐个头插入链表1
{
p = q; //p指向待插节点
q = q->next; //q继续持有链表2
p->next = mylist->first->next; //按计划插入
mylist->first->next = p;
}
}
void clear(List *mylist)
{
if( 0 == mylist->size )
return ;
Node *p = mylist->first->next;
while(p != mylist->first)
{
mylist->first->next = p->next;
free(p);
p = mylist->first->next;
}
mylist->last = mylist->first; //处理尾指针
mylist->last->next = mylist->first; //自循环
mylist->size = 0;
}
void destroy(List *mylist)
{
clear(mylist);
free(mylist->first);
mylist->first = mylist->last = NULL;
}
void sort(List *mylist)
{
if( 0 == mylist->size || 1 == mylist->size )
return ;
Node *p = mylist->first->next;
Node *q = p->next;
mylist->last = p;
mylist->last->next = mylist->first; //循环
Node *s = mylist->first;
while(q != mylist->first)
{
p = q;
q = q->next;
while(s->next != mylist->first && s->next->data < p->data)
s = s->next;
if( s->next == mylist->first ) //链表1中所有节点数据域值均小于p节点数据域
mylist->last = p;
p->next = s->next;
s->next = p;
s = mylist->first;
}
mylist->last->next = mylist->first; //循环
}
bool_ delete_val(List *mylist, ElementType e)
{
Node * p = NULL;
if( NULL == ( p = find(*mylist, e, true_)) ) //查找目标节点的前驱节点
{
printf("要删除的值不存在\n");
return false_;
}
Node *q = p->next; //目标节点
p->next = q->next;
if( mylist->last = q ) //更改尾指针
mylist->last = p;
free(q);
mylist->size--;
return true_;
}
bool_ delete_pos(List *mylist, int i, ElementType *e)
{
if( 0 == mylist->size )
{
printf("链表为空\n");
return false_;
}
if( i < 1 || i > mylist->size )
{
printf("删除的位置不合法\n");
return false_;
}
Node *p = mylist->first;
Node *q = NULL;
for(int j = 1; j < i; j++)
{
p = p->next;
}
q = p->next;
*e = q->data;
p->next = q->next;
if( q->next == mylist->first )
{
mylist->last = p;
p->next = mylist->first;
}
free(q);
mylist->size--;
return true_;
}
//main.c
/*****************************************
头插 尾插 显示 头删 尾删
按值插入 查找 长度 按值删除 排序
逆序 清除 摧毁 初始化 按位置插入
按位置删除
****************************************/
#include "SCList.h"
int main(int argc, char**argv)
{
int s = 0;
ElementType e;
List mylist;
init(&mylist);
while (1)
{
printf("/******************************************************/\n");
printf("1头插 2尾插 3显示 4头删 5尾删\n");
printf("6按值插入 7查找 8长度 9按值删除 10排序\n");
printf("11逆序 12清除 13摧毁 14按位置删除 15按位置插入\n");
printf("16初始化 17退出\n");
printf("/******************************************************/\n");
printf("请选择操作, -1退出\n");
if (0 == scanf_s("%d", &s))
break;
switch (s)
{
case 1:
printf("请输入待插入的值, -1退出\n");
while (scanf_s("%d", &e), e != -1)
push_front(&mylist, e);
break;
case 2:
printf("请输入待插入的值, -1退出\n");
while (scanf_s("%d", &e), e != -1)
push_back(&mylist, e);
break;
case 3:
show(mylist);
break;
case 4:
if (false_ != pop_front(&mylist, &e))
printf("被删除的值是%d\n", e);
break;
case 5:
if (false_ != pop_back(&mylist, &e))
printf("被删除的值是%d\n", e);
break;
case 6:
printf("请输入待插入的值, -1退出\n");
while (scanf_s("%d", &e), e != -1)
insert_val(&mylist, e);
break;
case 7:
printf("请输入需查找的值\n");
scanf_s("%d", &e);
printf("返回待查值的前驱节点?否:0,是:非0\n");
scanf_s("%d", &s);
if (NULL == find(mylist, e, (s == 0 ? false_ : true_)))
printf("查找的值不存在\n");
break;
case 8:
printf("链表长度为%d\n", length(mylist));
break;
case 9:
printf("请输入待删除的值\n");
scanf_s("%d", &e);
delete_val(&mylist, e);
break;
case 10:
sort(&mylist);
break;
case 11:
reverse(&mylist);
break;
case 12:
clear(&mylist);
break;
case 13:
destroy(&mylist);
break;
case 14:
printf("请输入待删除位置\n");
scanf_s("%d", &s);
if (false_ != delete_pos(&mylist, s, &e))
printf("被删除的值为%d\n", e);
break;
case 15:
printf("请输入待插入位置\n");
scanf_s("%d", &s);
printf("请输入待插入值");
scanf_s("%d", &e);
insert_pos(&mylist, s, e);
break;
case 16:
init(&mylist);
break;
case 17:
goto exit;
default:
printf("选择有误,请从新选择\n");
break;
}
}
exit:
return 1;
}