线性表
6/27/2016 20:35 PM
1. 顺序线性表seqlist
在内存中的存储在连续的空间,可以利用一维数组实现。
特点:
1. 连续存储;
2. 存取密度高;
3. 删除、插入需要移动大量元素;
4. 内存利用不灵活
2. 链式线性表linklist
内存中随机存储,分不再不同存储块,称为结点。通过指针相互链接。
typedef struct node_t{
data_t data;
struct node_t* next;
}linklist_t; //一般用typedef重名为linklist_t类型;
特点:
1.各个结点通过malloc动态分配空间;
2. 因此不是连续的;
相关功能实现代码
//在c语言中,非零==真
#define TRUE 1
#define FALSE 0
typedef int data_t;
typedef int bool;
/*******节点类型定义Link_t*****/
typedef struct node{
data_t data; //储存数据:
struct node *next; //下一个节点指针域
}Link_t;
Link_t *linklist_create(); //创建链表
bool linklist_isEmpty(Link_t *head); //判空
//求链表长度,不包括头指针
int linklist_getLength(Link_t *head); //求链表长度
//找到指定位置pos的元素,这里人性化点,按照人思维,第1个就是head->next所指向
data_t linklist_getElem(Link_t *head, int pos);
//找到指定位置pos地址指针,同上,人性化
Link_t* linklist_getLocation(Link_t *head, int pos);
bool linklist_clear(Link_t *head); //清空
void linklist_destroy(Link_t *head); //摧毁,释放内存空间
bool linklist_insert(Link_t *head, int pos, data_t add); //在指定位置处插入元素,即前插,不是后插哦
bool linklist_deletPosition(Link_t *head, int pos); //删除指定位置的元素
bool linklist_deletElem(Link_t *head, data_t elem); //删除指定的元素
int linklist_locate(Link_t *head, data_t elem); //定位elem在链表中第一次出现的位置
bool linklist_dataReplace(Link_t * head, data_t old_data, data_t new_data); //将链表中old_data替换成new_data
bool linklist_showList(Link_t *head); //显示整个链表
Link_t* linklist_malloc(); //为临时节点开辟空间
void linklist_invert(Link_t *head); //链表倒置
void linklist_sort(Link_t *head); //链表插入排序法
#endif
/*linklist.c*/
#include<stdio.h>
#include<stdlib.h>
#include <strings.h>
#include "linklist.h"
/*动态分配内存创建
*创建成功返回Link_t* 指针
* 失败:NULL
*/
Link_t *linklist_create()
{
Link_t *head = (Link_t *)linklist_malloc();
if(NULL == head)
{
printf("Linklist create Failed...\n");
return NULL;
}
bzero(head, sizeof(Link_t));
//将头指针初始化,假定-1为无效的数据,指针置空
head->data = -1;
head->next = NULL;
printf("new list has been created....\n");
return head;
}
bool linklist_isEmpty(Link_t * head)
{
return (head->next == NULL);
}
//求链表长度,不包括头指针
int linklist_getLength(Link_t *head)
{
int len = 0;
Link_t *p = head->next;
while(NULL != p)
{
len++;
p = p->next;
}
return len;
}
/*
*清除链表
*不能过直接将头指针的next置空,否则链表其他的节点再也无法操作,导致内存一直占用
*除了头节点,其他节点空间全部释放
*/
bool linklist_clear(Link_t *head)
{
Link_t *p = head->next;//用于记录当前节点的下一个节点地址,方便循环
Link_t *q = NULL; //用于指向要删除的节点
while(NULL != p)
{
q = p; //将循环到的非空地址保存到q
free(q); //释放q
p = p->next; //p继续找到下一个
}
head->next = NULL; //将头指针置空
}
data_t linklist_getElem(Link_t *head, int pos) //找到指定位置的元素
{
//由于人性化,所以插入的位置不能为0,pos: [1,len+1]
//插入的位置可以是最后一个元素的后边,因此<=len+1
if(pos < 1 || pos > linklist_getLength(head)+1)
{
printf("Position Invalid. Can`t find the elem...\n");
return FALSE;
}
int i = 0;
Link_t *p = head->next;
while(NULL != p)
{
i++;
if(i == pos)
{
break;
}else{
p = p->next;
}
}
return p->data;
}
Link_t* linklist_getLocation(Link_t *head, int pos) //找到指定位置的地址
{
if(pos < 1 || pos > linklist_getLength(head)+1)
{
printf("Position Invalid.GETLOCATION: Can`t find the elem...\n");
return NULL;
}
int i = 0;
Link_t *p = head->next;
while(NULL != p)
{
i++;
if(i == pos-1) //找到指定位置的前一个即可通过p->next访问到pos处地址
{
break;
}else{
p = p->next;
}
}
return p->next;
}
//找到指定位置pos的前一个节点,用于插入操作
Link_t* linklist_preNode(Link_t *head, int pos)
{
//pos只能是从第一个到最后一个的下一个
if(pos < 1 || pos > linklist_getLength(head)+1)
{
printf("ERR: Position Invalid.Can`t find the elem before %d.\n", pos);
return NULL;
}
int i = 0;
//创建一个临时节点,默认先指向链表头节点
Link_t *p = head;
/*
* 错误在这里,由于只需要找到pos位置前的一个节点
* 因此只需要循环pos-1次
* 错在循环了pos次,从而超出了
*/
for(i; i<pos-1; i++)
{
p = p->next;
}
// Link_t* p = linklist_getLocation(head, pos-1); //这里还是有问题!!!!!!!!!!!!!!!!!
return p;
}
bool linklist_insert(Link_t *head, int pos, data_t add)
{
//判断插入的位置合法性,限定可插入的位置从第一个到最后一个的下一个[1,len+1]
if(pos<1 || pos > (linklist_getLength(head)+1))
{
printf("ERR: Position Invalid.\n");
return FALSE;
}
//找到要插入的位置的前一个节点 *pre
Link_t *pre = linklist_preNode(head, pos); //这个函数出现了严重的错误,导致操作了非法内存
//开辟一个新的节点q来存放要插入的数据
Link_t *q = (Link_t*) malloc(sizeof(Link_t));
if(NULL == q)
{
printf("Insert: Malloc Failed....\n");
return FALSE;
}
bzero(q, sizeof(Link_t));
q->data = add;
q->next = NULL;
//插吧!
q->next = pre->next;
pre->next = q;
return TRUE;
}
bool linklist_deletPosition(Link_t *head, int pos) //删除指定位置的元素
{
//判断删除的位置合法性,限定可删除的位置从第一个到最后一个[1,len]
if(pos<1 || pos > linklist_getLength(head))
{
printf("Delet: Position Invalid.\n");
return FALSE;
}
/*
*要删除pos处的元素
* 1.找到它前面的节点pre;
* 2.将pre的指针域设为pos后的节点地址
* 3.释放pos处的节点
* */
Link_t *pre = linklist_preNode(head, pos); //第pos个前一个节点
Link_t *del = pre->next; //要删除的第pos个节点
pre->next = del->next;
free(del);
return TRUE;
}
bool linklist_deletElem(Link_t *head, data_t elem) //删除指定的元素
{
Link_t *del = linklist_malloc();
if(NULL == del)
{
printf("ERR: DeletElem: malloc failed.\n");
return FALSE;
}
del->data = -1;
del->next = NULL;
int pos = 0;
pos = linklist_locate(head, elem);
linklist_deletPosition(head, pos);
}
int linklist_locate(Link_t *head, data_t elem) //定位elem在链表中第一次出现的位置,如果没找到,返回-1
{
int pos = 0;
Link_t *p = head->next;
//遍历链表,找到指定元素的位置pos,然后调用linklist_deletPosition函数搞定
while(NULL != p)
{
pos++;
if(p->data == elem)
{
return pos;
}
p = p->next;
}
}
bool linklist_showList(Link_t *head)
{
if(head== NULL)
{
printf("链表空!\n");
return FALSE;
}
Link_t *p = head->next;
while( NULL != p)
{
printf("%3d\n", p->data);
p = p->next;
}
printf("\n");
return TRUE;
}
void linklist_destroy(Link_t *head)
{
//也可以先调用clear,然后在释放head即可
//遍历,依次释放各个节点内存
Link_t *p = head->next;
Link_t *del = NULL;
while(NULL != p)
{
del = p;
p = p->next;
free(del);
}
free(head);
}
bool linklist_dataReplace(Link_t * head, data_t old_data, data_t new_data) //将链表中old_data替换成new_data
{
Link_t *p = head->next;
while(old_data != p->data && p->next != NULL)
{
p = p->next;
}
//当找到old_data节点后,替换
p->data = new_data;
/*
//递归,直到全部替换
data_t older = old_data;
data_t newer = new_data;
linklist_dataReplace(p, older,newer);
*/
return TRUE;
}
Link_t* linklist_malloc() //为临时节点开辟空间
{
Link_t *p = (Link_t *) malloc(sizeof(Link_t));
if(NULL == p)
{
return NULL;
}
return p;
}
void linklist_invert(Link_t *head) //链表倒置
{
//利用头插法
Link_t *p = head->next; //循环遍历指针
Link_t *t = p; //保存将要插入的节点
head->next = NULL;//**断开原链表**
while(p != NULL)
{
t = p; //插入的是断开后的无头链表p的首节点
p = p->next; //p循环到下一个节点
/*这个操作不能和下面一条换位置,因为,现在t和p指向的是同一个节点,
* 如果先执行下一步,那么相当于把p的next也改变了
* 但是先执行p = p->next,只是改变了指针变量p的指向地址,而t不会变*/
t->next =head->next; //继续把t封装好,记得把head当前的下一个节点地址保存到t->next中
head->next = t;
}
}
void linklist_sort(Link_t *head) //链表插入排序法
{
Link_t *p = head->next; //循环遍历指针
Link_t *t = head->next; //保存head后的有序链表
head->next = NULL;//断开原链表
//现将第一个元素直接插到head后边
head->next = p;
p = p->next;
while(p!= NULL)
{
if(p->data < t->data){
p->next = t;
head->next = p;
}else if(p->data > t->data){
if(t == NULL){
t->next = p;
}else{
t = t->next;
}
}
p = p->next;
}
}