您的位置:首页 > 理论基础 > 数据结构算法

数据结构分析之——链表

2012-04-22 20:22 92 查看
这周线性表,链表,队列

现在是链表

自己敲的代码+网上查的资料

敬请批正

#include<iostream>
using namespace std;

typedef struct node   //链表一个节点的数据结构:该点元素和指向下一个节点的指针(看来是单向链表了)
{
int data;
struct node *next;
}Lnode,*LinkList;

int Count;
LinkList CreatLinkList(int length);                        //创建一个链表 ,长度为length
void Print( LinkList List);                                     //打印该链表
int  Insert(LinkList LIST,int Pos,int Elem);                //在链表LIST中的POS插入元素elem
int  DelPos(LinkList LIST,int Pos);                         //删除位置pos对应的节点
void Destroy(LinkList *LIST);                                //销毁链表list

int main()
{
LinkList List;                                     //list可是指针型哦
int Insert_Pos,Insert_Elem,Del_Pos;
int choice;
List = CreatLinkList(5);                           //创建List,长度为5
if (List != NULL)
{
cout << "Create LinkList successfully" << endl;
}
else
exit(0);
cout << "1 to print------2 to Insert------3 to delete-----4 to destroy------CTRL+Z to end" << endl;
while(cin >> choice)
{
switch(choice)
{
case 1:
Print(List);
break;
case 2:
{
cout << "Input Pos and Elem you want to Insert in" << endl;
cin >> Insert_Pos >> Insert_Elem;
if( !Insert(List,Insert_Pos,Insert_Elem) )
cout << "Inserted successfully!" << endl;
else
cout << "Inserted failed!" << endl;
}
break;
case 3:
{
cout << "Input the Pos you want to delete" << endl;
cin >> Del_Pos;
if(!DelPos(List,Del_Pos))
cout << "Deleted successfully!" << endl;
else
cout << "Deleted failed!" << endl;
}
break;
case 4:
Destroy(&List);
break;
default:
break;
}
}
system("pause");
return 0;
}

LinkList CreatLinkList(int length)                      //应该可以改进,这样感觉太复杂了
{
LinkList temp,r,list = NULL;
int elem;
cout << "Now creating a linklist!" << endl;
for (Count = 1; Count <= length; ++Count)
{
cout << "NO." << Count << "  element" << endl;
cin >> elem;
temp = (LinkList)malloc(sizeof(Lnode));
temp->data = elem;
temp->next = NULL;
if (!list)          //判断是否是头节点
{
list = temp;
}
else
r->next = temp;
r = temp;              // 这段也不好理解,但如果花流程图就ok了,我画了2次for内的语句就ok了。
}
return list;              //返回的list是刚生成的链表的头指针
}

void Print( LinkList List)
{
cout << "NO.\tLocal Pointer\tLocal Elem" << endl;
int i = 1;
if(List == NULL)
cout << "Empty" << endl;
else
while(List != NULL)
{
cout << i << "\t" << List << "\t" << List->data << endl;
List = List->next;
++i;             //其实++i可以放到while循环第一句中,放在这里只为方便读程序
}
}

int Insert(LinkList LIST,int Pos,int Elem)
{
if(Pos < 1 || Pos > sizeof(LIST)/(sizeof(LIST->data)+sizeof(LIST->next)) )
{
cout << "Pos is illegal!" << endl;
return 1;
}
else
while(Pos-- != 2)
LIST = LIST->next;            //list为链表头节点,如果要在第4个节点插入一个节点。那么有:
//4——2:List到第二个节点;3——2:list到第三个节点;2——2:list停在第三个节点
//即插入的数据在链表的第四个节点
LinkList temp;                     //新建一个链表节点temp
temp = (LinkList)malloc(sizeof(Lnode));
temp->data = Elem;
temp->next = LIST->next;
LIST->next = temp;
return 0;
}
/*原顺序为 list ,list下一个节点A,temp没插入
先把list的下一个节点A赋给temp的下一个节点,则有顺序  temp,  A
然后再把temp赋给list的下一个节点(注:此时A已经不是list的下一个节点了),则有 list,temp
最后不就是:list ,temp ,A了吗,即在list和list下一个A之间插入一个节点temp。Good job!
*/

int DelPos(LinkList LIST,int Pos)
{
if(Pos < 1 || Pos > sizeof(LIST)/(sizeof(LIST->data)+sizeof(LIST->next)) )
{
cout << "Pos is illegal!" << endl;
return 1;
}
else
while(Pos-- != 2)
LIST = LIST->next;         //同上,即找到要删除的节点位置
LinkList temp;                 //指针变换用
temp = (LinkList)malloc(sizeof(Lnode));
temp = LIST->next ;
//这里是不是还得有个free(list->next)啊????
LIST->next = temp->next;        //指针变化真不好理解,原顺序:list list下一个A,下下个B:list——A——B
//首先把A赋给temp,则:temp=A;temp——B
//然后有把特temp下一个赋给list下一个,则:list——B
free(temp);
return 0;
}

void Destroy(LinkList *LIST)
{
LinkList p,q;
p = *LIST;
while(p)
{
q = p->next;
free(p);
p = q;
}
*LIST = NULL;
cout << "Destroy successfully!" << endl;
}

/*
1.expression can not be evaluate
编译时正常,运行时却报错,调试器给的错误信息是expression cannot be uated,调试器里显示变量的地址通常是0×000000或者是0xCCCCCC。
出现这样的错误一般是由于对变量的初始化不正确或者根本就还没有初始化就直接引用变量。只要在对变量进行引用前确保变量已经正确初始化
就可以避免此类错误。另外结构体指针变量在赋值之前要先用malloc()分配一个内存空间。
2.access violation
出现这种Access-Violation异常,肯定是程序的逻辑有问题,它与一般的C++异常并不相同!!!!!
这种Access-Violation异常所代表的行为就是用一个无效指针来调用某个成员函数,因为指针无效,所以行为主体就无从得来,换句话说没有
抛出异常的主体,既然没有人throw,那么怎么捕获呢???
如果对于空指针调用函数一律捕获,那么这种异常处理函数就是无穷无尽也是不可能逐一实现的,更不可能做到对以后的兼容,因为那意味着
你每增加修改一个成员函数就对应一个异常处理.
其实这种情况应该归类于错误,也就是说处理它没有任何意义,因为它的出现意味着你的程序逻辑是错误的,C++编程思想中讨论过错误
和异常的关系.出现这种情况就应该去检查你的程序纠正错误,而不是去捕获它,它已经使你的程序中止,所能做的也就是只有无条件退出.
即使你去处理也只有这样的选择...
3.malloc,free(顺序表中也有相关知识)
malloc注意:
A、申请了内存空间后,必须检查是否分配成功。
B、当不需要再使用申请的内存时,记得释放;释放后应该把指向这块内存的指针指向NULL,防止程序后面不小心使用了它。
C、这两个函数应该是配对。如果申请后不释放就是内存泄露;如果无故释放那就是什么也没有做。释放只能一次,如果释放两次及两次以上会
出现错误(释放空指针例外,释放空指针其实也等于啥也没做,所以释放空指针释放多少次都没有问题)。
D、虽然malloc()函数的类型是(void *),任何类型的指针都可以转换成(void *),但是最好还是在前面进行强制类型转换,因为这样可以躲过一
些编译器的检查。

malloc()到底从哪里得来了内存空间:

1、 malloc()到底从哪里得到了内存空间?答案是从堆里面获得空间。也就是说函数返回的指针是指向堆里面的一块内存。操作系统中有一个
记录空闲内存地址的链表。当操作系统收到程序的申请时,就会遍历该链表,然后就寻找第一个空间大于所申请空间的堆结点,然后就将该结
点从空闲结点链表中删除,并将该结点的空间分配给程序。就是这样!

2、什么是堆:堆是大家共有的空间,分全局堆和局部堆。全局堆就是所有没有分配的空间,局部堆就是用户分配的空间。堆在操作系统对进程
初始化的时候分配,运行过程中也可以向系统要额外的堆,但是记得用完了要还给操作系统,要不然就是内存泄漏。

什么是栈:栈是线程独有的,保存其运行状态和局部自动变量的。栈在线程开始的时候初始化,每个线程的栈互相独立。每个函数都有自己的
栈,栈被用来在函数之间传递参数。操作系统在切换线程的时候会自动的切换栈,就是切换SS/ESP寄存器。栈空间不需要在高级语言里面显式的
分配和释放。
通过上面对概念的描述,可以知道:
栈是由编译器自动分配释放,存放函数的参数值、局部变量的值等。操作方式类似于数据结构中的栈。
堆一般由程序员分配释放,若不释放,程序结束时可能由OS回收。注意这里说是可能,并非一定。所以我想再强调一次,记得要释放!
注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。(这点我上面稍微提过)

所以,举个例子,如果你在函数上面定义了一个指针变量,然后在这个函数里申请了一块内存让指针指向它。实际上,这个指针的地址是在栈上,
但是它所指向的内容却是在堆上面的!这一点要注意!所以,再想想,在一个函数里申请了空间后,比如说下面这个函数:

程序代码:
// code...
void Function(void)
{
char *p = (char *)malloc(100 * sizeof(char));
}
就这个例子,千万不要认为函数返回,函数所在的栈被销毁指针也跟着销毁,申请的内存也就一样跟着销毁了!这绝对是错误的!因为申请的
内存在堆上,而函数所在的栈被销毁跟堆完全没有啥关系。所以,还是那句话:记得释放!

2.free
free()到底释放了什么
这个问题比较简单,其实我是想和第二大部分的题目相呼应而已!哈哈!free()释放的是指针指向的内存!注意!释放的是内存,不是指针!
这点非常非常重要!指针是一个变量,只有程序结束时才被销毁。释放了内存空间后,原来指向这块空间的指针还是存在!只不过现在指针指向的
内容的垃圾,是未定义的,所以说是垃圾。因此,前面我已经说过了,释放内存后把指针指向NULL,防止指针在后面不小心又被解引用了。
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c++ 数据结构 c 链表